Skip to content

Commit 78a7cee

Browse files
committed
Improvements to Count Occurrences
1 parent 67f00de commit 78a7cee

File tree

3 files changed

+29
-28
lines changed

3 files changed

+29
-28
lines changed

Count Occurrences/CountOccurrences.playground/Contents.swift

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11

2-
func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
3-
func leftBoundary() -> Int {
2+
func countOccurrences<T: Comparable>(of key: T, in array: [T]) -> Int {
3+
var leftBoundary: Int {
44
var low = 0
5-
var high = a.count
5+
var high = array.count
66
while low < high {
77
let midIndex = low + (high - low)/2
8-
if a[midIndex] < key {
8+
if array[midIndex] < key {
99
low = midIndex + 1
1010
} else {
1111
high = midIndex
@@ -14,12 +14,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
1414
return low
1515
}
1616

17-
func rightBoundary() -> Int {
17+
var rightBoundary: Int {
1818
var low = 0
19-
var high = a.count
19+
var high = array.count
2020
while low < high {
2121
let midIndex = low + (high - low)/2
22-
if a[midIndex] > key {
22+
if array[midIndex] > key {
2323
high = midIndex
2424
} else {
2525
low = midIndex + 1
@@ -28,13 +28,13 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
2828
return low
2929
}
3030

31-
return rightBoundary() - leftBoundary()
31+
return rightBoundary - leftBoundary
3232
}
3333

3434
// Simple test
3535

3636
let a = [ 0, 1, 1, 3, 3, 3, 3, 6, 8, 10, 11, 11 ]
37-
countOccurrencesOfKey(3, inArray: a)
37+
countOccurrences(of: 3, in: a)
3838

3939
// Test with arrays of random size and contents (see debug output)
4040

@@ -59,6 +59,6 @@ for _ in 0..<10 {
5959

6060
// Note: we also test -1 and 6 to check the edge cases.
6161
for k in -1...6 {
62-
print("\t\(k): \(countOccurrencesOfKey(k, inArray: a))")
62+
print("\t\(k): \(countOccurrences(of: k, in: a))")
6363
}
6464
}
+13-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
/*
2-
Counts the number of times a value appears in an array in O(lg n) time.
3-
The array must be sorted from low to high.
4-
*/
5-
func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
6-
func leftBoundary() -> Int {
1+
/// Counts the number of times a value appears in an array in O(log n) time. The array must be sorted from low to high.
2+
///
3+
/// - Parameter key: the key to be searched for in the array
4+
/// - Parameter array: the array to search
5+
/// - Returns: the count of occurences of the key in the given array
6+
func countOccurrences<T: Comparable>(of key: T, in array: [T]) -> Int {
7+
var leftBoundary: Int {
78
var low = 0
8-
var high = a.count
9+
var high = array.count
910
while low < high {
1011
let midIndex = low + (high - low)/2
11-
if a[midIndex] < key {
12+
if array[midIndex] < key {
1213
low = midIndex + 1
1314
} else {
1415
high = midIndex
@@ -17,12 +18,12 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
1718
return low
1819
}
1920

20-
func rightBoundary() -> Int {
21+
var rightBoundary: Int {
2122
var low = 0
22-
var high = a.count
23+
var high = array.count
2324
while low < high {
2425
let midIndex = low + (high - low)/2
25-
if a[midIndex] > key {
26+
if array[midIndex] > key {
2627
high = midIndex
2728
} else {
2829
low = midIndex + 1
@@ -31,5 +32,5 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
3132
return low
3233
}
3334

34-
return rightBoundary() - leftBoundary()
35+
return rightBoundary - leftBoundary
3536
}

Count Occurrences/README.markdown

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ The trick is to use two binary searches, one to find where the `3`s start (the l
2222
In code this looks as follows:
2323

2424
```swift
25-
func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
26-
func leftBoundary() -> Int {
25+
func countOccurrences<T: Comparable>(of key: T, in array: [T]) -> Int {
26+
var leftBoundary: Int {
2727
var low = 0
2828
var high = a.count
2929
while low < high {
@@ -37,7 +37,7 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
3737
return low
3838
}
3939

40-
func rightBoundary() -> Int {
40+
var rightBoundary: Int {
4141
var low = 0
4242
var high = a.count
4343
while low < high {
@@ -51,11 +51,11 @@ func countOccurrencesOfKey(_ key: Int, inArray a: [Int]) -> Int {
5151
return low
5252
}
5353

54-
return rightBoundary() - leftBoundary()
54+
return rightBoundary - leftBoundary
5555
}
5656
```
5757

58-
Notice that the helper functions `leftBoundary()` and `rightBoundary()` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going.
58+
Notice that the variables `leftBoundary` and `rightBoundary` are very similar to the [binary search](../Binary%20Search/) algorithm. The big difference is that they don't stop when they find the search key, but keep going. Also, notice that we constrain the type `T` to be Comparable so that the algorithm can be applied to an array of Strings, Ints or other types that conform to the Swift Comparable protocol.
5959

6060
To test this algorithm, copy the code to a playground and then do:
6161

@@ -113,7 +113,7 @@ The right boundary is at index 7. The difference between the two boundaries is 7
113113

114114
Each binary search took 4 steps, so in total this algorithm took 8 steps. Not a big gain on an array of only 12 items, but the bigger the array, the more efficient this algorithm becomes. For a sorted array with 1,000,000 items, it only takes 2 x 20 = 40 steps to count the number of occurrences for any particular value.
115115

116-
By the way, if the value you're looking for is not in the array, then `rightBoundary()` and `leftBoundary()` return the same value and so the difference between them is 0.
116+
By the way, if the value you're looking for is not in the array, then `rightBoundary` and `leftBoundary` return the same value and so the difference between them is 0.
117117

118118
This is an example of how you can modify the basic binary search to solve other algorithmic problems as well. Of course, it does require that the array is sorted.
119119

0 commit comments

Comments
 (0)