给定一个包含 n 个整数的数组 nums
,判断 nums
中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
例如给定nums = [-1,0,1,-1,2,-4],
满足条件的三元组为[[-1,0,1],[-1,-1,2]]
我的思路:
思路一:刚开始,我是想着直接用三个指针i,j,k进行遍历,三数之和等于0,且不在lists中则假如lists。代码如下:
//可行,但是时间超时了
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists = new ArrayList<List<Integer>>();
for(int i = 0;i<nums.length;i++) {
for(int j = i+1;j<nums.length;j++) {
int tmp = nums[i]+nums[j];
for(int k = j+1;k<nums.length;k++) {
if(nums[k] + tmp == 0 && k !=i && k != j) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
boolean isDifferent = true;
for(int m = 0;m<lists.size();m++) {
if(lists.get(m).containsAll(list)
&&list.containsAll(lists.get(m)))
isDifferent = false;
}
if(isDifferent)
lists.add(list);
}
}
}
}
return lists;
}
思路二:以上代码超时了,于是想想能不能对数组先进行排序,然后分三种情况:两个非负数一个负数、两个负数一个正数、三个零。修改后的代码运行总算是没有超时了,但是依旧很慢。如果各位有什么好的方法一定要告诉我哟!
代码:
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> lists = new ArrayList<List<Integer>>();
if(nums.length<3)return lists;
Arrays.sort(nums);
int mid = -1;
//找到第一个大于0的数
for(int i = 0;i<nums.length;i++) {
if(nums[i]>=0) {
mid = i;
break;
}
}
//没有负数但有三个0
if(mid == 0 && nums[mid+1] == 0 && nums[mid+2] == 0) {
List<Integer>list = new ArrayList<>();
list.add(0);
list.add(0);
list.add(0);
lists.add(list);
return lists;
}else if (mid == 0) {
//没有负数且没有三个0,则不存在满足情况的解
return lists;
}
//有负数的情况
//全是负数
if(mid == -1)return lists;
//一个负数两个非负数
if(nums.length-mid>=2) {
for(int i = 0;i<mid;i++) {
//最大的两个加起来还没负数大,不可能存在
if(nums[i]+nums[nums.length-1]+nums[nums.length-2]<0) continue;
//最小负数的和最小两个正数加起来大于0,不可能存在了
if(nums[i]+nums[mid]+nums[mid+1]>0)break;
if(i-1>=0&&nums[i] == nums[i-1])continue;
for(int j = mid;j<nums.length-1;j++) {
if(nums[j] == nums[j-1])continue; //相等,不需要管,因为必会存在于list中了
for(int k = j+1;k<nums.length;k++) {
if(nums[i]+nums[j]+nums[k] == 0) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
lists.add(list);
break;
}
}
}
}
}
int tMid = mid;
while(tMid<nums.length&&nums[tMid] == 0)tMid++;
if(mid>1) {
//一个正数两个负数
for(int i = tMid;i<nums.length;i++) {
//和最小的负数加起来都大于0
if(nums[i]+nums[0]+nums[1]>0)break;
//和最大的两个负数加起来都小于0
if(nums[i]+nums[mid-1]+nums[mid-2]<0)continue;
if(nums[i] == nums[i-1])continue;
for(int j = 0;j<mid-1;j++) {
if(j-1>=0&&nums[j-1] == nums[j]) continue;
for(int k = j+1;k<mid;k++) {
if(nums[i]+nums[j]+nums[k] == 0) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
lists.add(list);
break;
}
}
}
}
}
if(nums.length-mid>=3&&nums[mid] == 0 && nums[mid+1] == 0 && nums[mid+2] == 0) {
List<Integer> list = new ArrayList<>();
list.add(0);
list.add(0);
list.add(0);
lists.add(list);
}
return lists;
}