@@ -58,34 +58,13 @@ nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
58
58
59
59
<!-- 这里可写通用的实现逻辑 -->
60
60
61
- 若是使用三层嵌套循环,必然会导致程序超时,需要寻找其它方法。
61
+ ** 方法一:排序 + 双指针 **
62
62
63
- 因为不是返回对应的索引,所以可以对数组进行排序 。
63
+ 题目不要求我们按照顺序返回三元组,因此我们可以先对数组进行排序,这样就可以方便地跳过重复的元素 。
64
64
65
- 1 . 对 ` nums ` 进行排序。
66
- 2 . 遍历数组,并以当前遍历位置作为分割线,在右侧数组当中(不包括分割元素在内),寻找两个可以组成 ` 0 - nums[i] ` 的值,将该题转换为** 两数之和** 。
65
+ 接着枚举数组中的第一个元素 $nums[ i] $,我们可以使用双指针的方法枚举第二个元素 $nums[ j] $ 和第三个元素 $nums[ k] $,使得它们的和为 $-nums[ i] $。在枚举的过程中,我们需要跳过重复的元素,以避免出现重复的三元组。
67
66
68
- > 更贴切的说,与 [ 剑指 Offer 57. 和为 s 的两个数字] ( https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/ ) 目标一致
69
-
70
- ** 优化:**
71
-
72
- - 当 ` nums[i] > 0 ` 时,其后续的数值都比 ` nums[i] ` 大,那么就不可能存在两个数值一起组合为 0,可以提前结束遍历。
73
- - 若当前遍历数值与上一个数值一致(` nums[i] == nums[i - 1] ` ),可直接跳过(去重复)。
74
- - 相比两数之和,与其不同的是:** 目标数组是有序的** 。可使用** 二分查找** 或** 头尾指针** 快速搜索目标。
75
-
76
- ** 重复问题:**
77
-
78
- 最简易的方式便是使用哈希表。还有一种技巧:** 双指针**
79
-
80
- 能够使用双指针(头尾指针)搜索目标是因为** 数组是有序的** ,当移动指针时,数值的变化可预测的。
81
-
82
- > 此处头尾指针使用 ` l ` 与 ` r ` 表示。
83
-
84
- 当找到目标值之后,` l ` 与 ` r ` 都需要进行移动,并且是** 移动到不等于组合时的值** 。如 ` nums[l] == 0 ` ,那么 ` l ` 需要移动至 ` nums[l] != 0 ` 的位置,` r ` 同理。
85
-
86
- 为什么要同时移动两个指针,不会导致错过答案吗?并不会,如一个符合题意的组合是 ` [-1, 0, 1] ` ,当 ` l ` 移动到了非 0 的位置时,那么 ` nums[r] = 1 ` 不可能再组合出一个不重复的答案。
87
-
88
- > 需注意,该技巧需要与第二条优化一起使用。
67
+ 时间复杂度 $O(n^2 + n\times \log n)$。其中 $n$ 是数组的长度。枚举第一个元素需要 $O(n)$ 的时间,枚举第二个元素和第三个元素需要 $O(n)$ 的时间,排序的时间复杂度为 $O(n\times \log n)$。
89
68
90
69
<!-- tabs:start -->
91
70
@@ -96,30 +75,28 @@ nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
96
75
``` python
97
76
class Solution :
98
77
def threeSum (self , nums : List[int ]) -> List[List[int ]]:
99
- n, res = len (nums), []
100
- if n < 3 :
101
- return res
102
78
nums.sort()
79
+ n = len (nums)
80
+ ans = []
103
81
for i in range (n - 2 ):
104
82
if nums[i] > 0 :
105
83
break
106
- if i > 0 and nums[i] == nums[i - 1 ]:
84
+ if i and nums[i] == nums[i - 1 ]:
107
85
continue
108
86
j, k = i + 1 , n - 1
109
87
while j < k:
110
88
if nums[i] + nums[j] + nums[k] == 0 :
111
- res.append([nums[i], nums[j], nums[k]])
112
- j += 1
113
- k -= 1
89
+ ans.append([nums[i], nums[j], nums[k]])
90
+ j, k = j + 1 , k - 1
114
91
while j < n and nums[j] == nums[j - 1 ]:
115
92
j += 1
116
- while k > i and nums[k] == nums[k + 1 ]:
93
+ while k > j and nums[k] == nums[k + 1 ]:
117
94
k -= 1
118
95
elif nums[i] + nums[j] + nums[k] < 0 :
119
96
j += 1
120
97
else :
121
98
k -= 1
122
- return res
99
+ return ans
123
100
```
124
101
125
102
### ** Java**
@@ -129,26 +106,21 @@ class Solution:
129
106
``` java
130
107
class Solution {
131
108
public List<List<Integer > > threeSum (int [] nums ) {
132
- int n = nums. length;
133
- if (n < 3 ) {
134
- return Collections . emptyList();
135
- }
136
109
Arrays . sort(nums);
137
- List<List<Integer > > res = new ArrayList<> ();
110
+ List<List<Integer > > ans = new ArrayList<> ();
111
+ int n = nums. length;
138
112
for (int i = 0 ; i < n - 2 && nums[i] <= 0 ; ++ i) {
139
113
if (i > 0 && nums[i] == nums[i - 1 ]) {
140
114
continue ;
141
115
}
142
116
int j = i + 1 , k = n - 1 ;
143
117
while (j < k) {
144
118
if (nums[i] + nums[j] + nums[k] == 0 ) {
145
- res. add(Arrays . asList(nums[i], nums[j], nums[k]));
146
- ++ j;
147
- -- k;
119
+ ans. add(Arrays . asList(nums[i], nums[j++ ], nums[k-- ]));
148
120
while (j < n && nums[j] == nums[j - 1 ]) {
149
121
++ j;
150
122
}
151
- while (k > i && nums[k] == nums[k + 1 ]) {
123
+ while (k > j && nums[k] == nums[k + 1 ]) {
152
124
-- k;
153
125
}
154
126
} else if (nums[i] + nums[j] + nums[k] < 0 ) {
@@ -158,7 +130,7 @@ class Solution {
158
130
}
159
131
}
160
132
}
161
- return res ;
133
+ return ans ;
162
134
}
163
135
}
164
136
```
@@ -169,67 +141,58 @@ class Solution {
169
141
class Solution {
170
142
public:
171
143
vector<vector<int >> threeSum(vector<int >& nums) {
172
- int n = nums.size();
173
- if (n < 3) {
174
- return {};
175
- }
176
144
sort(nums.begin(), nums.end());
177
- vector<vector<int >> res;
145
+ int n = nums.size();
146
+ vector<vector<int >> ans;
178
147
for (int i = 0; i < n - 2 && nums[ i] <= 0; ++i) {
179
- if (i > 0 && nums[ i] == nums[ i - 1] ) continue;
148
+ if (i && nums[ i] == nums[ i - 1] ) continue;
180
149
int j = i + 1, k = n - 1;
181
150
while (j < k) {
182
151
if (nums[ i] + nums[ j] + nums[ k] == 0) {
183
- res.push_back({nums[ i] , nums[ j] , nums[ k] });
184
- ++j;
185
- --k;
186
- while (j < n && nums[ j] == nums[ j - 1] ) ++j;
187
- while (k > i && nums[ k] == nums[ k + 1] ) --k;
152
+ ans.push_back({nums[ i] , nums[ j++] , nums[ k--] });
153
+ while (j < k && nums[ j] == nums[ j - 1] ) ++j;
154
+ while (j < k && nums[ k] == nums[ k + 1] ) --k;
188
155
} else if (nums[ i] + nums[ j] + nums[ k] < 0) {
189
156
++j;
190
157
} else {
191
158
--k;
192
159
}
193
160
}
194
161
}
195
- return res ;
162
+ return ans ;
196
163
}
197
164
};
198
165
```
199
166
200
167
### **Go**
201
168
202
169
```go
203
- func threeSum(nums []int) [][]int {
204
- n, res := len(nums), make([][]int, 0)
205
- if n < 3 {
206
- return res
207
- }
208
- sort.Ints(nums)
209
- for i := 0; i < n-2 && nums[i] <= 0; i++ {
210
- if i > 0 && nums[i] == nums[i-1] {
211
- continue
212
- }
213
- j, k := i+1, n-1
214
- for j < k {
215
- if nums[i]+nums[j]+nums[k] == 0 {
216
- res = append(res, []int{nums[i], nums[j], nums[k]})
217
- j++
218
- k--
219
- for j < n && nums[j] == nums[j-1] {
220
- j++
221
- }
222
- for k > i && nums[k] == nums[k+1] {
223
- k--
224
- }
225
- } else if nums[i]+nums[j]+nums[k] < 0 {
226
- j++
227
- } else {
228
- k--
229
- }
230
- }
231
- }
232
- return res
170
+ func threeSum(nums []int) (ans [][]int) {
171
+ sort.Ints(nums)
172
+ n := len(nums)
173
+ for i := 0; i < n - 2 && nums[i] <= 0; i++ {
174
+ if i > 0 && nums[i] == nums[i - 1] {
175
+ continue
176
+ }
177
+ j, k := i + 1, n - 1
178
+ for j < k {
179
+ if nums[i] + nums[j] + nums[k] == 0 {
180
+ ans = append(ans, []int{nums[i], nums[j], nums[k]})
181
+ j, k = j + 1, k - 1
182
+ for j < k && nums[j] == nums[j - 1] {
183
+ j++
184
+ }
185
+ for j < k && nums[k] == nums[k + 1] {
186
+ k--
187
+ }
188
+ } else if nums[i] + nums[j] + nums[k] < 0 {
189
+ j++
190
+ } else {
191
+ k--
192
+ }
193
+ }
194
+ }
195
+ return
233
196
}
234
197
```
235
198
@@ -242,7 +205,6 @@ func threeSum(nums []int) [][]int {
242
205
*/
243
206
var threeSum = function (nums ) {
244
207
const n = nums .length ;
245
- if (n < 3 ) return [];
246
208
let res = [];
247
209
nums .sort ((a , b ) => a - b);
248
210
for (let i = 0 ; i < n - 2 && nums[i] <= 0 ; ++ i) {
@@ -251,9 +213,7 @@ var threeSum = function (nums) {
251
213
let k = n - 1 ;
252
214
while (j < k) {
253
215
if (nums[i] + nums[j] + nums[k] === 0 ) {
254
- res .push ([nums[i], nums[j], nums[k]]);
255
- ++ j;
256
- -- k;
216
+ res .push ([nums[i], nums[j++ ], nums[k-- ]]);
257
217
while (nums[j] === nums[j - 1 ]) ++ j;
258
218
while (nums[k] === nums[k + 1 ]) -- k;
259
219
} else if (nums[i] + nums[j] + nums[k] < 0 ) {
@@ -270,91 +230,33 @@ var threeSum = function (nums) {
270
230
### ** C#**
271
231
272
232
``` cs
273
- public class ThreeSumComparer : IEqualityComparer <IList <int >>
274
- {
275
- public bool Equals (IList <int > left , IList <int > right )
276
- {
277
- return left [0 ] == right [0 ] && left [1 ] == right [1 ] && left [2 ] == right [2 ];
278
- }
279
-
280
- public int GetHashCode (IList <int > obj )
281
- {
282
- return (obj [0 ] ^ obj [1 ] ^ obj [2 ]).GetHashCode ();
283
- }
284
- }
285
-
286
233
public class Solution {
287
234
public IList <IList <int >> ThreeSum (int [] nums ) {
288
235
Array .Sort (nums );
289
- var results = new HashSet <IList <int >>(new ThreeSumComparer ());
290
-
291
- var cIndex = Array .BinarySearch (nums , 0 );
292
- if (cIndex < 0 ) cIndex = ~ cIndex ;
293
- while (cIndex < nums .Length )
294
- {
295
- var c = nums [cIndex ];
296
- var aIndex = 0 ;
297
- var bIndex = cIndex - 1 ;
298
- while (aIndex < bIndex )
299
- {
300
- if (nums [aIndex ] + nums [bIndex ] + c < 0 )
301
- {
302
- var step = 1 ;
303
- while (aIndex + step < bIndex && nums [aIndex + step ] + nums [bIndex ] + c < 0 )
304
- {
305
- aIndex += step ;
306
- step *= 2 ;
307
- }
308
- step /= 2 ;
309
- while (step > 0 )
310
- {
311
- if (aIndex + step < bIndex && nums [aIndex + step ] + nums [bIndex ] + c < 0 )
312
- {
313
- aIndex += step ;
314
- }
315
- step /= 2 ;
316
- }
317
- }
318
-
319
- if (nums [aIndex ] + nums [bIndex ] + c > 0 )
320
- {
321
- var step = 1 ;
322
- while (aIndex < bIndex - step && nums [aIndex ] + nums [bIndex - step ] + c > 0 )
323
- {
324
- bIndex -= step ;
325
- step *= 2 ;
236
+ int n = nums .Length ;
237
+ IList < IList < int >> ans = new List <IList <int >>();
238
+ for (int i = 0 ; i < n - 2 && nums [i ] <= 0 ; ++ i ) {
239
+ if (i > 0 && nums [i ] == nums [i - 1 ]) {
240
+ continue ;
241
+ }
242
+ int j = i + 1 , k = n - 1 ;
243
+ while (j < k ) {
244
+ if (nums [i ] + nums [j ] + nums [k ] == 0 ) {
245
+ ans .Add (new List <int > { nums [i ], nums [j ++ ], nums [k -- ] });
246
+ while (j < n && nums [j ] == nums [j - 1 ]) {
247
+ ++ j ;
326
248
}
327
- step /= 2 ;
328
- while (step > 0 )
329
- {
330
- if (aIndex < bIndex - step && nums [aIndex ] + nums [bIndex - step ] + c > 0 )
331
- {
332
- bIndex -= step ;
333
- }
334
- step /= 2 ;
249
+ while (k > j && nums [k ] == nums [k + 1 ]) {
250
+ -- k ;
335
251
}
336
- }
337
-
338
- if (nums [aIndex ] + nums [bIndex ] + c == 0 )
339
- {
340
- var list = new List <int > { nums [aIndex ], nums [bIndex ], c };
341
- results .Add (list );
342
- ++ aIndex ;
343
- -- bIndex ;
344
- }
345
- else if (nums [aIndex ] + nums [bIndex ] + c < 0 )
346
- {
347
- ++ aIndex ;
348
- }
349
- else
350
- {
351
- -- bIndex ;
252
+ } else if (nums [i ] + nums [j ] + nums [k ] < 0 ) {
253
+ ++ j ;
254
+ } else {
255
+ -- k ;
352
256
}
353
257
}
354
- ++ cIndex ;
355
258
}
356
-
357
- return results .ToList ();
259
+ return ans ;
358
260
}
359
261
}
360
262
```
@@ -397,20 +299,15 @@ end
397
299
``` ts
398
300
function threeSum(nums : number []): number [][] {
399
301
nums .sort ((a , b ) => a - b );
400
- const res = [];
302
+ const ans = [];
401
303
const n = nums .length ;
402
- for (let i = 0 ; i < n - 2 ; i ++ ) {
403
- if (nums [i ] > 0 ) {
404
- break ;
405
- }
304
+ for (let i = 0 ; i < n - 2 && nums [i ] <= 0 ; i ++ ) {
406
305
const target = 0 - nums [i ];
407
306
let l = i + 1 ;
408
307
let r = n - 1 ;
409
308
while (l < r ) {
410
309
if (nums [l ] + nums [r ] === target ) {
411
- res .push ([nums [i ], nums [l ], nums [r ]]);
412
- l ++ ;
413
- r -- ;
310
+ ans .push ([nums [i ], nums [l ++ ], nums [r -- ]]);
414
311
while (nums [l ] === nums [l - 1 ]) {
415
312
l ++ ;
416
313
}
@@ -427,7 +324,7 @@ function threeSum(nums: number[]): number[][] {
427
324
i ++ ;
428
325
}
429
326
}
430
- return res ;
327
+ return ans ;
431
328
}
432
329
```
433
330
@@ -441,9 +338,6 @@ impl Solution {
441
338
nums . sort ();
442
339
let n = nums . len ();
443
340
let mut res = vec! [];
444
- if n < 3 {
445
- return res ;
446
- }
447
341
let mut i = 0 ;
448
342
while i < n - 2 && nums [i ] <= 0 {
449
343
let mut l = i + 1 ;
0 commit comments