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& 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> threeSum(vector& nums) {
        sort(nums.begin(), nums.end());
        vector> 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 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 > fourSum(vector &num, int target) {
        vector > 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 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& 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;
    }


你可能感兴趣的:(leetcode,leetcode)