LeetCode 16 3Sum Closest Available Rule of Thirds

The meaning of the question: a variant of the 3Sum question, given n numbers nums[] and a target, find the combination of 3 numbers in n so that the difference between the sum and the target is the smallest.

Idea: The traditional 3Sum method (LeetCode15), enumerate two of the three numbers, and then verify whether the remaining numbers are in the given set. In the next step, time can be exchanged for space, and it can be done by binary, so that the complexity is multiplied by a logn; or space can be exchanged for time, directly stored in an array or a hash chain.

For this question, you can continue to use the traditional solution, first enumerate two of the three numbers, but notice that the change of the target answer is not monotonic, that is, after taking out the two numbers nums[i] and nums[j] , the calculation process of the optimal solution is ans=f(v)=min(target-nums[i]-nums[j]-v), this function about v is first decreased and then increased, it is a classic can be used The model for calculating the optimal solution by the method of thirds.

I haven't written three points for a long time. Maybe someone else has a better way to write it. Here is a way to write a constant that may be higher but must not be wrong:

  1. First take l, r to get the distance d=rl between the endpoints;
  2. If d<3, exit the loop, and directly calculate the value corresponding to each point from l to r to maintain the answer;
  3. Otherwise, the length len=d/3 of the trisection is calculated, and p1=l+len, p2=r-len;
  4. Because len=d/3<=(double)d/3, plus the previous constraint when d>=3, it can be guaranteed that p1<p2;
  5. Compare the size of f(p1) and f(p2), and take the higher one for three points;

Regarding the reason for taking the higher point in step 5, the following figure is an example:

If the low point is taken, that is, the blue dot on the left, the left endpoint moves to the right, and it is obvious that the optimal solution is excluded from the interval.

The following is the code part:

#include <algorithm>
#include <cmath>

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        int ans = nums[0] + nums[1] + nums[2];
        for (int i = 0; i < n; ++i){
            for (int j = i + 1; j < n; ++j){
                int now = target - nums[i] - nums[j];
                int l = j + 1, r = n - 1;
                int p1, p2, v1, v2;
                while(r - l > 3){
                    int len = (r-l) / 3;
                    int p1 = l + len;
                    int p2 = r - len;
                    v1 = abs(now-nums[p1]);
                    v2 = abs(now-nums[p2]);
                    if (v1 > v2) l = p1;
                    else r = p2;
                }
                while(l <= r){
                    if (abs(target-ans) > abs(now-nums[l]))
                        ans = nums[i] + nums[j] + nums[l];
                    ++l;
                }
            }
        }
        return ans;
    }
};

Of course, O(n²logn) is not the optimal solution. In fact, there is an O(n²) approach to this problem. Just enumerate the smallest nums[i] of the three numbers, then take [l,r], where l=i+1 , r=n-1 , and then use ans=nums[i]+nums[ l]+nums[r] maintains the answer, when ans is less than target, ++l, otherwise r--;

This time, I got a new binary function f(l,r), and try to prove the correctness:

By contradictory method, assuming that the real answer is outside the [l,r] convergence process, denoted as x, y, then it can be determined that in the [l,r] convergence process, there must be [x+1,r] (or [l ,y-1] corresponds to another case), at this time there is r>y;

那么nums[x]+nums[r]+nums[i]<target,又y<r,则nums[y]<nums[r],

=>nums[x]+nums[y]+nums[i]<nums[x]+nums[r]+nums[i];

Therefore [x, y] is not the real optimal solution, which contradicts the hypothesis, so it is proved.

(When I am old, I can still do proof questions)

The code part is as follows:

#include <algorithm>
#include <cmath>

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n = nums.size();
        int ans = nums[0] + nums[1] + nums[2];
        int delta = abs(target-ans);
        sort(nums.begin(), nums.end());
        for(int i = 0; i < n; ++i){
            int l = i + 1;
            int r = n - 1;
            while(l < r){
                int now = nums[i] + nums[l] + nums[r];
                if(now == target)
                    return now;
                if(abs(now-target) < delta){
                    delta = abs(now-target);
                    ans = now;
                }
                if(now - target < 0)
                    ++l;
                else
                    r--;
            }
        }
        return ans;
    }
};

And the comparison of time efficiency:

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326385377&siteId=291194637