-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathBinarySearch.swift
80 lines (70 loc) · 2.69 KB
/
BinarySearch.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
func findIndices(of value: Int, in array: [Int]) -> CountableRange<Int>? {
guard let startIndex = startIndex(of: value, in: array, range: 0..<array.count)
else {
return nil
}
guard let endIndex = endIndex(of: value, in: array, range: 0..<array.count)
else {
return nil
}
return startIndex..<endIndex
}
func startIndex(of value: Int, in array: [Int], range: CountableRange<Int>) -> Int? {
let middleIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2
if middleIndex == 0 || middleIndex == array.count - 1 {
if array[middleIndex] == value {
return middleIndex
} else {
return nil
}
}
if array[middleIndex] == value {
if array[middleIndex - 1] != value {
return middleIndex
} else {
return startIndex(of: value, in: array, range: range.lowerBound..<middleIndex)
}
} else if value < array[middleIndex] {
return startIndex(of: value, in: array, range: range.lowerBound..<middleIndex)
} else {
return startIndex(of: value, in: array, range: middleIndex..<range.upperBound)
}
}
func endIndex(of value: Int, in array: [Int], range: CountableRange<Int>) -> Int? {
let middleIndex = range.lowerBound + (range.upperBound - range.lowerBound) / 2
if middleIndex == 0 || middleIndex == array.count - 1 {
if array[middleIndex] == value {
return middleIndex + 1
} else {
return nil
}
}
if array[middleIndex] == value {
if array[middleIndex + 1] != value {
return middleIndex + 1
} else {
return endIndex(of: value, in: array, range: middleIndex..<range.upperBound)
}
} else if value < array[middleIndex] {
return endIndex(of: value, in: array, range: range.lowerBound..<middleIndex)
} else {
return endIndex(of: value, in: array, range: middleIndex..<range.upperBound)
}
}
extension RandomAccessCollection where Element: Comparable {
func binarySearch(for value: Element, in range: Range<Index>? = nil) -> Index? {
let range = range ?? startIndex..<endIndex
guard range.lowerBound < range.upperBound else {
return nil
}
let size = distance(from: range.lowerBound, to: range.upperBound)
let middle = index(range.lowerBound, offsetBy: size / 2)
if self[middle] == value {
return middle
} else if self[middle] > value {
return binarySearch(for: value, in: range.lowerBound..<middle)
} else {
return binarySearch(for: value, in: index(after: middle)..<range.upperBound)
}
}
}