LeetCode15, sum of three numbers

Title description

Insert picture description here

practice

First approach (failure)

public List<List<Integer>> threeSum(int[] nums) {
    
    

        if(nums==null||nums.length<3){
    
    
            return null;
        }
        List<List<Integer>> lists = new ArrayList<>();
        for(int i=0;i<nums.length-3;i++){
    
    
            for(int j=i+1;j<nums.length-2&&nums[j]>=nums[i];j++){
    
    
                for(int k=j+1;k<=nums.length-1&&nums[k]>=nums[j];k++){
    
    
                    if(nums[i]+nums[j]+nums[k]==0){
    
    

                        ArrayList<Integer> arrayList = new ArrayList<>();
                        arrayList.add(nums[i]);
                        arrayList.add(nums[j]);
                        arrayList.add(nums[k]);
                        lists.add(arrayList);
                    }
                }
            }
        }
        return lists;
    }

Reason: I didn't avoid the triple loop. Because I think it is too much trouble to use a hash table to avoid weight.

Refer to the official solution

The problem that needs to be considered when using the three-layer loop is the repetition problem, so if we use a hash table, it is very troublesome, at least I think. Then we need to find another way. A very important point mentioned in the official solution is:将重复的情况一点一点的降低。

  • The order of reduction like (a, b, c) will be enumerated, but (b, a, c), (c, b, a) and so on will not. -The solution is to use sorting. It is ensured that the elements enumerated by the second recycle are not less than the elements enumerated by the current first recycle; the elements enumerated by the third recycle are not less than the elements enumerated by the current second recycle.

This method solves the situation where all the numbers are different. But there are some repetitive situations such as: -1, -1, 1, 1, 0; the
sorting results in -1, -1, 0, 1, 1. Then there are situations: the first time found: [-1,- 1,0], the second time found: [-1,0,1]. In fact, it is still repeated. How can we avoid this situation? Only if the element is different from the previous enumeration, we will enumerate.

Official pseudo code :

nums.sort()
for first = 0 .. n-1
    // 只有和上一次枚举的元素不相同,我们才会进行枚举
    if first == 0 or nums[first] != nums[first-1] then
        for second = first+1 .. n-1
            if second == first+1 or nums[second] != nums[second-1] then
                for third = second+1 .. n-1
                    if third == second+1 or nums[third] != nums[third-1] then
                        // 判断是否有 a+b+c==0
                        check(first, second, third)


We use [-1,-1,-1,-1] for analysis: the first layer loops through the first -1, the second layer traverses the second -1, the third layer traverses the third -1, no The sum is satisfied and equal to 0. Going back to the first level of enumeration, because the results starting with -1 have been enumerated, the next time we enumerate is not -1, and -1 is not allowed. The same is true for the second layer.

test:

class Solution {
    
    
    public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>> lists = new ArrayList<>();
        if(nums==null||nums.length<3){
    
    
            return lists;
        }
        Arrays.sort(nums);/*排序*/
        for(int i=0;i<nums.length;i++){
    
    
            if(i==0||nums[i]!=nums[i-1])
            for(int j=i+1;j<nums.length;j++){
    
    
                if(j==i+1||nums[j]!=nums[j-1])
                for(int k=j+1;k<nums.length;k++){
    
    
                    if(k==j+1||nums[k]!=nums[k-1]){
    
    
                        if(nums[i]+nums[j]+nums[k]==0){
    
    
                            ArrayList<Integer> arrayList = new ArrayList<>();
                            arrayList.add(nums[i]);
                            arrayList.add(nums[j]);
                            arrayList.add(nums[k]);
                            lists.add(arrayList);
                        }
                    }
                }
            }
        }
        return lists;
    }
}

The result timed out: It
Insert picture description here
means that the time complexity O(N 3 ) is difficult to pass

The official solution comes out again:
because of the a+b we got from the first two cycles, the c that exists in the third level is the only result that satisfies a+b+c=0. At the same time, if we traverse to the next number b'of b in the second iteration, we know that b'>b, so the c'that exists in the third layer is also the only one that satisfies a+b'+c'=0. But because b<b', we can deduce c'>c. And because we are sorting,
c'must appear to the left of c in the array. In other words, we can enumerate b from small to large, and at the same time enumerate c from large to small, that is, the second loop and the third loop are actually parallel.

So get the official pseudo code

nums.sort()
for first = 0 .. n-1
    if first == 0 or nums[first] != nums[first-1] then
        // 第三重循环对应的指针
        third = n-1
        for second = first+1 .. n-1
            if second == first+1 or nums[second] != nums[second-1] then
                // 向左移动指针,直到 a+b+c 不大于 0
                while nums[first]+nums[second]+nums[third] > 0
                    third = third-1
                // 判断是否有 a+b+c==0
                check(first, second, third)

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

This method is what we often say " 双指针(盛最多的水这道题里面也出现了。)". When we need to enumerate two elements in an array, if we find that as the first element increases, the second element decreases, then we can use double pointers Method, the time complexity of enumeration is reduced from O(N 2 ) to O(N). Why is it O(N)? This is because in each step of the enumeration process, the "left pointer" will move one position to the right (that is, the b in the title), and the "right pointer" will move several positions to the left, which is related to the elements of the array , But we know that the number of positions it will move in total is O(N), which is evenly spread, and it also moves one position to the left each time, so the time complexity is O(N).

Note that there is the first loop in our pseudocode, and the time complexity is O(N), so the total time complexity of enumeration is O(N 2 ). Since the time complexity of sorting is O(N \log N, which is less than the former in an asymptotic sense, the total time complexity of the algorithm is O(N 2 ).

Author: LeetCode-Solution
link: https: //leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
Source: stay button (LeetCode)
copyright reserved by the authors. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

test:

class Solution {
    
    
   public List<List<Integer>> threeSum(int[] nums) {
    
    
        List<List<Integer>> lists = new ArrayList<>();
        if(nums==null||nums.length<3){
    
    
            return lists;
        }
        Arrays.sort(nums);/*排序*/
        for(int i=0;i<nums.length;i++){
    
    
            if(i==0||nums[i]!=nums[i-1]){
    
    
                int k = nums.length-1;
                int target = -nums[i];
                for(int j=i+1;j<nums.length;j++){
    
    
                    if(j==i+1||nums[j]!=nums[j-1]) {
    
    
                        // 需要保证 b 的指针在 c 的指针的左侧
                        while (j < k && nums[j] + nums[k] > target) {
    
    
                            --k;
                        }
                        // 如果指针重合,随着 b 后续的增加
                        // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                        if (j == k) {
    
    
                            break;
                        }
                        if (nums[j] + nums[k] == target) {
    
    
                            List<Integer> list = new ArrayList<>();
                            list.add(nums[i]);
                            list.add(nums[j]);
                            list.add(nums[k]);
                            lists.add(list);
                        }
                    }
                }
            }

        }
        return lists;
    }
}

Insert picture description here
the complexity:
Insert picture description here

Guess you like

Origin blog.csdn.net/qq_44861675/article/details/108476396