|
| 1 | + |
1 | 2 | extension Collection where Element: Equatable {
|
2 | 3 |
|
3 |
| - /// Returns next index with unique value. Works only on sorted arrays. |
| 4 | + /// In a sorted collection, replaces the given index with a successor mapping to a unique element. |
4 | 5 | ///
|
5 |
| - /// - Parameter index: The current `Int` index. |
6 |
| - /// - Returns: The new index. Will return `nil` if new index happens to be the `endIndex` (out of bounds) |
7 |
| - func uniqueIndex(after index: Index) -> Index? { |
8 |
| - guard index < endIndex else { return nil } |
9 |
| - var index = index |
10 |
| - var nextIndex = self.index(after: index) |
11 |
| - while nextIndex < endIndex && self[index] == self[nextIndex] { |
| 6 | + /// - Parameter index: A valid index of the collection. `index` must be less than `endIndex` |
| 7 | + func formUniqueIndex(after index: inout Index) { |
| 8 | + var prev = index |
| 9 | + repeat { |
| 10 | + prev = index |
12 | 11 | formIndex(after: &index)
|
13 |
| - formIndex(after: &nextIndex) |
14 |
| - } |
15 |
| - return nextIndex != endIndex ? nextIndex : nil |
| 12 | + } while index < endIndex && self[prev] == self[index] |
16 | 13 | }
|
17 | 14 | }
|
18 | 15 |
|
19 | 16 | extension BidirectionalCollection where Element: Equatable {
|
20 | 17 |
|
21 |
| - /// Returns next index with unique value. Works only on sorted arrays. |
| 18 | + /// In a sorted collection, replaces the given index with a predecessor that maps to a unique element. |
22 | 19 | ///
|
23 |
| - /// - Parameter index: The current index. |
24 |
| - /// - Returns: The new index. Will return `nil` if new index happens to come before the `startIndex` (out of bounds) |
25 |
| - func uniqueIndex(before index: Index) -> Index? { |
26 |
| - return indices[..<index].reversed().first { index -> Bool in |
27 |
| - let nextIndex = self.index(after: index) |
28 |
| - guard nextIndex >= startIndex && self[index] != self[nextIndex] else { return false } |
29 |
| - return true |
30 |
| - } |
| 20 | + /// - Parameter index: A valid index of the collection. `index` must be greater than `startIndex`. |
| 21 | + func formUniqueIndex(before index: inout Index) { |
| 22 | + var prev = index |
| 23 | + repeat { |
| 24 | + prev = index |
| 25 | + formIndex(before: &index) |
| 26 | + } while index > startIndex && self[prev] == self[index] |
31 | 27 | }
|
32 | 28 | }
|
33 | 29 |
|
34 | 30 | func threeSum<T: BidirectionalCollection>(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable {
|
35 | 31 | let sorted = collection.sorted()
|
36 | 32 | var ret: [[T.Element]] = []
|
| 33 | + var l = sorted.startIndex |
37 | 34 |
|
38 |
| - ThreeSum: for l in sequence(first: sorted.startIndex, next: sorted.uniqueIndex(after:)) { |
| 35 | + while l < sorted.endIndex { |
39 | 36 | var m = sorted.index(after: l)
|
40 | 37 | var r = sorted.index(before: sorted.endIndex)
|
41 |
| - |
42 |
| - TwoSum: while m < r { |
| 38 | + |
| 39 | + while m < r && r < sorted.endIndex { |
43 | 40 | let sum = sorted[l] + sorted[m] + sorted[r]
|
44 | 41 | switch target {
|
45 | 42 | case sum:
|
46 | 43 | ret.append([sorted[l], sorted[m], sorted[r]])
|
47 |
| - guard let nextMid = sorted.uniqueIndex(after: m), let nextRight = sorted.uniqueIndex(before: r) else { break TwoSum } |
48 |
| - m = nextMid |
49 |
| - r = nextRight |
| 44 | + sorted.formUniqueIndex(after: &m) |
| 45 | + sorted.formUniqueIndex(before: &r) |
50 | 46 | case ..<target:
|
51 |
| - guard let nextMid = sorted.uniqueIndex(after: m) else { break TwoSum } |
52 |
| - m = nextMid |
| 47 | + sorted.formUniqueIndex(after: &m) |
53 | 48 | case target...:
|
54 |
| - guard let nextRight = sorted.uniqueIndex(before: r) else { break TwoSum } |
55 |
| - r = nextRight |
56 |
| - default: fatalError("Swift isn't smart enough to detect that this switch statement is exhausive") |
| 49 | + sorted.formUniqueIndex(before: &r) |
| 50 | + default: fatalError("Sw ift isn't smart enough to detect that this switch statement is exhausive") |
57 | 51 | }
|
58 | 52 | }
|
| 53 | + sorted.formUniqueIndex(after: &l) |
59 | 54 | }
|
60 | 55 |
|
61 | 56 | return ret
|
|
0 commit comments