LeetCode-18-sum of four numbers

subject

Source: LeetCode.

Give you a chance n An array of integers nums ,And a target value target . 
Please find and return the quads that meet all the following conditions and are not repeated [nums[a], nums[b], nums[c], nums[d]] : 

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
 Output:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

Example 2:

Input: nums = [2,2,2,2,2], target = 8
 Output:[[2,2,2,2]]

Tips:

  • 1 < = n u m s . l e n g t h < = 200 1 <= nums.length <= 200 1<=nums.length<=200
  • − 109 < = n u m s [ i ] < = 109 -109 <= nums[i] <= 109 −109<=nums[i]<=109
  • − 109 < = t a r g e t < = 109 -109 <= target <= 109 −109<=target<=109

Next, let's look at the problem-solving ideas:

Idea: sort + double pointer:

This question is related to Sum of three Similarly, you can use the same idea to solve this problem
In order to avoid enumerating to repeated quads, it is necessary to ensure that the elements enumerated in each re cycle are not less than those enumerated in the previous re cycle, and the same elements cannot be enumerated multiple times in the same re cycle;
You can sort the array and follow the following two points during the loop:

  • The subscript enumerated in each loop must be greater than the subscript enumerated in the previous loop;
  • In the same loop, if the current element is the same as the previous element, the current element is skipped;
    Because the array has been sorted, you can use the double pointer method to remove a double loop;
    Keep the third loop unchanged, and turn the fourth loop into a pointer moving to the left from the rightmost end of the array;
    Note: it is also necessary to keep the left pointer always on the left side of the right pointer (i.e. meet the requirements) c ≤ d c \leq d c≤d)
public static List<List<Integer>> fourSum1(int[] nums, int target) {
    List<List<Integer>> result = new ArrayList<>();

    if (nums == null || nums.length < 4) {
        return result;
    }
    // sort
    Arrays.sort(nums);
    int len = nums.length;
    // Enumerate the first digit a
    for (int i = 0; i < len; ++i) {
        // It needs to be different from the last enumeration
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        // Enumerate the second number b
        for (int j = i + 1; j < len; ++j) {
            // It needs to be different from the last enumeration
            if (j > i + 1 && nums[j] == nums[j - 1]) {
                continue;
            }
            // Enumerate the third digit c
            for (int k = j + 1; k < len; ++k) {
                // It needs to be different from the last enumeration
                if (k > j + 1 && nums[k] == nums[k - 1]) {
                    continue;
                }
                // Right pointer
                int m = len - 1;
                // It is necessary to ensure that the third number c is to the left of the fourth number d
                while (m > k && nums[i] + nums[j] + nums[k] + nums[m] > target) {
                    --m;
                }
                // The third number c coincides with the fourth number d. with the subsequent increase of c,
                // If a+b+c+d=0 and c < D is not satisfied, the loop can be exited.
                if (m == k) {
                    break;
                }
                if (nums[i] + nums[j] + nums[k] + nums[m] == target) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[k]);
                    list.add(nums[m]);
                    result.add(list);
                }
            }
        }
    }
    return result;
}

However, even using double pointers saves a layer of for loop, but the efficiency is still not high, and some optimization can be done;
Use the double loop to enumerate the first two numbers respectively, and then use the double pointer to enumerate the remaining two numbers after the number enumerated by the double loop;
Suppose that the first two numbers enumerated by the double loop are in the subscript respectively i i i and j j j. Among them i < j i<j I < J. initially, the left and right pointers point to the subscript respectively j + 1 j+1 j+1 and subscript n − 1 n-1 n − 1. Calculate the sum of four numbers at a time and perform the following operations:

  • If sum equals target \textit{target} target, add the four enumerated numbers to the answer, then move the left pointer to the right until different numbers are encountered, and move the right pointer to the left until different numbers are encountered;
  • If sum is less than target \textit{target} target, move the left pointer to the right one bit;
  • If the sum is greater than target \textit{target} target, move the right pointer one bit to the left.

We can also do some optimization to avoid some redundant loops:

  • After determining the first number, if nums [ i ] + nums [ i + 1 ] + nums [ i + 2 ] + nums [ i + 3 ] > target \textit{nums}[i]+\textit{nums}[i+1]+\textit{nums}[i+2]+\textit{nums}[i+3]>\textit{target} Num [i] + num [i + 1] + num [i + 2] + num [i + 3] > target indicates that the sum of the remaining three numbers must be greater than target \textit{target} target, so exit the first loop;
  • After determining the first number, if nums [ i ] + nums [ n − 3 ] + nums [ n − 2 ] + nums [ n − 1 ] < target \textit{nums}[i]+\textit{nums}[n-3]+\textit{nums}[n-2]+\textit{nums}[n-1]<\textit{target} nums[i]+nums[n − 3]+nums[n − 2]+nums[n − 1] < target indicates that no matter what value is taken for the remaining three numbers, the sum of the four numbers must be less than target \textit{target} target, so the first loop goes directly to the next round, enumeration nums [ i + 1 ] \textit{nums}[i+1] nums[i+1];
  • After determining the first two numbers, if nums [ i ] + nums [ j ] + nums [ j + 1 ] + nums [ j + 2 ] > target \textit{nums}[i]+\textit{nums}[j]+\textit{nums}[j+1]+\textit{nums}[j+2]>\textit{target} Nums [i] + nums [J] + nums [J + 1] + nums [J + 2] > target indicates that no matter what value is taken for the remaining two numbers, the sum of the four numbers must be greater than target \textit{target} target, so exit the second loop;
  • After determining the first two numbers, if nums [ i ] + nums [ j ] + nums [ n − 2 ] + nums [ n − 1 ] < target \textit{nums}[i]+\textit{nums}[j]+\textit{nums}[n-2]+\textit{nums}[n-1]<\textit{target} nums[i]+nums[j]+nums[n − 2]+nums[n − 1] < target indicates that the sum of the remaining two numbers must be less than target \textit{target} target, so the second loop goes directly to the next round, enumeration nums [ j + 1 ] \textit{nums}[j+1] nums[j+1];
public static List<List<Integer>> fourSum(int[] nums, int target) {
    List<List<Integer>> result = new ArrayList<>();

    if (nums == null || nums.length < 4) {
        return result;
    }
    Arrays.sort(nums);
    int n = nums.length;
    // Enumerate the first digit a
    for (int i = 0; i < n - 3; ++i) {
        // It needs to be different from the last enumeration
        if (i > 0 && nums[i] == nums[i - 1]) {
            continue;
        }
        // At this time, no matter what value is taken for the remaining three numbers, the sum of the four numbers must be greater than the target, so exit the first loop;
        if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
            break;
        }
        // At this time, no matter what value the remaining three numbers take, the sum of the four numbers must be less than the target. Therefore, the first cycle directly enters the next round, enumerating num [i + 1];
        if (nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) {
            continue;
        }
        // Enumerate the second number b
        for (int j = i + 1; j < n - 2; ++j) {
            // It needs to be different from the last enumeration
            if (j > i + 1 && nums[j] == nums[j - 1]) {
                continue;
            }
            if (nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                break;
            }
            if (nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) {
                continue;
            }
            int left = j + 1;
            int right = n - 1;
            while (left < right) {
                int sum = nums[i] + nums[j] + nums[left] + nums[right];
                // If the sum is equal to target, add the four enumerated numbers to the answer, then move the left pointer to the right until different numbers are encountered, and move the right pointer to the left until different numbers are encountered
                if (sum == target) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[j]);
                    list.add(nums[left]);
                    list.add(nums[right]);
                    result.add(list);
                    while (left < right && nums[left] == nums[left + 1]) {
                        ++left;
                    }
                    ++left;
                    while (left < right && nums[right] == nums[right - 1]) {
                        --right;
                    }
                    --right;
                } else if(sum < target){   // If the sum is less than target, the left pointer is shifted one bit to the right
                    ++left;
                } else {  // If the sum is greater than the target, the right pointer is moved one bit to the left
                    --right;
                }
            }
        }
    }
    return result;
}
summary

Time complexity: O ( n 3 ) O(n^3) O(n3), where n n n is the length of the array. The time complexity of sorting is O ( n log ⁡ n ) O(n \log n) O(nlogn), the time complexity of enumerating quads is O ( n 3 ) O(n^3) O(n3), so the total time complexity is O ( n 3 + n log ⁡ n ) = O ( n 3 ) O(n^3+n\log n)=O(n^3) O(n3+nlogn)=O(n3);
Space complexity: O ( log ⁡ n ) O(\log n) O(logn), where n n n is the length of the array. The space complexity mainly depends on the additional space used for sorting. An additional array is used to store the array nums \textit{nums} Copies of nums and sort, with a space complexity of O ( n ) O(n) O(n);

Tags: Java Algorithm leetcode

Posted on Wed, 13 Oct 2021 15:57:49 -0400 by Rokboy