思路
一开始上来用了暴力法三重循环,发现难点在于去重。
排序后再尝试,发现可以使用双指针法优化。
优化后的算法如下:
- nums 为 null 或者长度小于3 返回空列表
- 排序
- 遍历排序后数组:
如果nums[i] > 0,那么没有sum为0的可能,直接返回。
左指针 left = i+1;
右指针 right = length - 1;
当 left < right 时,执行循环:
* 如果sum == 0:将三个数添加进列表。并做以下循环,left和right移动到下一个不同的值(去重)。
* 如果sum > 0 意味着 右侧的值过大,所以 right 需要左移。
* 如果sum < 0 意味着 左侧的值过小,所以 left 需要右移。
复杂度分析
- 时间复杂度:O(n 2):数组排序是O(N logN) ,遍历数组是O(n),双指针遍历是O(n),总体 O(N logN) + O(n) * O(n)
- 空间复杂度:O(1)
代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if (null == nums) return res;
int length = nums.length;
if (length < 3) return res;
Arrays.sort(nums);
for (int i = 0; i < length; i++) {
if (nums[i] > 0){
return res;
}
if (i > 0 && nums[i] == nums[i-1]){
continue;
}
int left = i + 1;
int right = length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(nums[i]);
integers.add(nums[left]);
integers.add(nums[right]);
res.add(integers);
while (left < right && nums[left + 1] == nums[left]) {
left++;
}
while (left < right && nums[right-1] == nums[right]){
right--;
}
left++;
right--;
}else if (sum > 0){
right--;
}else if (sum < 0){
left++;
}
}
}
return res;
}
}