Merge and sort: solve the problem of small sum and reverse order pairs

Keywords: Java Algorithm Back-end Programmer

1, Small and problems

1. Title Description:

In an array, the numbers on the left of each number that are smaller than the current number are added up, which is called the small sum of the array. Find the small sum of a given array.

2. Example:

The array is: [1,3,4,2,5]

1 the number smaller than 1 on the left: No

3 the number smaller than 3 on the left: 1

4 the number smaller than 4 on the left: 1,3

2 the number smaller than 2 on the left: 1

5 numbers smaller than 5 on the left: 1,3,4,2

Therefore, the small sum is 1 + (1 + 3) + 1 + (1 + 3 + 4 + 2) = 16

3. Idea:

Find the number larger than the current number on the right of each number, and the cumulative sum of (number * current number) is the result.

How can this be related to merging and sorting? Think about it carefully. When merging the left group and the right group, the number will be compared. At this time, you can find a number larger than the current number of the left group in the right group.

4. Detailed reference code:

/**
 * Small sum problem: in an array, the numbers on the left of each number that are smaller than the current number are accumulated, which is called the small sum of the array. Required time complexity O(N*logN)  
 *
 * @author Java And algorithm learning: Monday
 */
public class SmallSum {

    public static int smallSum(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    private static int process(int[] arr, int l, int r) {
        if (l == r) {
            return 0;
        }
        int mid = l + ((r - l) >> 1);
        return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r);
    }

    private static int merge(int[] arr, int l, int mid, int r) {
        int[] help = new int[r - l + 1];
        int i = 0;

        int pL = l;
        int pR = mid + 1;
        int res = 0;
        while (pL <= mid && pR <= r) {
            //  When the number of left groups is less than the number of right groups,   Number of current right groups * current number   Cumulative sum of   That is, the result of small sum
            //  Careful comparison with merge sort shows that there are more codes here. The only difference is,
            //  When equal to, copy the right group, because to find a larger number in the right group than the left group, you must not copy the left group first, otherwise how to find the number
            res += arr[pL] < arr[pR] ? (r - pR + 1) * arr[pL] : 0;
            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 res;
    }

    /**
     * Logarithmic method
     */
    public static int comparator(int[] arr) {
        int res = 0;
        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < i; j++) {
                res += arr[j] < arr[i] ? arr[j] : 0;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int maxSize = 100;
        int maxValue = 100;
        int testTimes = 100000;

        boolean isSuccess = true;
        for (int i = 0; i < testTimes; i++) {
            int[] arr1 = generateArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);
            if (smallSum(arr1) != comparator(arr2)) {
                printArray(arr1);
                printArray(arr2);
                isSuccess = false;
                break;
            }
        }
        System.out.println(isSuccess ? "Nice" : "Error");
    }

    //------------------------------------------ TEST METHODS ----------------------------------------------

    public static int[] generateArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) ((maxValue + 1) * Math.random());
        }
        return arr;
    }

    public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    public static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }
        for (int value : arr) {
            System.out.print(value + " ");
        }
        System.out.println();
    }

}

Copy code

2, Inverse pair problem

1. Title Description:

There is an array [a1, a2, a3,... an]. For any two elements ai and aj in the array, if I < J, ai > aj, it indicates that ai and aj are a pair of reverse order pairs. Find the number of pairs in reverse order of a given array.

2. Example:

3 5 2 1 0 4 9

All reverse order pairs are: (3,2), (3,1), (3,0), (5,2), (5,1), (5,0), (5,4), (2,1), (2,0), (1,0). The number of pairs in reverse order is 10.

3. Idea:

When merging, merge from right to left. The cumulative sum of the right group position - mid position is the number of pairs in reverse order.

How can this be related to merging and sorting? Think about it carefully. When merging the left group and the right group, I will compare the size of the number, but what I want to find is the smaller one on the right, so I can merge from right to left; At the same time, when processing equality, you need to copy the of the right group first, so as to accurately find the small number of the right group.

4. Detailed reference code:

/**
 * Reverse order pair problem: set an array   [a1, a2, a3,... an], for any two elements ai, aj in the array, if I < J and ai > aj, it indicates that ai and aj are a pair of reverse order pairs.
 * Find the number of pairs in reverse order of a given array.
 *
 * @author Java And algorithm learning: Monday
 */
public class ReversePair {

    public static int reversePairNum(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    private static int process(int[] arr, int l, int r) {
        if (l == r) {
            return 0;
        }
        int mid = l + ((r - l) >> 1);
        return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r);
    }

    private static int merge(int[] arr, int l, int mid, int r) {
        //  Auxiliary array
        int[] help = new int[r - l + 1];
        //  The auxiliary subscript is the maximum value of the array because it is merged from right to left
        int i = help.length - 1;

        //  Similarly, the position of the first number in the left group is mid
        int pL = mid;
        //  The first number in the right group is the last
        int pR = r;
        //  Number of pairs in reverse order
        int num = 0;
        while (pL >= l && pR >= (mid + 1)) {
            //  If the first number in the right group is smaller than that in the left group, the number of pairs in reverse order that currently meet the requirements is   (pR  -  (mid  +  1)  +  1)   That is   (pR  -  mid)
            num += arr[pL] > arr[pR] ? (pR - mid) : 0;
            //  Copy from right to left, equal copy of right group
            help[i--] = arr[pL] > arr[pR] ? arr[pL--] : arr[pR--];
        }
        //  The left and right groups have and only one has not been copied, so only one of the following two loops will be executed
        while (pL >= l) {
            help[i--] = arr[pL--];
        }
        while (pR > mid) {
            help[i--] = arr[pR--];
        }

        //  Copy back to the original array
        for (int j = 0; j < help.length; j++) {
            arr[l + j] = help[j];
        }
        return num;
    }

    /**
     * Logarithms are used for testing
     */
    public static int comparator(int[] arr) {
        int num = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[i]) {
                    num++;
                }
            }
        }
        return num;
    }

    public static void main(String[] args) {
        int testTime = 1000000;
        int maxSize = 100;
        int maxValue = 100;

        boolean isSuccess = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);
            if (reversePairNum(arr1) != comparator(arr2)) {
                printArray(arr1);
                printArray(arr2);
                isSuccess = false;
                break;
            }
        }
        System.out.println(isSuccess ? "Nice" : "Error");
    }

    //---------------------------------------   Auxiliary test method  ---------------------------------------------

    public static int[] generateRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) ((maxValue + 1) * Math.random());
        }
        return arr;
    }

    public static int[] copyArray(int[] arr) {
        if (arr == null) {
            return null;
        }

        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    public static void printArray(int[] arr) {
        if (arr == null) {
            return;
        }

        for (int value : arr) {
            System.out.print(value + " ");
        }
        System.out.println();
    }

}

Copy code

OK, let's talk about using merge sort to solve the problem of small and reverse pairs for the time being.

Sometimes, it is not difficult to master various sorting algorithms. The difficulty is that you can fully understand its process and essence. What is more difficult is that you can think of using this sorting algorithm to solve practical problems. Therefore, there is no shortcut to the algorithm. Only by practicing more and accumulating enough quantitative changes, can we usher in qualitative changes. At that time, we can come easily and come on.


 

Posted by porco on Sun, 28 Nov 2021 10:30:33 -0800