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;
    }

 

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