题目来源
问题描述
给定一个包含 n 个整数的数组 S,是否存在属于 S 的三个元素 a,b,c 使得 a + b + c = 0 ?找出所有不重复的三个元素组合使三个数的和为零。
注意:结果不能包括重复的三个数的组合。
例如, 给定数组 S = [-1, 0, 1, 2, -1, -4],
一个结果集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
解决方案
python
该方法基于三重遍历,时间复杂度为 O(n3) O ( n 3 ) ,运行超时。
class Solution:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res=[]
isin=[]
for i in range(len(nums)):
for j in range(i+1,len(nums)):
#注意起始遍历位置,代码已经在坐标上去重,但数据还可能重复,故用isin数组辅助记录
p=-(nums[i]+nums[j])
if p in nums[j+1:]:
t=[nums[i], nums[j], p]
t.sort()
s="%d%d%d" % (t[0],t[1],t[2])
if s not in isin:
res.append(t)
isin.append(s)
return res
Java
基于原数组的排序,先固定一个数,然后使用两边夹的办法。该算法时间复杂度为 O(n2) O ( n 2 ) 。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> arrayList=new ArrayList<>();
Arrays.sort(nums);//排序
int i,j,k,res;
for(i=0;i<nums.length-2;i++) {//规定的数从第一个位置开始到倒数第三个
if(i>0 && nums[i]==nums[i-1])//数组已经有序,避免nums[i]重复
continue;
j=i+1;
k=nums.length-1;
while (j<k) {//两头夹
if(j>i+1 && nums[j]==nums[j-1]) {//已经访问过的值不再访问
j++;
continue;
}
if(k<nums.length-1 && nums[k]==nums[k+1]) {//已经访问过的值不再访问
k--;
continue;
}
res=nums[i]+nums[j]+nums[k];
if (res<0)
j++;
else if (res>0)
k--;
else {
arrayList.add(Arrays.asList(nums[i],nums[j],nums[k]));
j++;
k--;
}
}
}
return arrayList;
}
}
至于是否超时,除了算法的作用外,编程语言也有影响,如下本算法的python代码实现运行超时。
class Solution:
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res=[]
nums.sort()
for i in range(len(nums)-2):
if i>0 and nums[i]==nums[i-1]:
continue
j=i+1
k=len(nums)-1
while j<k:
if j>i+1 and nums[j]==nums[j-1]:
j+=1
continue
if k<len(nums)-1 and nums[k]==nums[k+1]:
k-=1
continue
s=nums[i] + nums[j] + nums[k]
if s<0:
j+=1
elif s>0:
k-=1
else:
res.append([nums[i],nums[j],nums[k]])
j+=1
k-=1
return res