题目描述:
给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
1 | 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], |
解题思路:
这题肯定要写循环遍历数组的。
想到的第一种办法就是:遍历数组,每次都与其后面的数组进行相加,如果得到的结果的倒数,在剩余数组中能够找到,则成功。
存在的问题:
- 如何快速的定位两数之和的倒数仍在剩余的数组中 - 如果有重复的结果,如何有效的去重
第一个问题,我采用的办法是使用
list```中的```in```方法,因为list是使用线性结构存储的,其查询复杂度是$O(n)$,整个程序的时间复杂度就达到了$O(n^3)$。列表与字典的存储结构不同,字典使用Hash表结构来存储,其存取效率要高很多,时间复杂度是$O(1)$。 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
第二个问题,去重也是使用的```in```方法判断是否在列表其中,在其中,则不添加。
```python
if len(nums) < 3:
return []
result = []
for i in range(len(nums)-1):
for j in range(i+1, len(nums)):
sum = nums[i] + nums[j]
if -sum in nums:
k = nums.index(-sum)
if k != i and k != j:
temp = sorted([nums[i], nums[j], nums[k]])
if temp not in result:
result.append(temp)
return result所以想的是,为了提高遍历效率,要考虑使用双指针。
Tips : 一般遍历问题,都考虑一下是否可以使用双指针,然后想清楚双指针的移动条件。
先对数组排序,使用双指针从首尾两端对数组进行遍历。每次都得到首尾两端数字的和,然后判断两数字和的倒数是否在剩余的列表切片中即可。如果在的话,则加到结果集中。如果不在的话…. 额(⊙o⊙)…是个问题。
如果两数字之和大于0,则需要右边(大于0)的指针左移
如果两数之和小于0…
好像这样讲不出道理。。。GG
虽然上一种做法有问题,不过双指针的想法还是正确的。所以,应该换个思路。
先对列表进行排序,然后从头到尾遍历。这样每次都固定住一个值,而不是用双指针来解决三值问题,好像是可行的。
在固定一个值之后,剩下的有序列表中,用双指针法寻找两个值的和是否是固定值的负数。这样指针移动的标准也就出来了。如下图:
- 当两值之和大于固定值的负数时,右边的指针左移
- 当两值之和小于固定值的负数时,左边指针右移
- 当两值之和恰好为固定值负数,保存结果。此时有个很有必要的操作:判断 start+1的值,end-1的值,是否与上一个一样,相同的话,则跳过处理,我一开始就没处理,想偷懒最后保存结果的时候去重即可,但是去重要使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
### 解答:
实现是使用的Python3写的。代码地址在GitHub,可调试:https://github.com/zhangdianlei/LeetCode_python/blob/master/src/c15.py
实现:
```python
if len(nums) < 3:
return []
result = []
nums = sorted(nums)
for index, item in enumerate(nums):
target = -item
start = index + 1
end = len(nums) - 1
if item > 0 or nums[end] < 0:
break
if index > 0 and item == nums[index-1]:
continue
while start < end:
if nums[end] < 0:
break
if nums[start] + nums[end] == target:
temp_list = [nums[index], nums[start], nums[end]]
result.append(temp_list)
while start < end and nums[start] == nums[start+1]:
start = start + 1
while start < end and nums[end] == nums[end-1]:
end = end - 1
start = start + 1
end = end - 1
elif nums[start] + nums[end] < target:
start = start + 1
else:
end = end - 1
return result