Skip to content

Commit 4d92bfc

Browse files
authored
Updates the avoiding duplicates section.
1 parent 4567dd1 commit 4d92bfc

File tree

1 file changed

+44
-38
lines changed

1 file changed

+44
-38
lines changed

3Sum and 4Sum/README.md

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -111,45 +111,51 @@ There are slight optimizations you can do to find `m`, but to keep things simple
111111

112112
#### Avoiding Duplicates
113113

114-
Avoiding duplicate values is fairly straightforward if you've understood everything so far. Let's consider a sample array that has a few duplicates:
115-
116-
```
117-
target = 0
118-
119-
[-1, -1, -1, -1, 0, 1, 1, 1]
120-
```
121-
122-
One possible subset is `[-1, 0, 1]`, and in fact is the only subset for 3Sum.
123-
124-
The easiet way is using set. We can maintain a solution set, then we can check if the triplets is in the set or not to determine whether it's duplicate.
125-
126-
Set introduces space complexity. So we still want to avoid extra space using. Let's change an angle consider, we can loop the array first find `m` then next thing is to find `l` and `r`.
127-
128-
For example
129-
114+
Since you pre-sort the array, duplicates will be adjacent to each other. You just need to skip over duplicates by comparing adjacent values:
115+
116+
```
117+
extension Collection where Element: Equatable {
118+
119+
/// Returns next index with unique value. Works only on sorted arrays.
120+
///
121+
/// - Parameter index: The current `Int` index.
122+
/// - Returns: The new `Int` index. Will return `nil` if new index happens to be the `endIndex` (out of bounds)
123+
func uniqueIndex(after index: Index) -> Index? {
124+
guard index < endIndex else { return nil }
125+
var index = index
126+
var nextIndex = self.index(after: index)
127+
while nextIndex < endIndex && self[index] == self[nextIndex] {
128+
formIndex(after: &index)
129+
formIndex(after: &nextIndex)
130+
}
131+
132+
if nextIndex == endIndex {
133+
return nil
134+
} else {
135+
return nextIndex
136+
}
137+
}
138+
}
139+
```
140+
141+
A similar implementation is used to get the unique index *before* a given index:
142+
143+
```
144+
extension BidirectionalCollection where Element: Equatable {
145+
146+
/// Returns next index with unique value. Works only on sorted arrays.
147+
///
148+
/// - Parameter index: The current `Int` index.
149+
/// - Returns: The new `Int` index. Will return `nil` if new index happens to come before the `startIndex` (out of bounds)
150+
func uniqueIndex(before index: Index) -> Index? {
151+
return indices[..<index].reversed().first { index -> Bool in
152+
let nextIndex = self.index(after: index)
153+
guard nextIndex >= startIndex && self[index] != self[nextIndex] else { return false }
154+
return true
155+
}
156+
}
157+
}
130158
```
131-
​```
132-
[-1, 0, 1, 2, -1, -4] // unsorted
133-
134-
1)
135-
[-4, -1, -1, 0, 1, 2]
136-
m l r
137-
138-
2)
139-
[-4, -1, -1, 0, 1, 2]
140-
m l r
141-
142-
3)
143-
[-4, -1, -1, 0, 1, 2]
144-
m l r
145-
​```
146-
147-
We loop `m` in `0..<n`. We will do another inner loop at the same time, `l..r` loops in `i+1..<n`.
148-
In 1), we will check if `a[i] == a[i-1]`? It's not in this case, then the problem is 2sum (`l..r`).
149-
In 2), Since `a[i] == a[i-1]`, it means `a[i-1]` covers `a[i]` case. Because case 3) contains case 2) solutions.
150-
```
151-
152-
153159

154160
## 4Sum
155161
Given an array S of n integers, find all subsets of the array with 4 values where the 4 values sum up to a target number.

0 commit comments

Comments
 (0)