leetcode之数组左右夹逼法

来源:互联网 发布:兄弟绣花机软件 编辑:程序博客网 时间:2024/06/06 07:15

一、题型:在一个数组中选出k个元素,使这k个元素的和等于目标值target。


二、分析:我们可以用k个for循环求出这k个元素,这时的时间复杂度为O(n^k)。但通过左右夹逼法可以将时间复杂度将至O(n^(k-1))。

    左右夹逼法(2个元素):先对数组nums[ ]所有元素进行排序,然后数组从左右两侧向中间推进:left为当前左侧元素的下标,right为当前右侧元素的下标。若nums[left]+nums[right]<target,即当前两个元素和小于target,那么如果其中一个元素再大一点,就会更接近target,而数组此时是有序的,所以只能left向中间推进,left+1;若nums[left]+nums[right]>target,同理可得此时right向中间推进,right-1。


三、例题

1.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.

Example:

Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,return [0, 1].

UPDATE (2016/2/13):
The return format had been changed to zero-based indices. Please read the above updated description carefully.

分析:若本题要求返回和等于target的元素,则可以使用左右夹逼法,但本题要求返回元素的序号,排序后就把原本的序号打乱了,所以本题不能使用左右夹逼法,。此时可以使用unordered_map哈希表来记录出现的元素。

class Solution {public:    vector<int> twoSum(vector<int>& nums, int target) {        unordered_map<int,int> map;        vector<int> twosum;        for(int i=0;i<nums.size();++i) {            map[nums[i]] = i;        }                for(int i=0;i<nums.size();++i) {            if(map.find(target-nums[i])!=map.end() && map[target-nums[i]]>i) {                twosum.push_back(i);                twosum.push_back(map[target-nums[i]]);                break;            }        }        return twosum;    }};


2. 3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • The solution set must not contain duplicate triplets.

    For example, given array S = {-1 0 1 2 -1 -4},    A solution set is:    (-1, 0, 1)    (-1, -1, 2)

分析:原数组内出现重复的元素,但结果却不能有相同的三元组,所以在处理中要跳过相同的元素。

class Solution {public:    vector<vector<int>> threeSum(vector<int>& nums) {        const int size = nums.size();        vector<vector<int>> result;        if(size<3) return result;        sort(nums.begin(),nums.end());        const int target = 0;                for(int i=0;i<size-2;i++) {            int j = i+1;            int k = size-1;            if(i>0&&nums[i]==nums[i-1]) continue;            while(j<k) {                if(nums[i]+nums[j]+nums[k] < target) {                    ++j;                    while(j<k && nums[j-1]==nums[j]) j++;                 } else if(nums[i]+nums[j]+nums[k] > target) {                    k--;                    while(j<k && nums[k+1]==nums[k]) k--;                 } else {                    result.push_back({nums[i],nums[j],nums[k]});                    j++;                    k--;                    while(j<k && nums[j]==nums[j-1] && nums[k]==nums[k+1]) {                        j++;                        --k;                    }                }            }        }        return result;    }};

3. 3Sum closest

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

分析:原数组元素唯一

class Solution {public:    int threeSumClosest(vector<int>& nums, int target) {        const int size = nums.size();        if(size<3) return 0;        int closest = INT_MAX;        int sum = 0;        sort(nums.begin(),nums.end());        for(int i=0;i<size-2;i++) {            int j = i+1;            int k = size-1;            while(j<k) {                int temp = nums[i]+nums[j]+nums[k];                if(abs(temp-target)<closest) {                    closest = abs(temp-target);                    sum = temp;                }                if(temp < target) {                    ++j;                } else if(temp > target) {                    k--;                } else {                    return target;                }            }                    }        return sum;    }};

4. 4Sum

Given an array S of n integers, are there elements abc, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.

Note:

  • Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
  • The solution set must not contain duplicate quadruplets.

    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.    A solution set is:    (-1,  0, 0, 1)    (-2, -1, 1, 2)    (-2,  0, 0, 2)

class Solution {public:    vector<vector<int>> fourSum(vector<int>& nums, int target) {        const int size = nums.size();        vector<vector<int>> result;        if(size<4) return result;        sort(nums.begin(),nums.end());        for(int i=0;i<size-3;i++) {            if(i>0&&nums[i]==nums[i-1]) continue;            for(int j=i+1;j<size-2;j++) {                if(<span style="color:#ff0000;">j>i+1</span>&&nums[j]==nums[j-1]) continue;  //j-1有可能等于i,避免nums[i]==nums[j](相当于<span style="font-family: Arial, Helvetica, sans-serif;">nums[i]==nums[j])</span><span style="font-family: Arial, Helvetica, sans-serif;">进行continue,</span>                int s = j+1;                int t = size-1;                while(s<t) {                    int sum = nums[i]+nums[j]+nums[s]+nums[t];                    if(sum<target) {                        s++;                        while(s<t&&nums[s]==nums[s-1]) s++;                    } else if(sum>target) {                        t--;                        while(s<t&&nums[t]==nums[t+1]) t--;                    } else {                        result.push_back({nums[i],nums[j],nums[s],nums[t]});                        s++;                        t--;                        while(s<t&&nums[s]==nums[s-1]&&nums[t]==nums[t+1]) {                            s++;                        }                    }                }            }        }        return result;    }};


0 0
原创粉丝点击