Skip to content

Commit d645be9

Browse files
committed
feat: add solutions to lc problem: No.0015
No.0015.3Sum
1 parent 5d6ca31 commit d645be9

10 files changed

+192
-468
lines changed

solution/0000-0099/0015.3Sum/README.md

+73-179
Original file line numberDiff line numberDiff line change
@@ -58,34 +58,13 @@ nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
5858

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

61-
若是使用三层嵌套循环,必然会导致程序超时,需要寻找其它方法。
61+
**方法一:排序 + 双指针**
6262

63-
因为不是返回对应的索引,所以可以对数组进行排序
63+
题目不要求我们按照顺序返回三元组,因此我们可以先对数组进行排序,这样就可以方便地跳过重复的元素
6464

65-
1.`nums` 进行排序。
66-
2. 遍历数组,并以当前遍历位置作为分割线,在右侧数组当中(不包括分割元素在内),寻找两个可以组成 `0 - nums[i]` 的值,将该题转换为**两数之和**
65+
接着枚举数组中的第一个元素 $nums[i]$,我们可以使用双指针的方法枚举第二个元素 $nums[j]$ 和第三个元素 $nums[k]$,使得它们的和为 $-nums[i]$。在枚举的过程中,我们需要跳过重复的元素,以避免出现重复的三元组。
6766

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)$。
8968

9069
<!-- tabs:start -->
9170

@@ -96,30 +75,28 @@ nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
9675
```python
9776
class Solution:
9877
def threeSum(self, nums: List[int]) -> List[List[int]]:
99-
n, res = len(nums), []
100-
if n < 3:
101-
return res
10278
nums.sort()
79+
n = len(nums)
80+
ans = []
10381
for i in range(n - 2):
10482
if nums[i] > 0:
10583
break
106-
if i > 0 and nums[i] == nums[i - 1]:
84+
if i and nums[i] == nums[i - 1]:
10785
continue
10886
j, k = i + 1, n - 1
10987
while j < k:
11088
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
11491
while j < n and nums[j] == nums[j - 1]:
11592
j += 1
116-
while k > i and nums[k] == nums[k + 1]:
93+
while k > j and nums[k] == nums[k + 1]:
11794
k -= 1
11895
elif nums[i] + nums[j] + nums[k] < 0:
11996
j += 1
12097
else:
12198
k -= 1
122-
return res
99+
return ans
123100
```
124101

125102
### **Java**
@@ -129,26 +106,21 @@ class Solution:
129106
```java
130107
class Solution {
131108
public List<List<Integer>> threeSum(int[] nums) {
132-
int n = nums.length;
133-
if (n < 3) {
134-
return Collections.emptyList();
135-
}
136109
Arrays.sort(nums);
137-
List<List<Integer>> res = new ArrayList<>();
110+
List<List<Integer>> ans = new ArrayList<>();
111+
int n = nums.length;
138112
for (int i = 0; i < n - 2 && nums[i] <= 0; ++i) {
139113
if (i > 0 && nums[i] == nums[i - 1]) {
140114
continue;
141115
}
142116
int j = i + 1, k = n - 1;
143117
while (j < k) {
144118
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--]));
148120
while (j < n && nums[j] == nums[j - 1]) {
149121
++j;
150122
}
151-
while (k > i && nums[k] == nums[k + 1]) {
123+
while (k > j && nums[k] == nums[k + 1]) {
152124
--k;
153125
}
154126
} else if (nums[i] + nums[j] + nums[k] < 0) {
@@ -158,7 +130,7 @@ class Solution {
158130
}
159131
}
160132
}
161-
return res;
133+
return ans;
162134
}
163135
}
164136
```
@@ -169,67 +141,58 @@ class Solution {
169141
class Solution {
170142
public:
171143
vector<vector<int>> threeSum(vector<int>& nums) {
172-
int n = nums.size();
173-
if (n < 3) {
174-
return {};
175-
}
176144
sort(nums.begin(), nums.end());
177-
vector<vector<int>> res;
145+
int n = nums.size();
146+
vector<vector<int>> ans;
178147
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;
180149
int j = i + 1, k = n - 1;
181150
while (j < k) {
182151
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;
188155
} else if (nums[i] + nums[j] + nums[k] < 0) {
189156
++j;
190157
} else {
191158
--k;
192159
}
193160
}
194161
}
195-
return res;
162+
return ans;
196163
}
197164
};
198165
```
199166
200167
### **Go**
201168
202169
```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
233196
}
234197
```
235198

@@ -242,7 +205,6 @@ func threeSum(nums []int) [][]int {
242205
*/
243206
var threeSum = function (nums) {
244207
const n = nums.length;
245-
if (n < 3) return [];
246208
let res = [];
247209
nums.sort((a, b) => a - b);
248210
for (let i = 0; i < n - 2 && nums[i] <= 0; ++i) {
@@ -251,9 +213,7 @@ var threeSum = function (nums) {
251213
let k = n - 1;
252214
while (j < k) {
253215
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--]]);
257217
while (nums[j] === nums[j - 1]) ++j;
258218
while (nums[k] === nums[k + 1]) --k;
259219
} else if (nums[i] + nums[j] + nums[k] < 0) {
@@ -270,91 +230,33 @@ var threeSum = function (nums) {
270230
### **C#**
271231

272232
```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-
286233
public class Solution {
287234
public IList<IList<int>> ThreeSum(int[] nums) {
288235
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;
326248
}
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;
335251
}
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;
352256
}
353257
}
354-
++cIndex;
355258
}
356-
357-
return results.ToList();
259+
return ans;
358260
}
359261
}
360262
```
@@ -397,20 +299,15 @@ end
397299
```ts
398300
function threeSum(nums: number[]): number[][] {
399301
nums.sort((a, b) => a - b);
400-
const res = [];
302+
const ans = [];
401303
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++) {
406305
const target = 0 - nums[i];
407306
let l = i + 1;
408307
let r = n - 1;
409308
while (l < r) {
410309
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--]]);
414311
while (nums[l] === nums[l - 1]) {
415312
l++;
416313
}
@@ -427,7 +324,7 @@ function threeSum(nums: number[]): number[][] {
427324
i++;
428325
}
429326
}
430-
return res;
327+
return ans;
431328
}
432329
```
433330

@@ -441,9 +338,6 @@ impl Solution {
441338
nums.sort();
442339
let n = nums.len();
443340
let mut res = vec![];
444-
if n < 3 {
445-
return res;
446-
}
447341
let mut i = 0;
448342
while i < n - 2 && nums[i] <= 0 {
449343
let mut l = i + 1;

0 commit comments

Comments
 (0)