Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions solution/0000-0099/0015.3Sum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,34 @@

<!-- 这里可写通用的实现逻辑 -->

“排序 + 双指针”实现。
若是使用三层嵌套循环,必然会导致程序超时,需要寻找其它方法。

因为不是返回对应的索引,所以可以对数组进行排序。

1. 对 `nums` 进行排序。
2. 遍历数组,并以当前遍历位置作为分割线,在右侧数组当中(不包括分割元素在内),寻找两个可以组成 `0 - nums[i]` 的值,将该题转换为**两数之和**。

> 更贴切的说,与 [剑指 Offer 57. 和为s的两个数字](https://leetcode-cn.com/problems/he-wei-sde-liang-ge-shu-zi-lcof/) 目标一致

**优化:**

- 当 `nums[i] > 0` 时,其后续的数值都比 `nums[i]` 大,那么就不可能存在两个数值一起组合为 0,可以提前结束遍历。
- 若当前遍历数值与上一个数值一致(`nums[i] == nums[i - 1]`),可直接跳过(去重复)。
- 相比两数之和,与其不同的是:**目标数组是有序的**。可使用**二分查找**或**头尾指针**快速搜索目标。

**重复问题:**

最简易的方式便是使用哈希表。还有一种技巧:**双指针**

能够使用双指针(头尾指针)搜索目标是因为**数组是有序的**,当移动指针时,数值的变化可预测的。

> 此处头尾指针使用 `l` 与 `r` 表示。

当找到目标值之后,`l` 与 `r` 都需要进行移动,并且是**移动到不等于组合时的值**。如 `nums[l] == 0`,那么 `l` 需要移动至 `nums[l] != 0` 的位置,`r` 同理。

为什么要同时移动两个指针,不会导致错过答案吗?并不会,如一个符合题意的组合是 `[-1, 0, 1]`,当 `l` 移动到了非 0 的位置时,那么 `nums[r] = 1` 不可能再组合出一个不重复的答案。

> 需注意,该技巧需要与第二条优化一起使用。

<!-- tabs:start -->

Expand Down Expand Up @@ -237,7 +264,7 @@ public class ThreeSumComparer: IEqualityComparer<IList<int>>
{
return left[0] == right[0] && left[1] == right[1] && left[2] == right[2];
}

public int GetHashCode(IList<int> obj)
{
return (obj[0] ^ obj[1] ^ obj[2]).GetHashCode();
Expand All @@ -248,7 +275,7 @@ public class Solution {
public IList<IList<int>> ThreeSum(int[] nums) {
Array.Sort(nums);
var results = new HashSet<IList<int>>(new ThreeSumComparer());

var cIndex = Array.BinarySearch(nums, 0);
if (cIndex < 0) cIndex = ~cIndex;
while (cIndex < nums.Length)
Expand Down Expand Up @@ -276,7 +303,7 @@ public class Solution {
step /= 2;
}
}

if (nums[aIndex] + nums[bIndex] + c > 0)
{
var step = 1;
Expand All @@ -295,7 +322,7 @@ public class Solution {
step /= 2;
}
}

if (nums[aIndex] + nums[bIndex] + c == 0)
{
var list = new List<int> { nums[aIndex], nums[bIndex], c };
Expand All @@ -314,7 +341,7 @@ public class Solution {
}
++cIndex;
}

return results.ToList();
}
}
Expand Down