3数之和 3Sum

本文解析了经典的三数之和问题,通过排序与双指针技巧实现高效求解,避免重复答案的同时达到O(n^2)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

解决:

① 首先想到暴力破解,O(n^3)的时间复杂度,必然超时。

② 数组排序+双指针 O(n^2) --- 动态规划

第一步,对数组排序。
第二步,
分析1:对于元素 S[i] , 最后的答案可以分为两种,包含 S[i] 的,和不包含 S[i] 的。当包含 S[i] 的情况都找到后,后续就可以不用再考虑 S[i] 。
分析2:对于 S[i] , l = i+1, r = len-1 。若 s[i] + S[l] + S[r] == 0, 则为原问题的一个解。
当 S[i] + S[l] > -S[r] 时,则 r--
当 S[i] + S[l] < -S[r] 时,则 l++
当 S[i] + S[i] = -S[r] 时, 表示是原问题的一个解,则 l++, r--;
第三步,性能优化。同样根据分析1,若 S[i] == S[i+1],可以跳过。

class Solution { //72ms
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums == null || nums.length < 3) return res;
        Arrays.sort(nums);
        int len = nums.length;
        for (int i = 0;i < len - 2 ;i ++ ) {
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            twoSum(nums,i + 1,len - 1,nums[i]);
        }
        return res;
    }
    public void twoSum(int[] nums,int begin,int end,int sum1){
        while(begin < end){
            if(nums[begin] + nums[end] + sum1== 0){
                List<Integer> tmp = new ArrayList<>();
                tmp.add(sum1);
                tmp.add(nums[begin]);
                tmp.add(nums[end]);
                res.add(tmp);
                while(begin < end && nums[begin] == nums[begin + 1]) begin ++;
                while(begin < end && nums[end] == nums[end - 1]) end --;

                begin ++;
                end --;
            }else if(nums[begin] + nums[end] + sum1< 0){
                begin ++;
            }else{
                end --;
            }
        }
    }
}

② 这样写简单点

class Solution { //81ms
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> threeSum(int[] nums) {
        if(nums == null || nums.length < 3) return res;
        Arrays.sort(nums);
        int len = nums.length;
        for (int i = 0;i < len - 2 ;i ++ ) {
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            twoSum(nums,i + 1,len - 1,nums[i]);
        }
        return res;
    }
    public void twoSum(int[] nums,int begin,int end,int sum1){
        while(begin < end){
            if(nums[begin] + nums[end] + sum1== 0){
                res.add(Arrays.asList(sum1,nums[begin],nums[end]));
                while(++ begin < end && nums[begin] == nums[begin - 1]);
                while(-- end > begin && nums[end] == nums[end + 1]);
            }else if(nums[begin] + nums[end] + sum1< 0){
                begin ++;
            }else{
                end --;
            }
        }
    }
}

转载于:https://my.oschina.net/liyurong/blog/1523800

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值