LeetCode No15. 三数之和
题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
思路
首先第一反应就是暴力,三重循环,然后时间复杂度O(n^3),按照题目给的数据范围应该不会超时,然而写完之后提交直接超时。那就优化呗,看题目的样例,似乎是对返回的顺序什么的没有要求,那么就想到排序,然后对排序后的数组去取值,这样就想到如下两种方法:
二分查找
既然三重循环不行,那我减少一层循环试试,先用两层循环找到两个数a、b,因为需要三个数之和为0,那么另外一个数必然是 -(a+b),因为数组已经有序,找这个数就可以用二分,时间复杂度为O(n^2*log(n))。
双指针
既然已经能减少一层循环,那么是否还能再减少一层循环呢?显然是可以的,用一层循环遍历出第一个数a,对于剩下的两个数,由于数组已经排好序了,只需要用两个指针去从数组的头和尾取数,只要找到的两个数和a相加等0即可。
AC代码
二分查找
点击查看代码
class Solution {
private int b_search(int[] nums, int low, int high, int num) {
while( low <= high ) {
int mid = ( low + high ) / 2;
if( nums[mid] == num ) {
return mid;
} else if( nums[mid] > num ){
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int len = nums.length;
if( len < 3 ){
return res;
}
Arrays.sort(nums);
for(int i=0; i<len; i++) {
if( i!=0 && nums[i-1]==nums[i] ) {
continue;
}
int last = i+1;
while( last < len-1 ) {
if( last > i+1 && nums[last-1]==nums[last] ) {
last ++;
continue;
}
int num = nums[i] + nums[last];
if( num > 0 ) {
break;
}
int ind = b_search(nums, last+1, len-1, num*-1);
if( ind!=-1 ) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[last]);
list.add(nums[ind]);
res.add(list);
}
last ++;
}
}
return res;
}
}
双指针
点击查看代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int lasta = -100005;
int n = nums.length;
Arrays.sort(nums);
for(int i=0; i<n; i++) {
int a = nums[i];
if( lasta==a ) {
continue;
}
lasta = a;
int low = i+1;
int high = n - 1;
while( low < high ) {
int sum = a + nums[low] + nums[high];
if( sum>0 ) {
high --;
} else if( sum < 0 ) {
low ++;
} else {
List<Integer> list = new ArrayList<>();
list.add(a);
list.add(nums[low]);
list.add(nums[high]);
res.add(list);
while(low<high && nums[low]==nums[low+1]) {
low ++;
}
while(low<high && nums[high]==nums[high-1]) {
high --;
}
low ++;
high --;
}
}
}
return res;
}
}
低调做人,高调做事。