leetcode hot 100-15. 三数之和

15. 三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]

思路:双指针法

思路参考:https://leetcode-cn.com/problems/3sum/solution/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/

总体思路:对于每个数nums[i], 判断它后面是否存在两个数,使得这两个数加上 nums[i] 的和刚好为0
具体实现过程:
先对nums[]数组进行排序
遍历nums[]数组,对于每个数nums[i], 判断它后面是否存在两个数,使得这两个数加上 nums[i] 之后的和刚好为0

如果nums[i]大于0, 因为nums[ ]数组已经按从小到大排序,所以可以断定nums[i]后面不存在两个数能使的三数之和等于0,且nums[i]后面的元素也不符合条件,不需要继续枚举下去,直接 break 跳出循环。

如果nums[i] == nums[i-1],无论nums[i]是否存在合法解,它的所有合法情况都已经在nums[i-1]被枚举过了,所以应该跳过。

开始寻找符合条件的解:让左指针等于i+1, 右指针等于len - 1

  • 如果三数之和大于0, 右指针应该左移使得和能够减小一些
  • 如果三数之和小于0, 左指针应该右移使得总和能够增大一些
  • 如果三数之和等于0, 说明找到了一个合法的解,记录下来,此时,如果nums[left] = nums[left+1], left应该后移一位,因为nums[i]已经固定了,如果nums[left+1]也和上一个解一样的话,则剩下的一个数肯定也是一样的,则此次统计的一定是一个重复解,同理右指针
 1 class Solution {
 2     public List<List<Integer>> threeSum(int[] nums) {
 3 
 4         List<List<Integer>> res = new ArrayList<>();
 5         if(nums == null || nums.length == 0){
 6             return res;
 7         }
 8 
 9         Arrays.sort(nums);  // 排序
10 
11         int len = nums.length;
12         for(int i = 0; i < len; i++){
13             if(nums[i] > 0){
14                 break;
15             }
16             if(i > 0 && nums[i] == nums[i-1]){  // 去重
17                 continue;
18             }
19             int left = i + 1, right = len - 1;
20             while(left < right){
21                 int sum = nums[i] + nums[left] + nums[right];
22                 if(sum == 0){ //如果三数之和等于0, 说明找到了一个合法的解,记录下来,
23                     res.add(Arrays.asList(nums[i], nums[left], nums[right]));
24                     while(left < right && nums[left] == nums[left + 1]){  // 跳过重复元素
25                         left++;
26                     }
27                     while(left < right && nums[right] == nums[right-1]){    // 跳过重复元素
28                         right--;
29                     }
30                     left++;
31                     right--;
32                 }else if(sum > 0){ //如果三数之和大于0, 右指针应该左移使得和能够减小一些
33                     right--;
34                 }else{  //如果三数之和小于0, 左指针应该右移使得总和能够增大一些
35                     left++;
36                 }
37             }
38         }
39         return res;
40     }
41 }

leetcode 执行用时:23 ms > 84.00%, 内存消耗:42 MB > 97.62%

复杂度分析:

时间复杂度:O(n2)。排序的时间复杂度为O(nlogn)。接下来循环遍历每个nums[i], 使用双指针法遍历这个nums[i]后面的所有元素是否存在符合条件的解,双指针的复杂度为O(n), 所以总的时间复杂度为O(n2)。

空间复杂度:O(1)。除了存储结果的列表,其他的变量空间都是常数级别的, 所以空间复杂度为O(1)。

原文地址:https://www.cnblogs.com/hi3254014978/p/13945527.html