Skip to content

Commit 42e5e31

Browse files
committed
Two-Sum Problem
1 parent dd0a9c7 commit 42e5e31

File tree

4 files changed

+249
-1
lines changed

4 files changed

+249
-1
lines changed

README.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@
216216

217217
很多程序员在面试时都会被问到一些算法性质的智力题。这里只囊括了一点比较有趣的。想了解更多的智力题(及答案),请浏览[这里](http://elementsofprogramminginterviews.com/),还有[这里](http://www.crackingthecodinginterview.com)
218218

219-
- [二和问题](Two-Sum%20Problem/)
219+
- [二和问题](Two-Sum%20Problem/)
220220
- [⏳Three-Sum/Four-Sum Problem](3Sum%20and%204Sum/)
221221
- [⏳Fizz Buzz](Fizz%20Buzz/)
222222
- [⏳蒙提霍尔问题](Monty%20Hall%20Problem/)

Schedule.markdown

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,5 +182,11 @@
182182
| Dijkstra's algorithm | | | | |
183183
| | | | | |
184184

185+
### 智力题
186+
187+
| 题目 | 翻译人员 | 翻译是否完成 | 校对人员 | 校对是否完成|
188+
|---------------------------|------------|:-------------:|----------|:---------:|
189+
| Two-Sum Problem | andyRon | Y | | |
190+
185191

186192
> ❗️:表示理解不够深刻

Two-Sum Problem/README.markdown

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ Given an array of integers and an integer target, return the indices of two numb
44

55
There are a variety of solutions to this problem (some better than others). The following solutions both run in **O(n)** time.
66

7+
给定一个整数数组和一个整数目标,返回与目标相加的两个数字的索引。
8+
9+
这个问题有很多解决方案(有些比其他解决方案更好)。 以下解决方案均在**O(n)**时间内运行。
10+
711
# Solution 1
12+
# 解决方案1
813

914
This solution looks at one number at a time, storing each number in the dictionary. It uses the number as the key and the number's index in the array as the value.
1015

1116
For each number n, we know the complementing number to sum up to the target is `target - n`. By looking up the complement in the dictionary, we'd know whether we've seen the complement before and what its index is.
1217

18+
此解决方案一次查看一个数字,将每个数字存储在字典中。 它使用数字作为键,数组中的数字索引作为值。
19+
20+
对于每个数字n,我们知道总和到目标的互补数是 `target - n`。 通过在字典中查找补语,我们可以知道我们是否已经看过补码之前及其索引是什么。
21+
1322
```swift
1423
func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? {
1524
var dict = [Int: Int]()
@@ -36,6 +45,10 @@ The `twoSum` function takes two parameters: the `numbers` array and the target s
3645

3746
Let's run through the algorithm to see how it works. Given the array:
3847

48+
`twoSum`函数有两个参数:`numbers`数组和目标和。 它返回总和到目标的元素对的两个指标,如果找不到则返回`nil`
49+
50+
让我们通过算法来看看它是如何工作的。 给定数组:
51+
3952
```swift
4053
[3, 2, 9, 8]
4154
```
@@ -44,9 +57,14 @@ Let's find out if there exist two entries whose sum is 10.
4457

4558
Initially, our dictionary is empty. We begin looping through each element:
4659

60+
让我们看看是否存在两个总和为10的条目。
61+
62+
最初,我们的字典是空的。 我们开始循环遍历每个元素:
63+
4764
- **currentIndex = 0** | n = nums[0] = 3 | complement = 10 - 3 = 7
4865

4966
Is the complement `7` in the dictionary? No, so we add `3` and its index `0` to the dictionary.
67+
字典中的补码是`7`吗? 不,所以我们将`3`及其索引`0`添加到字典中。
5068

5169
```swift
5270
[3: 0]
@@ -55,6 +73,7 @@ Is the complement `7` in the dictionary? No, so we add `3` and its index `0` to
5573
- **currentIndex = 1** | n = 2 | complement = 10 - 2 = 8
5674

5775
Is the complement `8` in the dictionary? No, so we add `2` and its index `1` to the dictionary.
76+
字典中的补码是`8`吗? 不,所以我们将`2`及其索引`1`添加到字典中。
5877

5978
```swift
6079
[3: 0, 2: 1]
@@ -63,6 +82,7 @@ Is the complement `8` in the dictionary? No, so we add `2` and its index `1` to
6382
- **currentIndex = 2** | n = 9 | complement = 10 - 9 = 1
6483

6584
Is the complement `1` in the dictionary? No, so we add `9` and its index `2` to the dictionary.:
85+
字典中的补码是`1`吗? 不,所以我们将`9`及其索引`2`添加到字典中:
6686

6787
```swift
6888
[3: 0, 2: 1, 9: 2]
@@ -78,12 +98,26 @@ If the given array has multiple solutions, only the first solution is returned.
7898

7999
The running time of this algorithm is **O(n)** because it may look at every element in the array. It also requires **O(n)** additional storage space for the dictionary.
80100

101+
字典中的补码是`2`吗? 是! 这意味着我们找到了一对与目标相加的条目!
102+
103+
因此,`complementIndex = dict[2] = 1``currentIndex = 3`。 我们返回的元组是`(1, 3)`
104+
105+
如果给定的数组有多个解决方案,则只返回第一个解决方案。
106+
107+
该算法的运行时间为**O(n)**,因为它可能会查看数组中的每个元素。 它还需要**O(n)**字典的额外存储空间。
108+
81109
# Solution 2
110+
# 解决方案2
82111

83112
**Note**: This particular algorithm requires that the array is sorted, so if the array isn't sorted yet (usually it won't be), you need to sort it first. The time complexity of the algorithm itself is **O(n)** and, unlike the previous solution, it does not require extra storage. Of course, if you have to sort first, the total time complexity becomes **O(n log n)**. Slightly worse but still quite acceptable.
84113

85114
Here is the code in Swift:
86115

116+
**注意**:这个特殊的算法要求对数组进行排序,因此如果数组尚未排序(通常不会排序),则需要先对其进行排序。 算法本身的时间复杂度为**O(n)**,与之前的解决方案不同,它不需要额外的存储空间。 当然,如果你必须先排序,总时间复杂度变为**O(n log n)**。 稍差但仍然可以接受。
117+
118+
这是Swift中的代码:
119+
120+
87121
```swift
88122
func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? {
89123
var i = 0
@@ -107,6 +141,11 @@ As in the first solution, the `twoSumProblem()` function takes as parameters the
107141

108142
To test it, copy the code into a playground and add the following:
109143

144+
与第一个解决方案一样,`twoSumProblem()`函数将数组`a`作为参数,使用数字和`k`,我们正在寻找的总和。 如果有两个数字加起来为`k`,则该函数返回一个包含其数组索引的元组。 如果没有,则返回`nil`。 主要区别在于假定`a`被排序。
145+
146+
要测试它,请将代码复制到游乐场并添加以下内容:
147+
148+
110149
```swift
111150
let a = [2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100]
112151
if let (i, j) = twoSumProblem(a, k: 33) {
@@ -120,40 +159,62 @@ So how does this algorithm work? It takes advantage of the array being sorted. T
120159

121160
In the example, the sorted array is:
122161

162+
这将返回元组`(8, 10)`因为`a[8] = 12``a[10] = 21`,它们一起加起来为`33`
163+
164+
那么这个算法是如何工作的呢? 它利用了正在排序的数组。 顺便说一下,许多算法都是如此。 如果您首先对数据进行排序,则通常更容易执行计算。
165+
166+
在示例中,排序的数组是:
167+
168+
123169
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
124170

125171
The algorithm uses the two variables `i` and `j` to point to the beginning and end of the array, respectively. Then it increments `i` and decrements `j` until the two meet. While it's doing this, it checks whether `a[i]` and `a[j]` add up to `k`.
126172

127173
Let's step through this. Initially, we have:
128174

175+
该算法使用两个变量`i``j`分别指向数组的开头和结尾。 然后它增加`i`并递减`j`直到两者相遇。 当它这样做时,它会检查`a[i]``a[j]`是否加起来为`k`
176+
177+
让我们一步一步。 最初,我们有:
178+
129179
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
130180
i j
131181

132182
The sum of these two is `2 + 100 = 102`. That's obviously too much, since `k = 33` in this example. There is no way that `100` will ever be part of the answer, so decrement `j`.
133183

134184
We have:
135185

186+
这两者的总和是`2 + 100 = 102`。 这显然太多了,因为在这个例子中`k = 33``100`永远不会成为答案的一部分,所以减少`j`
187+
188+
我们有:
189+
136190
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
137191
i j
138192

139193
The sum is `2 + 22 = 24`. Now the sum is too small. We can safely conclude at this point that the number `2` will never be part of the answer. The largest number on the right is `22`, so we at least need `11` on the left to make `33`. Anything less than `11` is not going to cut it. (This is why we sorted the array!)
140194

141195
So, `2` is out and we increment `i` to look at the next small number.
142196

197+
总和是`2 + 22 = 24`。 现在总和太小了。 我们可以在这一点上得出结论,数字`2`永远不会成为答案的一部分。 右边最大的数字是`22`,所以我们至少需要左边的`11`来制作`33`。 任何低于`11`的东西都不会削减它。 (这就是我们对数组进行排序的原因!)
198+
199+
所以,`2`出来了,我们增加`i`来看下一个小数字。
200+
143201
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
144202
i j
145203

146204
The sum is `3 + 22 = 25`. Still too small, so increment `i` again.
205+
总和是`3 + 22 = 25`。 还是太小了,所以再次增加`i`
147206

148207
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
149208
i j
150209

151210
In fact, we have to increment `i` a few more times, until we get to `12`:
211+
事实上,我们必须再增加几次`i`,直到我们达到`12`
152212

153213
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
154214
i j
155215

156216
Now the sum is `12 + 22 = 34`. It's too high, which means we need to decrement `j`. This gives:
217+
现在总和是`12 + 22 = 34`。 它太高了,这意味着我们需要减少`j`。 这给出了:
157218

158219
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
159220
i j
@@ -164,8 +225,18 @@ It's possible, of course, that there are no values for `a[i] + a[j]` that sum to
164225

165226
I'm quite enamored by this little algorithm. It shows that with some basic preprocessing on the input data -- sorting it from low to high -- you can turn a tricky problem into a very simple and beautiful algorithm.
166227

228+
最后,我们得到了答案:`12 + 21 = 33`。 好极了!
229+
230+
当然,有可能`a[i] + a[j]`没有与”k“相加的值。 在这种情况下,最终`i``j`将指向相同的数字。 然后我们可以得出结论,没有答案存在,我们返回`nil`
231+
232+
我非常迷恋这个小算法。 它表明,对输入数据进行一些基本的预处理 - 从低到高排序 - 你可以把一个棘手的问题变成一个非常简单和漂亮的算法。
233+
167234
## Additional Reading
235+
## 等多阅读
168236

169237
* [3Sum / 4Sum](https://github.com/raywenderlich/swift-algorithm-club/tree/master/3Sum%20and%204Sum)
170238

171239
*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser*
240+
241+
*作者:Matthijs Hollemans, Daniel Speiser*
242+
*翻译:[Andy Ron](https://github.com/andyRon)*

Two-Sum Problem/README_en.markdown

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Two-Sum Problem
2+
3+
Given an array of integers and an integer target, return the indices of two numbers that add up to the target.
4+
5+
There are a variety of solutions to this problem (some better than others). The following solutions both run in **O(n)** time.
6+
7+
# Solution 1
8+
9+
This solution looks at one number at a time, storing each number in the dictionary. It uses the number as the key and the number's index in the array as the value.
10+
11+
For each number n, we know the complementing number to sum up to the target is `target - n`. By looking up the complement in the dictionary, we'd know whether we've seen the complement before and what its index is.
12+
13+
```swift
14+
func twoSum(_ nums: [Int], target: Int) -> (Int, Int)? {
15+
var dict = [Int: Int]()
16+
17+
// For every number n,
18+
for (currentIndex, n) in nums.enumerated() {
19+
// Find the complement to n that would sum up to the target.
20+
let complement = target - n
21+
22+
// Check if the complement is in the dictionary.
23+
if let complementIndex = dict[complement] {
24+
return (complementIndex, currentIndex)
25+
}
26+
27+
// Store n and its index into the dictionary.
28+
dict[n] = currentIndex
29+
}
30+
31+
return nil
32+
}
33+
```
34+
35+
The `twoSum` function takes two parameters: the `numbers` array and the target sum. It returns the two indicies of the pair of elements that sums up to the target, or `nil` if they can't be found.
36+
37+
Let's run through the algorithm to see how it works. Given the array:
38+
39+
```swift
40+
[3, 2, 9, 8]
41+
```
42+
43+
Let's find out if there exist two entries whose sum is 10.
44+
45+
Initially, our dictionary is empty. We begin looping through each element:
46+
47+
- **currentIndex = 0** | n = nums[0] = 3 | complement = 10 - 3 = 7
48+
49+
Is the complement `7` in the dictionary? No, so we add `3` and its index `0` to the dictionary.
50+
51+
```swift
52+
[3: 0]
53+
```
54+
55+
- **currentIndex = 1** | n = 2 | complement = 10 - 2 = 8
56+
57+
Is the complement `8` in the dictionary? No, so we add `2` and its index `1` to the dictionary.
58+
59+
```swift
60+
[3: 0, 2: 1]
61+
```
62+
63+
- **currentIndex = 2** | n = 9 | complement = 10 - 9 = 1
64+
65+
Is the complement `1` in the dictionary? No, so we add `9` and its index `2` to the dictionary.:
66+
67+
```swift
68+
[3: 0, 2: 1, 9: 2]
69+
```
70+
71+
- **currentIndex = 3** | n = 8 | complement = 10 - 8 = 2
72+
73+
Is the complement `2` in the dictionary? Yes! That means that we have found a pair of entries that sum to the target!
74+
75+
Therefore, the `complementIndex = dict[2] = 1` and the `currentIndex = 3`. The tuple we return is `(1, 3)`.
76+
77+
If the given array has multiple solutions, only the first solution is returned.
78+
79+
The running time of this algorithm is **O(n)** because it may look at every element in the array. It also requires **O(n)** additional storage space for the dictionary.
80+
81+
# Solution 2
82+
83+
**Note**: This particular algorithm requires that the array is sorted, so if the array isn't sorted yet (usually it won't be), you need to sort it first. The time complexity of the algorithm itself is **O(n)** and, unlike the previous solution, it does not require extra storage. Of course, if you have to sort first, the total time complexity becomes **O(n log n)**. Slightly worse but still quite acceptable.
84+
85+
Here is the code in Swift:
86+
87+
```swift
88+
func twoSumProblem(_ a: [Int], k: Int) -> ((Int, Int))? {
89+
var i = 0
90+
var j = a.count - 1
91+
92+
while i < j {
93+
let sum = a[i] + a[j]
94+
if sum == k {
95+
return (i, j)
96+
} else if sum < k {
97+
i += 1
98+
} else {
99+
j -= 1
100+
}
101+
}
102+
return nil
103+
}
104+
```
105+
106+
As in the first solution, the `twoSumProblem()` function takes as parameters the array `a` with the numbers and `k`, the sum we're looking for. If there are two numbers that add up to `k`, the function returns a tuple containing their array indices. If not, it returns `nil`. The main difference is that `a` is assumed to be sorted.
107+
108+
To test it, copy the code into a playground and add the following:
109+
110+
```swift
111+
let a = [2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100]
112+
if let (i, j) = twoSumProblem(a, k: 33) {
113+
a[i] + a[j] // 33
114+
}
115+
```
116+
117+
This returns the tuple `(8, 10)` because `a[8] = 12` and `a[10] = 21`, and together they add up to `33`.
118+
119+
So how does this algorithm work? It takes advantage of the array being sorted. That's true for many algorithms, by the way. If you first sort the data, it's often easier to perform your calculations.
120+
121+
In the example, the sorted array is:
122+
123+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
124+
125+
The algorithm uses the two variables `i` and `j` to point to the beginning and end of the array, respectively. Then it increments `i` and decrements `j` until the two meet. While it's doing this, it checks whether `a[i]` and `a[j]` add up to `k`.
126+
127+
Let's step through this. Initially, we have:
128+
129+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
130+
i j
131+
132+
The sum of these two is `2 + 100 = 102`. That's obviously too much, since `k = 33` in this example. There is no way that `100` will ever be part of the answer, so decrement `j`.
133+
134+
We have:
135+
136+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
137+
i j
138+
139+
The sum is `2 + 22 = 24`. Now the sum is too small. We can safely conclude at this point that the number `2` will never be part of the answer. The largest number on the right is `22`, so we at least need `11` on the left to make `33`. Anything less than `11` is not going to cut it. (This is why we sorted the array!)
140+
141+
So, `2` is out and we increment `i` to look at the next small number.
142+
143+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
144+
i j
145+
146+
The sum is `3 + 22 = 25`. Still too small, so increment `i` again.
147+
148+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
149+
i j
150+
151+
In fact, we have to increment `i` a few more times, until we get to `12`:
152+
153+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
154+
i j
155+
156+
Now the sum is `12 + 22 = 34`. It's too high, which means we need to decrement `j`. This gives:
157+
158+
[ 2, 3, 4, 4, 7, 8, 9, 10, 12, 14, 21, 22, 100 ]
159+
i j
160+
161+
And finally, we have the answer: `12 + 21 = 33`. Yay!
162+
163+
It's possible, of course, that there are no values for `a[i] + a[j]` that sum to `k`. In that case, eventually `i` and `j` will point at the same number. Then we can conclude that no answer exists and we return `nil`.
164+
165+
I'm quite enamored by this little algorithm. It shows that with some basic preprocessing on the input data -- sorting it from low to high -- you can turn a tricky problem into a very simple and beautiful algorithm.
166+
167+
## Additional Reading
168+
169+
* [3Sum / 4Sum](https://github.com/raywenderlich/swift-algorithm-club/tree/master/3Sum%20and%204Sum)
170+
171+
*Written for Swift Algorithm Club by Matthijs Hollemans and Daniel Speiser*

0 commit comments

Comments
 (0)