46
46
47
47
<!-- 这里可写通用的实现逻辑 -->
48
48
49
- “排序 + 双指针”实现。
49
+ 若是使用三层嵌套循环,必然会导致程序超时,需要寻找其它方法。
50
+
51
+ 因为不是返回对应的索引,所以可以对数组进行排序。
52
+
53
+ 1 . 对 ` nums ` 进行排序。
54
+ 2 . 遍历数组,并以当前遍历位置作为分割线,在右侧数组当中(不包括分割元素在内),寻找两个可以组成 ` 0 - nums[i] ` 的值,将该题转换为** 两数之和** 。
55
+
56
+ > 更贴切的说,与 [ 剑指 Offer 57. 和为s的两个数字] ( https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/ ) 目标一致
57
+
58
+ ** 优化:**
59
+
60
+ - 当 ` nums[i] > 0 ` 时,其后续的数值都比 ` nums[i] ` 大,那么就不可能存在两个数值一起组合为 0,可以提前结束遍历。
61
+ - 若当前遍历数值与上一个数值一致(` nums[i] == nums[i - 1] ` ),可直接跳过(去重复)。
62
+ - 相比两数之和,与其不同的是:** 目标数组是有序的** 。可使用** 二分查找** 或** 头尾指针** 快速搜索目标。
63
+
64
+ ** 重复问题:**
65
+
66
+ 最简易的方式便是使用哈希表。还有一种技巧:** 双指针**
67
+
68
+ 能够使用双指针(头尾指针)搜索目标是因为** 数组是有序的** ,当移动指针时,数值的变化可预测的。
69
+
70
+ > 此处头尾指针使用 ` l ` 与 ` r ` 表示。
71
+
72
+ 当找到目标值之后,` l ` 与 ` r ` 都需要进行移动,并且是** 移动到不等于组合时的值** 。如 ` nums[l] == 0 ` ,那么 ` l ` 需要移动至 ` nums[l] != 0 ` 的位置,` r ` 同理。
73
+
74
+ 为什么要同时移动两个指针,不会导致错过答案吗?并不会,如一个符合题意的组合是 ` [-1, 0, 1] ` ,当 ` l ` 移动到了非 0 的位置时,那么 ` nums[r] = 1 ` 不可能再组合出一个不重复的答案。
75
+
76
+ > 需注意,该技巧需要与第二条优化一起使用。
50
77
51
78
<!-- tabs:start -->
52
79
@@ -237,7 +264,7 @@ public class ThreeSumComparer: IEqualityComparer<IList<int>>
237
264
{
238
265
return left [0 ] == right [0 ] && left [1 ] == right [1 ] && left [2 ] == right [2 ];
239
266
}
240
-
267
+
241
268
public int GetHashCode (IList <int > obj )
242
269
{
243
270
return (obj [0 ] ^ obj [1 ] ^ obj [2 ]).GetHashCode ();
@@ -248,7 +275,7 @@ public class Solution {
248
275
public IList <IList <int >> ThreeSum (int [] nums ) {
249
276
Array .Sort (nums );
250
277
var results = new HashSet <IList <int >>(new ThreeSumComparer ());
251
-
278
+
252
279
var cIndex = Array .BinarySearch (nums , 0 );
253
280
if (cIndex < 0 ) cIndex = ~ cIndex ;
254
281
while (cIndex < nums .Length )
@@ -276,7 +303,7 @@ public class Solution {
276
303
step /= 2 ;
277
304
}
278
305
}
279
-
306
+
280
307
if (nums [aIndex ] + nums [bIndex ] + c > 0 )
281
308
{
282
309
var step = 1 ;
@@ -295,7 +322,7 @@ public class Solution {
295
322
step /= 2 ;
296
323
}
297
324
}
298
-
325
+
299
326
if (nums [aIndex ] + nums [bIndex ] + c == 0 )
300
327
{
301
328
var list = new List <int > { nums [aIndex ], nums [bIndex ], c };
@@ -314,7 +341,7 @@ public class Solution {
314
341
}
315
342
++ cIndex ;
316
343
}
317
-
344
+
318
345
return results .ToList ();
319
346
}
320
347
}
0 commit comments