算法第三周 3Sum[medium]

3Sum[medium]


Description

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.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]


Analysis

这道题目是之前所做的Add Two Sum的升级版,这道题目要求寻找数组中和为0的3个数,与之前所做的题目的最大区别是两个数的和题目要求解只有一个,而这道题目明显可能存在这多组解,除此之外,我们不能从题目给的例子可以看出,解得给出存在着一定的顺序,所以我们可以得出本题所需要考虑的三大要点:

  • 求和
  • 排序
  • 去重

一开始,我打算采用类似于Add Two Sum的算法,即多重循环;

for (int i = 0; i < s; i++) {
            for (int j = i + 1; j < s; j++) {
                int sumoftwo = nums[i]+nums[j];
                for (int k = j+1; k < s; k++) {
                    if ((sumoftwo+nums[k]) == 0) {
                        vector<int> temp;
                        temp.push_back(nums[i]);
                        temp.push_back(nums[j]);
                        temp.push_back(nums[k]);
                        sort(temp.begin(), temp.end());
                        result.push_back(temp);
                    }
                }
            }
        }

此题中排序主要利用的是STL中vector的sort函数;
去重利用的是erase函数;

result.erase(unique(result.begin(), result.end()), result.end());

然而不幸的是由于复杂度为O(n*n*n),导致运行超时,那还有什么方法可以降低复杂度,经过思考以及查阅资料
首先,将原数组排序;
以每一个数的相反数作为剩下两个数求和的target(类似于add two number);
设置两个变量h,r 分别从前,从后遍历数组,终止条件即为h >= r;
- 当 nums[h]+nums[r] 大于 target 要缩小其中一个 即r- -;
- 当 nums[h]+nums[r] 大于 target 要增大其中一个 即h++;
- 当 nums[h]+nums[r] 等于 target 即获得满足要求的组合;
接下来的遍历则要避免nums[h],nums[r]的重复;


Solution

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        int s = nums.size();
        for (int i = 0; i < s; i++) {
            if (i >= 1) {
                if (nums[i] == nums[i-1]) continue;
            } 
            int sumoftwo = -nums[i];
            int h = i+1;
            int r = s-1;
            while (h < r) {
                if (nums[h]+nums[r] > sumoftwo) r--;
                else if (nums[h]+nums[r] < sumoftwo) h++;
                else if (nums[h]+nums[r] == sumoftwo) {
                    vector<int> temp;
                    temp.push_back(nums[i]);
                    temp.push_back(nums[h]);
                    temp.push_back(nums[r]);
                    result.push_back(temp);
                    int v1 = nums[h];
                    int v2 = nums[r];
                    while (h < r&&nums[h] == v1) h++;
                    while (h < r&&nums[r] == v2) r--;
                }
            } 

        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值