Merge and sort the first Hard problem of LeetCode (the number of the sum of LeetCode 327 intervals), Shuai

Keywords: Java Algorithm leetcode

Hello, I'm Monday.

We have talked about merging and sorting in recent algorithms. We'll open another one today. Two more questions.

1, Greater than twice the number on the right

I'm afraid everyone will forget Merge sort , so practice with a question first.

1. Title Description

Find the number in the given array that the current number is greater than twice the number on the right

2. Examples

Array: [6, 7, 3, 2, 1]

The current number is greater than twice the number on the right: (6,2), (6,1), (7,3), (7,2), (7,1), (3,1)

There are six in all.

3. Train of thought

Read it carefully Merge and sort: solve the problem of small sum and reverse order pairs Our partners know that when we solve, we are put together with the merge operation. However, if this problem is solved together with merge operation, it will be very difficult and code complexity.

So, let's change the angle. It's very simple. We divide the operation of finding the number and the merge operation into two cycles. If we find them separately, it will suddenly open up in an instant.

4. Detailed reference code

As like as two peas, only merge code is used.

private static int merge(int[] arr, int l, int mid, int r) {
        int num = 0;
        //  l...mid,   mid+1...r,   The scope of the current right group   [mid+1,   windowR)
        int windowR = mid + 1;
        for (int i = l; i <= mid; i++) {
            while (windowR <= r && arr[i] > (arr[windowR] << 1)) {
                windowR++;
            }
            //  At this time, the number of qualified is   (windowR  -  (mid+1))
            //  Because windowR does not meet the requirements at this time, it is not (windowR)  -  (mid+1))  + one
            num += windowR - mid - 1;
        }

        int[] help = new int[r - l + 1];
        int i = 0;
        int pL = l;
        int pR = mid + 1;
        while (pL <= mid && pR <= r) {
            //  Who small copy who (equal copy left group)
            help[i++] = arr[pL] <= arr[pR] ? arr[pL++] : arr[pR++];
        }
        while (pL <= mid) {
            help[i++] = arr[pL++];
        }
        while (pR <= r) {
            help[i++] = arr[pR++];
        }
        for (int j = 0; j < help.length; j++) {
            arr[l + j] = help[j];
        }

        return num;
    }

OK, the warm-up is over. Of course, today's highlight is how to solve the Hard problem of LeetCode by merging and sorting.

2, LeetCode327. Number of interval sums

So let's look at the use of merging and sorting in the title of LeetCode.

1. Title Description

https://leetcode-cn.com/probl...

Give you an integer array nums and two integers lower and upper. Find the number of intervals and sums in the array whose values are within the range [lower, upper] (including lower and upper).

The interval sum S(i, j) represents the sum of elements with positions from i to j in nums, including i and j (i ≤ j).

2. Examples

Input: num = [- 2,5, - 1], lower = - 2, upper = 2

Output: 3

Explanation: there are three intervals: [0,0], [2,2] and [0,2], and the corresponding interval sum is: - 2, - 1 and 2 respectively.

3. Train of thought

First, we need to know the concept of prefix and.

Prefix and: the prefix and meaning of J position represented by prefix [J] is the sum of the numbers from 0 to j position of the original array.

Why use prefix sum? For frequently summing numbers in a certain range of the array, use prefix sum instead. In this way, summing numbers in the i - j range of the original array is equal to prefix sum and prefix [J] - prefix [I - 1] in the array. In this way, you don't have to traverse the array every time you sum.

The core idea is as follows:

1. Use prefix and instead of the original array;

2. In the merge sort merge method, count the number of accumulation that meet the conditions and separate the merge operation.

3. For each merging operation, for each number x [i] in the right group (prefix and array), find the number of ranges in all numbers in the left group (prefix and array) on [x [i] - upper, x [i] - lower], and add up the numbers that meet the conditions to be the final result

Maybe it's in the clouds. Let's take a look at the detailed code

4. Detailed reference code

/**
 * Description: https://leetcode.com/problems/count-of-range-sum/ . 
 * Chinese version: (327. Number of interval sums) https://leetcode-cn.com/problems/count-of-range-sum/
 * <p>
 * Give you an integer array nums and two integers lower and upper.
 * The value in the evaluation array is in the range   [lower, upper]   (including lower and upper)   Number of interval sums  . 
 * <p>
 * Interval sum S(i, j)   Represents the sum of elements with positions from i to j in nums, including i and j (i ≤ j).
 * <p>
 * The results are tested directly in leetcode
 * <p> 
 *
 * @author Java And algorithm learning: Monday
 */
public class CountOfRangeSum {

    public static int countRangeSum(int[] nums, int lower, int upper) {
        if (nums == null || nums.length < 1) {
            return 0;
        }

        //  Find the prefix sum of the original array
        long[] preSum = new long[nums.length];
        preSum[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            preSum[i] = preSum[i - 1] + nums[i];
        }

        return process(preSum, 0, preSum.length - 1, lower, upper);
    }

    private static int process(long[] preSum, int L, int R, int lower, int upper) {
        //  L  ==  When R, sum [l]   Represents the original array   [0,   50] Cumulative sum over range
        //  In the merge process, the situation that there is no number in the left group will be ignored, so this situation is supplemented here
        if (L == R) {
            return preSum[L] >= lower && preSum[L] <= upper ? 1 : 0;
        }
        int mid = L + ((R - L) >> 1);
        //  Returns the cumulative sum of the left and right groups that meet the conditions during the consolidation process
        return process(preSum, L, mid, lower, upper)
                + process(preSum, mid + 1, R, lower, upper)
                + merge(preSum, L, mid, R, lower, upper);
    }

    private static int merge(long[] arr, int L, int mid, int R, int lower, int upper) {
        //  Cumulative sum number
        int ans = 0;
        //  The left position of the left group (it must start from the current L position)
        int windowL = L;
        //  The right position of the left group (must also start from the current L position)
        int windowR = L;
        //  For each number X in the right group, find the value in the left group in [X-upper,   Number between X-lower]
        for (int i = mid + 1; i <= R; i++) {
            long min = arr[i] - upper;
            long max = arr[i] - lower;

            //  Because the search is in the left group, the subscript cannot exceed mid
            //  Find the first position where the current value is greater than max (this position is not included because it is shifted one bit to the right when it is equal to max)
            while (windowR <= mid && arr[windowR] <= max) {
                windowR++;
            }

            //  Find the first position where the current value is greater than or equal to min (this position is included because there is no right shift when it is equal to min)
            while (windowL <= mid && arr[windowL] < min) {
                windowL++;
            }

            //  Finally, the cumulative sum meeting the requirements is   [windowL,   Window R), i.e   windowR  -  Windowl and windowr are open intervals, so they are not  + one
            ans += windowR - windowL;
        }

        //  The following is the classic merge process
        long[] help = new long[R - L + 1];
        int i = 0;
        int pL = L;
        int pR = mid + 1;
        while (pL <= mid && pR <= R) {
            help[i++] = arr[pL] <= arr[pR] ? arr[pL++] : arr[pR++];
        }
        while (pL <= mid) {
            help[i++] = arr[pL++];
        }
        while (pR <= R) {
            help[i++] = arr[pR++];
        }
        for (int j = 0; j < help.length; j++) {
            arr[L + j] = help[j];
        }

        return ans;
    }

}

LeetCode test results:

Although the execution time is a little worse, it is the first Hard question passed, step by step, and believe in yourself.

Posted by sean72 on Tue, 30 Nov 2021 07:41:28 -0800