LeetCode-数组三数之和

Posted Flix

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode-数组三数之和相关的知识,希望对你有一定的参考价值。

题目描述

给你一个包含 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/

思路1

很容易想到的方法,先找到两个数,然后固定住这两个数去寻找满足条件的第三个数,为了加快寻找速度可以通过哈希表来寻找。代码如下:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        if(nums.empty())
            return ans;

        map<int, int> hashTabel;
        for(int i=0; i<nums.size(); i++)
            hashTabel[nums[i]] = i;
        
        for(int i=0; i<nums.size(); i++){
            for(int j=i; j<nums.size(); j++){
                int complement = -nums[i]-nums[j];
                if(i!=j && hashTabel.find(complement)!=hashTabel.end() 
                && hashTabel[complement]!=i && hashTabel[complement]!=j){
                    ans.push_back({nums[i], nums[j], nums[hashTabel[complement]]});
                }
            }
        }
        // 使用set去重
        for(int i=0; i<ans.size(); i++)
            sort(ans[i].begin(), ans[i].end());
        set<vector<int>> s(ans.begin(), ans.end());
        ans.assign(s.begin(), s.end());

        return ans;
    }
};

这样的话得到的结果里面包含重复的三元组,所以使用set去重后返回。

  • 时间复杂度O(n^2)
    包含一个双层循环。
  • 空间复杂度O(n)
    使用了哈希表。

该方法由于超时未通过。

思路2

假如是在排序数组中找和为target的两个数,则我们可以使用两个指针,一个指针left从左到右遍历,另一个指针right从右到左遍历。如果两个指针指向的两个数字之和小于target,则left++;如果大于target,则right--。直至找到target或者left>=right。代码如下:

//array = [1,2,3,4,5,6,7,8,9]; array is sorted in a increasing order
//target = 10;
int len = array.size();
int p1 = 0, p2 = len - 1; //p1 points to the start of the array and p2 points to the end
//the search stops when the two pointers meet each other
while(p1 < p2){
    if(array[p1] + array[p2] < target){
        p1++;
    }else if(array[p1] + array[p2] == target){
        cout << p1 << p2 << endl;
        p1++,p2--;
    }else{
        p2--;
    }

}

对于这个问题,我们可以用类似的思想。首先,将数组排序,然后从头开始遍历数组,当遍历到nums[i]时,我们从i+1开始往后利用上面的方法寻找两个值使得两个值之和为-nums[i]即可。
还有一个问题就是去重,例如[-1,-1,0,0,1,1],算法结果中包含两个[-1,0,1]。解决这个问题的办法是:当移动指针的时候,要移动一个位置,这个位置和指针移动前指向的值不同,而不是简单地将指针移动一步。代码如下:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ans;
        if(nums.empty() || nums.size()<3)
            return ans;

        sort(nums.begin(), nums.end());

        for(int i=0; i<nums.size(); i++){
            if(i==0 || (i>0&&nums[i]!=nums[i-1])){
                int left = i+1;
                int right = nums.size()-1;
                while(left<right){
                    int s = nums[i]+nums[left]+nums[right];
                    if(s<0){
                        left++;
                    }else if(s>0) {
                        right--;
                    }else{
                        ans.push_back({nums[i], nums[left], nums[right]});
                        while(left<right && nums[left]==nums[left+1]){  // 找到下一个不相等的下标,为了去重
                            left++;
                        }
                        while(left<right && nums[right]==nums[right-1]){ // 找到下一个不相等的下标,为了去重
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return ans;
    }
};
  • 时间复杂度O(n^2)
  • 空间复杂度O(n)

总结

双指针的应用场景:去重、找满足条件的数字、链表相关问题等。

参考

1、https://leetcode-cn.com/problems/3sum/solution/xiang-xi-jie-shi-shuang-zhi-zhen-jie-jue-san-shu-z/
2、https://leetcode-cn.com/problems/3sum/solution/pai-xu-shuang-zhi-zhen-zhu-xing-jie-shi-python3-by/

以上是关于LeetCode-数组三数之和的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode1两数之和15三数之和

LeetCode1两数之和15三数之和

[leetcode数组系列]2三数之和

LeetCode-数组三数之和

LeetCode5.三数之和(C++,Python)

leetcode 15.三数之和