Leetcode15:3Sum
题目描述:3Sum
简而言之,找出数组中和为0的三个数,且不能有重复。
可以使用双指针的方法降低多重循环的时间复杂度。
解题过程
最简单的方法自然是暴力循环,先确定一个再确定后两个。但是该方法复杂度太高,而且无法通过,时间超过限制。
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> resultList=new ArrayList<List<Integer>>();
if (nums.length<3) {
return resultList;
}
for (int i = 0; i < nums.length; i++) {
int temp=0-nums[i];
for (int j = i+1; j < nums.length; j++) {
for (int j2 = j+1; j2 < nums.length; j2++) {
if (nums[j]+nums[j2]==temp) {
List<Integer>tempList=new ArrayList<Integer>();
tempList.add(nums[i]);
tempList.add(nums[j]);
tempList.add(nums[j2]);
Collections.sort(tempList); //去重
if (!resultList.contains(tempList)) { //去重
resultList.add(tempList);
}
}
}
}
}
return resultList;
}
所以可以对算法进行优化:
- 对数组进行排序
- 固定一个数nums[i],再用左右指针指向剩下的数的两端,即当前固定数的左边一个和nums数组的最后一个,分别为nums[left]和nums[right]。
- 如果num[i]+nums[left]+nums[right]==0,则添入到结果列表中。
一些限制:
- 因为数组已经排好序,所以如果当前nums[i]>0,则三个数的和不可能等于0,结束循环。
- 如果当前nums[i]==nums[i-1],说明可能会产生与之前重复的结果,应该跳过。
- 当找到三数之和等于0时,如果nums[left]==nums[left+1],说明可能会产生与之前重复的结果,应该将左指针右移,直接移到与nums[left]不同的数。
- 当找到三数之和等于0时,如果nums[right]==nums[right-1],说明可能会产生与之前重复的结果,应该将右指针左移,直接移到与nums[right]不同的数。
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> resultList=new ArrayList<List<Integer>>();
if (nums.length<3) {
return resultList;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i]>0) {
break;
}
if (i>0&&nums[i-1]==nums[i]) {
continue;
}
int left=i+1;
int right=nums.length-1;
while(left<right) {
if(nums[i]+nums[left]+nums[right]==0) {
List<Integer>tempList=new ArrayList<Integer>();
resultList.add(Arrays.asList(nums[i],nums[left],nums[right]));
while (left<right&&nums[left]==nums[left+1]) {
left++;
}
while (left<right&&nums[right]==nums[right-1]) {
right--;
}
left++;
right--;
}
else if (nums[i]+nums[left]+nums[right]<0) {
left++;
}
else if (nums[i]+nums[left]+nums[right]>0) {
right--;
}
}
}
return resultList;
}
这样优化后,就可以降低时间复杂度。
如此,可以看出,当要使用多重循环时,可以考虑使用双指针的方法减少时间复杂度。