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]]),因此導致找不到。這也是個遺留問題吧。希望後面可以解決!!!

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