Array(8) -- Search Insert Position,3Sum,4Sum

Search Insert Position

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1


二分查找,插入如果在某数的左边,则right < left, 要返回该数的index即left; 插入如果在某数的右边,即left > right, 要返回该数的index+1,即left.

    int searchInsert(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int half = 0;
        while(left <= right){
            half = (left + right) / 2;
            if(nums[half] > target)
                right = half - 1;
            else if(nums[half] == target) 
                return half;
            else
                left = half + 1;
        }
        return left;
    }


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

思路是将3Sum问题降为2Sum问题,注意去重的情况,注意几个可以剪枝的情况。 剪枝时num[i]*3 比nums[i] + nums[i+1] + nums[i+2] 这种形式还是快一些的。

在解决2Sum问题时,有人提出可以用类似二分查找的方式,在解决2Sum问题加快速度,感觉上可行。

    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> rst;
        if(nums.empty()) return rst;
        int max = nums[nums.size()-1];
        for(int i = 0; i < nums.size() - 2; i++){
            if(nums[i] * 3 > 0) break;  //pruning
            if(nums[i] + max*2 < 0) continue;
            int target_2 = 0 - nums[i];
            int low = i+1, high = nums.size() - 1;
            while(low < high){
                if(nums[low] * 2 > target_2 || nums[high]*2 < target_2) break;
           if(nums[low] + nums[high] < target_2){
              if(nums[(low+high)/2] + nums[high] < target_2) low = (low+high)/2 + 1;  //类似二分查找的方式
             else low++;  //一般方式
           }
           else if(nums[low] + nums[high] > target_2){
             if(nums[(low+high)/2] + nums[low] > target_2) high = (low+high)/2 - 1;
             else high--;
           } 
                else{
                    vector<int> tmp;
                    tmp.push_back(nums[i]);
                    tmp.push_back(nums[low]);
                    tmp.push_back(nums[high]);
                    rst.push_back(tmp);
                    while(low < high && nums[low] == tmp[1]) low++;  //avoid duplicates,去掉与前面重复的
                    while(high > low && nums[high] == tmp[2]) high--;
                }
            }
            while(i+1 < nums.size() && nums[i+1] == nums[i]) i++;
        }
        return rst;
    }


4Sum

思路是将4Sum问题先降为3Sum问题,再降为2Sum问题;然后使用前后双指针解决2Sum问题。

有一些不可能的情况可以被剪掉。

开始采用回溯的做法会超时,原因是在回溯在解决2Sum问题时是O(n2)的解法,双指针是O(n)解法。

    vector<vector<int> > fourSum(vector<int> &num, int target) {
        vector<vector<int> > res;
        if (num.empty())
            return res;
        std::sort(num.begin(),num.end());
        int max = num[num.size()-1];
        for (int i = 0; i < num.size(); i++) {
            //impossible conditions
            if(num[i]*4 > target
                || (num[i] + max*3) < target
                || i + 3 > num.size() - 1) 
                continue;
            int target_3 = target - num[i];
            for (int j = i + 1; j < num.size(); j++) {
                //impossible conditions
                if(num[j]*3 > target_3
                    || (num[j] + max*2) < target_3
                    || j + 2 > num.size() - 1) 
                    continue;
                int target_2 = target_3 - num[j];
                int front = j + 1;
                int back = num.size() - 1;
                while(front < back) {
                    //impossible conditions
                    if(num[front]*2 > target_2) break;
                    int two_sum = num[front] + num[back];
                    if (two_sum < target_2) front++;
                    else if (two_sum > target_2) back--;
                    else {
                        vector<int> quadruplet(4, 0);
                        quadruplet[0] = num[i];
                        quadruplet[1] = num[j];
                        quadruplet[2] = num[front];
                        quadruplet[3] = num[back];
                        res.push_back(quadruplet);
                        // Processing the duplicates of number 3
                        while (front < back && num[front] == quadruplet[2]) ++front;  
                        // Processing the duplicates of number 4
                        while (front < back && num[back] == quadruplet[3]) --back;
                    }
                }
                // Processing the duplicates of number 2
                while(j + 1 < num.size() && num[j + 1] == num[j]) ++j;
            }
            // Processing the duplicates of number 1
            while (i + 1 < num.size() && num[i + 1] == num[i]) ++i;
        }
        return res;
    }

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).
和上面是一个系列,思路类似,不去重虽然不会影响结果,但是会影响速度。

    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int rst = nums[0] + nums[1] + nums[2];
        int closet = abs(nums[0] + nums[1] + nums[2] - target);
        for(int i = 0; i < nums.size() - 2; i++){
            int target_2 = target - nums[i];
            int low = i + 1;
            int high = nums.size() - 1;
            while(low < high){
                int sum_2 = nums[low] + nums[high];
                if(abs(sum_2 - target_2) < closet) {
                    rst = sum_2 + nums[i];
                    closet = abs(sum_2 - target_2);
                }
                if(sum_2 > target_2) 
                    while (low < high && nums[high] == nums[--high]);	//去重
                else if(sum_2 == target_2) return target;
                else 
                    while (low < high && nums[low] == nums[++low]);	//去重
            }
        }
        return rst;
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值