Daily AC series: the closest sum of three

Keywords: less github

1 topic

The sixteenth question of leetcode , given an array and a target number, find out three numbers in the array. The sum of these three numbers should be closest to the target number.

2 violence

As a rule, the first O(n3) violence:

int temp = nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.length;++i)
    for(int j=i+1;j<nums.length;++j)
        for(int k=j+1;k<nums.length;++k)
        {
            int temp1 = nums[i]+nums[j]+nums[k];
            if(Math.abs(temp-target) > Math.abs(temp1-target))
            {
                temp = temp1;
                if(temp == target)
                    return target;
            }
        }
return temp;

then....

Flattered, the direct violence has been given...

3 O(n2)

Well, I can't watch this kind of violence. I can do something serious. If it's violent, I'll go through three cycles directly. Each time, I'll add three numbers and judge the distance from target. If it's target, I'll go back. If it's not, I'll go on O(n3) ah...
In fact, this can also be used by the author Last article In the double pointer method mentioned in, the array is sorted first, then a number is fixed, and then two pointers point to the start and end, and then approach to the middle continuously.

Arrays.sort(nums);
int t1 = nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.length-2;++i)
{
    int left = i+1;
    int right = nums.length-1;

    while(left < right)
    {
        int t2 = nums[i]+nums[left]+nums[right];
        if(t2 == target)
            return target;
        else if(t2 > target)
            --right;
        else 
            ++left;
        if(abs(t1-target) > abs(t2-target))
        {
            t1 = t2;
        }
    }
}
return t1;

First, the array is sorted. nums[i] is a fixed number, and left and right are two pointers. According to the calculated t2=nums[i]+nums[left]+nums[right], the relationship with target is judged. If it is larger, move the right pointer to the left, and if it is smaller, move the left pointer to the right until the two pointers meet. O(n log n) is required for sorting, O (N 2) is required for two cycles, and the total time complexity is O (N 2)

4 impact 2ms

Take a look at the first answer, 2ms, it's really fast. It's mainly about the handwritten quick arrangement, and then use the maximum and minimum pruning in the loop of for.

4.1 quick arrangement of handwriting

Check the algorithm of Arrays.sort(), which is a combination of several algorithms:

(picture source)

Only when the length of the array is less than 286 and greater than or equal to 47, can quick sorting be called. Therefore, a quick sorting is directly written here, and it is directly used no matter how long.
(I won't say much about the principle. It's a little bit difficult to arrange quickly by hand...)

public void qs(int [] nums,int l,int r)
{
    if(l < r-1)
    {
        int t = l;
        int ll = l+1;
        int rr = r-1;
        int temp;
        while(true)
        {
            while(t < rr && nums[t] < nums[rr])
                --rr;
            if(t < rr)
            {
                temp = nums[rr];
                nums[rr] = nums[t];
                nums[t] = temp;
                t = rr--;
            }
            else
                break;
            while(ll < t && nums[ll] < nums[t])
                ++ll;
            if(ll < t)
            {
                temp = nums[ll];
                nums[ll] = nums[t];
                nums[t] = temp;
                t = ll++;
            }
            else
                break;
        }
        qs(nums,l,t);
        qs(nums,t+1,r);
    }
}

The condition in the original two while loops is

while(ll < rr && ...)

Later, there was a bug. I adjusted it for a while and found that the scope was wrong. I changed it to two while:

while(t < rr && ...)
while(ll < t && ...)

4.2 maximum and minimum pruning

The minimum pruning is to calculate the fixed number, and the sum of the two minimum numbers. If the minimum value is greater than the target value, the result may be the minimum value, but it cannot be any other value, because this value is the minimum value, and it is greater than the target value. If it is added with other values, it will only be further away from the target value, so the judgment is the most important After a small value, you can break directly

The maximum pruning is also similar. Calculate the sum of the two largest numbers and the fixed number, judge the size of the target value. If it is less than the target value, the result may be this maximum value, not other values, and break directly after judgment

int left = i+1;
int right = nums.length-1;
if(left < right)
{
    int min = nums[i] + nums[left] + nums[left+1];
    if(min > target)
    {
        if(abs(min - target) < abs(t1 - target))
            t1 = min;
        continue;
    }
}

int max = nums[i] + nums[right] + nums[right-1];
if(max < target)
{
    if(abs(max - target) < abs(t1 - target))
        t1 = max;
    continue;
}

4.3 oh...


One word, happy.

5 source code

github
Code cloud

Published 47 original articles, won praise 4, visited 4109
Private letter follow

Posted by belaraka on Fri, 24 Jan 2020 01:24:12 -0800