two sum / three sum

一:TWO SUM,

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 15, 11], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

思路:如果之前做過 Contiguous Array 題目,那麼這個題目很容易。遍歷數組,使用 ordered_map 數據結構(在 Contiguous Array 中已經說明過爲什麼使用 ordered_map 比 map更快了),保存每個元素期望配對的值 ( target - nums[i] ),以及對應的下標 i .判斷當前的值,是否保存在 ordered_map 數據結構中,如果存在,則返回解。

 

//該方法總的時間複雜度是 O(n),目前在LeetCode中擊敗了 %99.98 碼友

vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        for(int i = 0;i<nums.size(); ++i)
        {
           if(mp.find(nums[i])!=mp.end()){    //在數據不超過千萬級別的情況下,.find 時間複雜度是 O(1)
               int idx = mp[nums[i]];
               return {idx,i};
           }else{    //保存 target - num[i] 的值到map
               int value = target - nums[i];
               mp[value] = i;
           }
        }
        return {};
    }

 

拓展,如果不是結果返回下標,而是直接返回數組的值,還有什麼解法?  可以首先給數組sort排序,耗時 O(nlogn);然後通過最前下標b,末尾下標e;如果nums[b] + nums[e] > target ,那麼 --e;如果 nums[b] + nums[e] < target , 那麼 ++b;相等則返回值。在 3 sum的問題上,由於需要處理重複的值,所以不宜再採用ordered_map方法。採用先排序後處理的方式更加簡便。

 

二:THREE SUM,

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

思路,2sum問題,是3sum問題的一個子問題。對於nums[i],轉嫁爲求在 [ i+1,nums.size() ) 區間的 2sum = (target - nums[i]) 的2sum問題。同理,3sum也是4sum的一個子問題。該方法時間複雜度O(n^2)

vector<vector<int>> threeSum(vector<int>& nums){
        int target = 0;
        vector<vector<int>> rlt;
        sort(nums.begin(),nums.end());
        for(int i=0;i<(int)nums.size() - 2;++i)  //注意啦,size_t(0) - 2 會提升爲無符號數!
        {
            //特別注意需要去除重複,注意不要搞成了 if (nums[i] == nums[i+1]),nums[i]都沒有機會在求解區域就被過濾掉了!
            if(i>0 && nums[i] == nums[i-1])   
                continue;
            if(nums[i] + nums[i+1] + nums[i+2] > target)
                return rlt;
            //問題縮小爲,求nums在 [i+1, nums.size()) 區間的 2sum問題
            int ts = target - nums[i];
            int b = i+1;
            int e = nums.size() - 1;
            while(b<e)
            {
                if(nums[b]+nums[e] > ts)
                    --e;
                else if(nums[b]+nums[e] < ts)
                    ++b;
                else{
                    rlt.push_back(vector<int>{nums[i],nums[b],nums[e]});
                    //注意可能有多個重複的值,需要去除
                    while((b < e) && (nums[b +1] == nums[b])) ++b;
                    while((b < e) && (nums[e -1] == nums[e])) --e;
                    ++b; --e;
                }
            }
        }
        return rlt;
    }

 

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