LeetCode:3 Sum问题(C++实现)

一、问题描述

Given an array nums of n integers, are there elements abc in nums 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.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],

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

二、解题思路

3 Sum问题可以转化为2 Sum问题(类似4 Sum问题可以转化为3 Sum)。这类问题最优解的时间复杂度为O(n*(k-1))。即:2 Sum最优复杂度为O(n),3 Sum最优为O(n * n)。

对于2 Sum有两种解题思路:

①先排序,然后用left和right分别指向开头和结尾,之后计算和。同时根据情况移动即可。感觉这种方法像是快排。时间复杂度是:O(NlogN);

②就是利用unordered_map(底层为哈希表),查找一个数为线性时间,这样的话一次遍历即可找到,所以复杂度就降低为:O(n)。

因此,对于3 Sum也有两种方法。

基于①:首先要进行一次排序,然后就转为2 Sum问题,复杂度:O(N*NlogN)

基于②:先进行一次排序,然后也是2 Sum问题,复杂度:O(N * N).

三、代码实现(C++)

基于①:首先要进行一次排序,然后就转为2 Sum问题,复杂度:O(N*NlogN)
#include <vector>
#include <algorithm>
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());
        //因为题目中要求和为0,而且此时已经排过序,因此第一个元素必须要<0
        for(int i=0; i<nums.size() && nums[i]<=0; i++){
            int target = -nums[i];
            
            int left = i+1;
            int right = nums.size()-1;
            while(left < right){
                int sum = nums[left] + nums[right];
                if(sum < target){
                    left++;
                } else if(sum > target){
                    right--;
                } else{
                    result.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--;
                }
            }
            //第一次写时这里用nums[i++] == nums[i],得出的结果不对。原因就是忽略了++特性
            //这里i++,后面由来了个i++,因此导致得不出正确的结果
            while( (i+1)<nums.size() && nums[i+1] == nums[i] ) i++;
        }
        return result;
    }
};
基于②:先进行一次排序,然后也是2 Sum问题,复杂度:O(N * N).
#include <unordered_map>
#include <algorithm>
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        unordered_map<int, int> map;
        if(nums.size() < 3){
            return result;
        }
        sort(nums.begin(),nums.end());
        
        for(int i=0; i<(nums.size()-1) && nums[i]<=0; i++){
            int target = -nums[i];//从下面开始就是2 Sum的问题了
            
            for(int j=(i+1); j<nums.size(); j++){
                int other = target - nums[j];
                if(map.find(other) != map.end()){
                    //加这个判断是防止[-1,0,1],[-1,1,0]情况,因为vector是有序的
                    if(nums[j]<=nums[map[other]]){
					    result.push_back({nums[i],nums[j],nums[map[other]]});
				    }
                }else {
                    //去掉重复的
                    if(map.find(nums[j]) == map.end()) map[nums[j]] = j;
                }
            }
            //防止第一个数据重复,即:[-1,-1,2],[-1,-1,2].因为样例可能是[-1,0,1,-1,-1,2]
            while( (i+1)<nums.size() && nums[i+1] == nums[i] ) i++;
        }
        return result;
    }
};

说明,对于这个方法。有个测试用例一直不过:

Input:[-1,0,1]

Output:[]

Expected:[[-1,0,1]]

我也一步一步的跟下去,发现是这样的:初始当i=0,j=1时,此时map为空,因此找不到1.所以,将0添加到map中(此时map为<0,1>);当i=0,j=2时,本来可以用map中拿到0,但是我在代码21行加了判断:if(nums[j]<=nums[map[other]]),因此导致找不到。这也是个遗留问题吧。希望后面可以解决!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章