题目传送门
方法一:使用双指针+排序
先排重num【i】版本
由于当前还没有计算过 nums[i]
如nums【-4,-1,-1,0,1,2】
若直接排重就会错过如 [-1,-1,2] 这样的结果。
因此当前排重只需要if(i > 0 && nums[i] == nums[i-1]){ continue; }
这样就不会错过
如 [-1,-1,2] 这样的结果。因为前置判断后会计算(重复元素的前列)
当num[i] 等于第一个 -1 的结果
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
int n = nums.length;
Arrays.sort(nums);
for(int i = 0; i < n; i++){
if(nums[i] > 0)break;
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
int target = -nums[i];
int left = i + 1;
int right = n-1;
while(left < right){
if(nums[left] + nums[right] == target){
ret.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[left] + nums[right] < target){
left++;
}else{
right--;
}
}
}
return ret;
}
}
算法思维导图
后排重nums【i】版本
如nums【-4,-1,-1,0,1,2】
由于此时已经把当前 num[i] (重复元素的前列)计算过了
此时就已经加上如 [-1,-1,2] 这样的结果
因此直接while循环排重 num[i] 最后由于for循环还有i++
成功排重 nums【i】
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
int n = nums.length;
Arrays.sort(nums);
for(int i = 0; i < n; i++){
if(nums[i] > 0)break;
int target = -nums[i];
int left = i + 1;
int right = n-1;
while(left < right){
if(nums[left] + nums[right] == target){
ret.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[left] + nums[right] < target){
left++;
}else{
right--;
}
}
while(i < n-3 && nums[i] == nums[i+1]){
i++;
}
}
return ret;
}
}
算法思维导图
复杂度分析:
时间复杂度:O(n log n)
- 排序:O(n log n)
- 外层循环 + 双指针扫描:O(n) × O(n) = O(n²)
空间复杂度(O(log n))
该算法的空间复杂度为 O(log n),主要来源于排序过程中的递归调用栈空间。结果列表的空间通常不计入复杂度,因为它取决于输入的具体情况(解的数量),而非算法本身的实现。