[C++][Leetcode]Two Sum以及其變形

目錄

 

1.Leetcode 1 兩數之和

2.Leetcode 15 三數之和

3.Leetcode 16 最接近的三數之和

4.Leetcode 18 四數之和

5. Leetcode 454 四數之和II


1.Leetcode 1 兩數之和

  • 題目描述
給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。

你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。

示例:

給定 nums = [2, 7, 11, 15], target = 9

因爲 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/two-sum
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
  • 思路分析
    • 使用map做hashmap,使用額外的空間(n),一趟遍歷進行判斷。如果不在map,就加入,在map就計數。
    • 因爲需要返回下標,所以用sort+雙指針不方便。
  • 代碼設計
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {

        vector<int>res;
        int n=nums.size();
        
        map<int,int>hashmap;
        
        for(int i=0;i<n;++i)
        {
            if(hashmap.find(target-nums[i])!=hashmap.end()&&hashmap[target-nums[i]]!=i)//存在
            {
                res.push_back(i);
                res.push_back(hashmap[target-nums[i]]);
                break;
            }
            else
                hashmap[nums[i]]=i;
        }
        return res;
        
    }
};

 

2.Leetcode 15 三數之和

  • 題目描述
給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。



示例:

給定數組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合爲:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/3sum
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。



  • 思路分析
    •  第一種思路,時間複雜度爲N*2,空間複雜度爲N。對於三個數,我們分成兩部分,固定一個數,然後使用Two Sum的思路,去判斷這個數的負數是不是有Two sum的解。Two Sum的求解辦法是使用一個map,進行O(n)的遍歷,邊遍歷邊放進map中。但是需要考慮到數組中有重複元素,所以結果集合裏面也有重複,所以需要判斷一下,如果結果集合中已經有這個解了,就不再加入。
    • 第二種思路,時間複雜度爲NlogN。我們採用快速排序的庫函數,得到排序後的數組。我們也是像第一種思路一樣,固定一個數,然後去尋找兩個數之後是該數的負數。因爲現在是排序數組,所以我們可以採用雙指針遍歷查找,爲了避免重複組合,我們需要將兩個指針設置到一個範圍,比如都在目標數的右側且相互不相遇。如果不加約束,那麼會出現重複的組合:比如a[i]+a[j]=target;a[j]+a[i]=target。除此之外,我們還有兩個策略去避免重複:
      • 對於固定的數,這個數不可以重複選取,重複的話就跳過。
      • 對於兩個指針的遍歷的過程,遇到解之後,接着尋找其他解的時候,需要跳過之前解的重複值。
  • 代碼設計
//超時代碼
class Solution {
public:
    void twoSum(vector<int>&nums,int target,int k,vector<vector<int>>&res)
    {
        map<int,int>m;
        for(int i=0;i<nums.size();++i)
        {
            if(m.find(target-nums[i])!=m.end()&&m[target-nums[i]]!=i&&i!=k&&m[target-nums[i]]!=k)
            {
                vector<int>pos;
                pos.push_back(nums[i]);
                pos.push_back(nums[m[target-nums[i]]]);
                pos.push_back(nums[k]);
                sort(pos.begin(),pos.end());
                //在結果集合裏面找答案
                vector<vector<int> > ::iterator it=find(res.begin(),res.end(),pos);
                if(it==res.end())//不在裏面
                    res.push_back(pos);
            }
            else
                m[nums[i]]=i;
        }
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
       vector< vector<int> >res;

        int n=nums.size();
        
        for(int i=0;i<n;++i)
        {
            twoSum(nums,-nums[i],i,res);
        }
        return res;
    }
};
//pass
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
       vector< vector<int> >res;
       //排序NlogN
        sort(nums.begin(),nums.end());
        int n=nums.size();
        
        for(int i=0;i<n-2;++i)
        {
            if(i>0&&nums[i]==nums[i-1])//枚舉元素的時候需要跳過重複元素 
                continue;
            int target=-nums[i];

            //雙指針
            int low=i+1;
            int high=n-1;
            while(low<high)
            {
                if(nums[low]+nums[high]<target)
                    ++low;
                else if(nums[low]+nums[high]>target)
                    high--;
                else
                {
                    vector<int>pos;
                    pos.push_back(nums[i]);
                    pos.push_back(nums[low]);
                    pos.push_back(nums[high]);
                    res.push_back(pos);
                

                    //找完之後 可能還有其他組合 所以跳過重複元素 接着遍歷查找
                    ++low;
                    while(low<high&&nums[low]==nums[low-1])
                        ++low;
                    --high;
                    while(low<high&&nums[high]==nums[high+1])
                        --high;
                }
            }
        }
        return res;
    }
};

 

3.Leetcode 16 最接近的三數之和

  • 題目描述
給定一個包括 n 個整數的數組 nums 和 一個目標值 target。找出 nums 中的三個整數,使得它們的和與 target 最接近。返回這三個數的和。假定每組輸入只存在唯一答案。

例如,給定數組 nums = [-1,2,1,-4], 和 target = 1.

與 target 最接近的三個數的和爲 2. (-1 + 2 + 1 = 2).

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/3sum-closest
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
  • 思路分析

三數之和的變形問題,排序+雙指針。

  • 代碼設計
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n=nums.size();
        sort(nums.begin(),nums.end());
        int cur=0;
        int res=nums[0]+nums[1]+nums[2];
        for(int i=0;i<n-2;++i)
        {
            int low=i+1;
            int high=n-1;
            while(low<high)
            {
                cur=nums[i]+nums[low]+nums[high];
                if(abs(cur-target)<abs(res-target))
                    res=cur;
                if(nums[low]+nums[high]+nums[i]<target)
                    ++low;
                else if(nums[low]+nums[high]+nums[i]>target)
                    --high;
                else
                    return target;
            }
        }
        return res;
        
    }
};

4.Leetcode 18 四數之和

  • 題目描述
給定一個包含 n 個整數的數組 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。

注意:

答案中不可以包含重複的四元組。

示例:

給定數組 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

滿足要求的四元組集合爲:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/4sum
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
  • 思路分析

結合三數之和的方法,首先將前兩個數進行枚舉,然後使用雙指針進行查找後面兩個數。時間複雜度爲O(n^2logn)。在枚舉過程中要注意去重。需要考慮就是在每一個數考慮的時候不要重複,四個數之間可以有重複的數,比如都是輸入[0,0,0,0] target=0,那麼結果集合爲[[0,0,0,0]].

  • 代碼設計
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        //先排序
        sort(nums.begin(),nums.end());
        int n=nums.size();
        vector<vector<int>>res;
        for(int i=0;i<n-3;++i)
        {
            if(i>0&&nums[i]==nums[i-1])
                continue;
            for(int j=i+1;j<n-2;++j)
            {
                if(j>i+1&&nums[j]==nums[j-1])//和第一個數和第二個數是可以相等的 只要第二個數不要取重複值就可以
                    continue;
                int ans=nums[i]+nums[j];
                int low=j+1;
                int high=n-1;
                while(low<high)
                {
                    if(nums[low]+nums[high]+ans<target)
                        ++low;
                    else if(nums[low]+nums[high]+ans>target)
                        --high;
                    else
                    {
                        vector<int>pos;
                        pos.push_back(nums[i]);
                        pos.push_back(nums[j]);
                        pos.push_back(nums[low]);
                        pos.push_back(nums[high]);
                        res.push_back(pos);
                        ++low;
                        while(low<high&&nums[low]==nums[low-1])
                            ++low;
                        --high;
                        while(low<high&&nums[high]==nums[high+1])
                            --high;
                    }
                }
            }
        }

        return res;        
    }
};

5. Leetcode 454 四數之和II

  • 題目描述
給定四個包含整數的數組列表 A , B , C , D ,計算有多少個元組 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

爲了使問題簡單化,所有的 A, B, C, D 具有相同的長度 N,且 0 ≤ N ≤ 500 。所有整數的範圍在 -228 到 228 - 1 之間,最終結果不會超過 231 - 1 。

例如:

輸入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]

輸出:
2

解釋:
兩個元組如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/4sum-ii
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
  • 思路分析

使用map進行hash操作,分成兩組數分別遍歷,第一組數的和存儲在map裏(數,這種組合出現的次數)。然後使用map的查找功能判斷第二組數的和是否在map裏,統計次數。這道題返回的是組合數,算是比較簡單。並且不考慮重複組合,只要組合的下標不一樣就可以。

  • 代碼設計
class Solution {
public:
    int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        map<int,int>Map;
        int res=0;
        for(int i=0;i<A.size();++i)
        {
           // if(i>0&&A[i]==A[i-1])
             //   continue;
            for(int j=0;j<B.size();++j)
            {
            //    if(j>0&&B[j-1]==B[j])
              //      continue;

                int ans=-(A[i]+B[j]);
                if(Map.find(ans)==Map.end())
                    Map[ans]=1;
                else
                    Map[ans]+=1;
            }
        }

        for(int i=0;i<C.size();++i)
        {
           // if(i>0&&C[i-1]==C[i])
             //   continue;
            for(int j=0;j<D.size();++j)
            {
               // if(j>0&&D[j-1]==D[j])
                 //   continue;

                int ans=C[i]+D[j];
                if(Map.find(ans)!=Map.end())
                    res+=Map[ans];
            }
        }

        return res;

    }
};

 

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