Skip to content

Commit 3402103

Browse files
authored
Simplifies algorithm via in-place index traversals
1 parent 48d83f2 commit 3402103

File tree

1 file changed

+26
-31
lines changed

1 file changed

+26
-31
lines changed

3Sum and 4Sum/3Sum.playground/Contents.swift

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,56 @@
1+
12
extension Collection where Element: Equatable {
23

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.
45
///
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
1211
formIndex(after: &index)
13-
formIndex(after: &nextIndex)
14-
}
15-
return nextIndex != endIndex ? nextIndex : nil
12+
} while index < endIndex && self[prev] == self[index]
1613
}
1714
}
1815

1916
extension BidirectionalCollection where Element: Equatable {
2017

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.
2219
///
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]
3127
}
3228
}
3329

3430
func threeSum<T: BidirectionalCollection>(_ collection: T, target: T.Element) -> [[T.Element]] where T.Element: Numeric & Comparable {
3531
let sorted = collection.sorted()
3632
var ret: [[T.Element]] = []
33+
var l = sorted.startIndex
3734

38-
ThreeSum: for l in sequence(first: sorted.startIndex, next: sorted.uniqueIndex(after:)) {
35+
while l < sorted.endIndex {
3936
var m = sorted.index(after: l)
4037
var r = sorted.index(before: sorted.endIndex)
41-
42-
TwoSum: while m < r {
38+
39+
while m < r && r < sorted.endIndex {
4340
let sum = sorted[l] + sorted[m] + sorted[r]
4441
switch target {
4542
case sum:
4643
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)
5046
case ..<target:
51-
guard let nextMid = sorted.uniqueIndex(after: m) else { break TwoSum }
52-
m = nextMid
47+
sorted.formUniqueIndex(after: &m)
5348
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")
5751
}
5852
}
53+
sorted.formUniqueIndex(after: &l)
5954
}
6055

6156
return ret

0 commit comments

Comments
 (0)