3sum问题解决方案


题目描述:

Given an array S of n integers, are there elements a, b, c 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.



解决思路:

方法一:暴力解决,写三个循环。好傻……时间复杂度是O(N^3)

方法二:之前有一个2sum的题,是给定一个和以及一个数组,让从数组里头找到两个数字,使其和为给定的和。那道题用了hash,直接把时间复杂度降到了O(N)。所以我们想一想这道题其实也可以用到hash。

             将数组放到hash表中,因为本题还要求输出结果不要有重复的三元组,所以我们可以利用hash表去重:在放入每一个数组元素前判断一下该数组元素是否在hash表中存在(O(N)),不存在则放入,存在则跳过这个元素判断下一个数组元素。

            在hash表中依次遍历,从第一个元素开始,遍历之后的元素中是否有两个元素的和为该元素的相反数(O(N)),因为要遍历一遍hash表,所以是在O(N)的情况下继续O(N),即总体的时间复杂度为O(N^2)


方法三:不用hash

             我们先对数组进行排序(没有思路就排序……从小到大排序),为O(NlogN)的时间复杂度。还是要先从第一个元素开始作最外层循环,之后在它之后的元素中找到两个元素的和为这个元素的相反数(设为a)。

             这里我们就可以利用到排序后的有序数组了,使用两个指针分别指向剩下的元素的两端,如果指针指向的两个数之和小于a,则把左边的指针向右移;若指针指向的两个数之和大于a,则把右边的指针向左移。这样利用了排序后的数组带来的便利性,即如果两数之和小于a,则要把数据往大了找,但同时为了不遗漏一定要按照一定规律地找,所以这个排序和动一个数就保证了有规律,往大了找代表这较小的元素太小所以它需要往大了调,所以左边的指针右移。这样我们可以在O(N)找出剩下的元素中的两数和为a的元素为哪些。为了去重也要作一些操作在移动指针的时候。

             所以在最外层循环O(N)里头又有O(N),故而总的时间复杂度为O(N^2)

            代码:

class Solution {
public:    
    /**
     * @param numbers : Give an array numbers of n integer
     * @return : Find all unique triplets in the array which gives the sum of zero.
     */
    vector<vector<int> > threeSum(vector<int> &nums) {
        vector<vector<int> > result;
        
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            // two sum;
            int start = i + 1, end = nums.size() - 1;
            int target = -nums[i];
            while (start < end) {
                if (start > i + 1 && nums[start - 1] == nums[start]) {
                    start++;
                    continue;
                }
                if (nums[start] + nums[end] < target) {
                    start++;
                } else if (nums[start] + nums[end] > target) {
                    end--;
                } else {
                    vector<int> triple;
                    triple.push_back(nums[i]);
                    triple.push_back(nums[start]);
                    triple.push_back(nums[end]);
                    result.push_back(triple);
                    start++;
                }
            }
        }
        
        return result;
    }
};

这里推荐一下ksum问题的总结式的解决思路:

求和问题总结(leetcode 2Sum, 3Sum, 4Sum, K Sum)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值