15.3Sum

来源:互联网 发布:php yaf导出excel表格 编辑:程序博客网 时间:2024/06/06 07:01

Problem:

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]
]


这题和第一题TwoSum是比较类似的一道题,这次是寻找数组中任意三个数的和为0的组合,不能重复。我一开始的想法是用TwoSum的函数,然后先是用target=0减去nums数组中的一个数,然后再用TwoSum函数找出剩下的数中符合两个数加起来的和等于target,然后排序就完成了,后来用代码实现了这个想法:


Code:

class Solution {public:    vector<vector<int>> threeSum(vector<int>& nums) {        vector<vector<int>> result;        if (nums.size() < 3) {            return result;        }        const int target = 0;                for (int i = 0; i < nums.size(); i++) {            int gap = target - nums[i];            vector<int> tmp = twoSum(nums, gap, i);            if (tmp.size() > 0) {                tmp.push_back(nums[i]);                sort(tmp.begin(), tmp.end());                if (result.size() == 0) {                    result.push_back(tmp);                }                for (int j = 0; j < result.size(); j++) {                    if (tmp == result[j]) {                        break;                    }                    if (j == result.size() - 1) {                        result.push_back(tmp);                    }                }            }                    }        return result;    }        vector<int> twoSum(vector<int>& nums, int target, int now) {        unordered_map<int, int> mapping;        vector<int> result;                for (int i = 0; i < nums.size(); i++) {            if (now == i) {                continue;            }            mapping[nums[i]] = i;        }        for (int i = 0; i < nums.size(); i++) {            if (now == i) {                continue;            }            const int gap = target - nums[i];            if (mapping.find(gap) != mapping.end() && mapping[gap] != i) {                result.push_back(nums[i]);                result.push_back(nums[mapping[gap]]);                break;            }        }        return result;            }        };


遗憾的是Wrong Answer。经过样例的分析,TwoSum中的数组是要没有重复的。而3Sum给的数组是有大量的重复元素的。所以这样会导致不跳过重复元素,进行了错误的判断。然后我去参考了别人的想法,学习到了一种夹逼的方法,代码如下,算法的思想都写在注释里了。


Code2:(LeetCode运行109ms)

class Solution {public:    vector<vector<int>> threeSum(vector<int>& nums) {        vector< vector<int> > result;        if (nums.size() < 3) {            return result;        }        //夹逼法的前提是要排序,因为在进行前后比较需要判断是要哪一个下标往前,哪一个往后。        sort(nums.begin(), nums.end());                auto last = nums.end();        //attention: last - 2, 因为j+1会让下标越界。        for (auto i = nums.begin(); i < last - 2; i++) {            auto j = i + 1;            //跳过i迭代器表示的值重复的元素            if (i > nums.begin() && *i == *(i - 1)) {                continue;            }            auto k = last - 1;            //i,j,k表示三个数的迭代器,判断他们的和是否为0,固定i,如果比0大则表示k太大,k--,否则就是j太小,j++.            while(j < k) {                if (*i + *j + *k < 0) {                    j++;                    while(*j == *(j - 1) && j < k) {                        j++; //跳过重复的元素                    }                } else if (*i + *j + *k > 0) {                    k--;                    while(*k == *(k + 1) && j < k) {                        k--;                    }                } else {                    result.push_back( {*i, *j, *k} );                    //继续搜索下去一直到j<k                    j++;                    k--;                    while(*j == *(j - 1) && *k == *(k + 1) && j < k) {                        j++;                    }                }            }        }        return result;    }};


如果有更好的算法,希望大家和我分享!

原创粉丝点击