Algorithm Multiple Solutions - Reverse Pairs in JZ51 Array (Merge Sort Advanced Tree Array)

topic

[Medium] Pass rate: 16.79% Time limit: 3 seconds Space limit: 64M


Solution 1 (naive approach)

ideas

  • Seeing this topic, the simplest idea is violence:
  • The double loop scans the array, if the front is larger than the back, count +1
  • But seeing 50% of the data, size<=1e4, the double loop is 1e8, but it is obviously not enough if it is bigger.
  • Therefore, pure violence can't get full marks (see how the test points are given)

Complexity Analysis

  • Time complexity: O(nlogn) to O(n^2), the length of the inner loop is reduced by one after each loop
  • Space Complexity: O(1)

code

class Solution {
public:
    int InversePairs(vector<int> data) {
        int len = data.size();
        if(!data.size()){
            return 0;
        }
        long long int ans = 0;
        for(int i=0; i<len; i++){
            for(int j=i+1; j<len; j++){
                if(data[i]>data[j]) ans++;
            }
        }
        return ans%1000000007;
    }
};

Solution 2 (merge sort optimization)

ideas

When you see the time complexity required to be O(nlogn), the correct idea should think of quicksort, mergesort, heapsort. This problem is more suitable to use merge sort to solve.

In the process of merge sort, the array is divided into sub-arrays with a minimum of 2 elements, and then the lengths of the sub-arrays are compared in turn. Here, the same method can be used to count the reverse order pairs. There are three main stages:

  1. Divide stage: Divide the midpoint of the interval to be divided into two parts;
  2. Sorting phase: Use merge sort to process subsequences recursively, while counting inverse pairs;
  3. Merge stage: Merge the sorted subsequences.

In merge sort, when the right is greater than the left, it is greater than all subsequences on the left. Based on this property, we can count without adding 1 each time, reducing the number of operations.

diagram

Complexity Analysis

  • Time complexity: O(nlogn), merge sort uses the idea of ​​divide and conquer, the complexity is this
  • Space complexity: O(n), the length of the auxiliary array temp is n and the maximum depth of the recursive stack will not exceed n

code

class Solution {
public:
    int mod = 1000000007;
    int mergeSort(int left, int right, vector<int>& data, vector<int>& temp){
        if(left>=right)    // 停止划分
            return 0;
        int mid = (left+right)/2; //取中间
        int res = mergeSort(left, mid, data, temp) + mergeSort(mid+1, right, data, temp); //左右划分
        res %= mod;  //防止溢出
        int i=left, j = mid+1;
        for(int k=left; k<=right; k++)
            temp[k] = data[k];
        for(int k=left; k<=right; k++){
            if(i==mid+1)
                data[k] = temp[j++];
            else if(j==right+1 || temp[i]<=temp[j])
                data[k] = temp[i++];
            else{ //左边比右边大,答案增加
                data[k] = temp[j++];
                res += mid-i+1; // 统计逆序对
            }
        }
        return res % mod;
    }
    int InversePairs(vector<int> data) {
        int n = data.size();
        vector<int> res(n);
        return mergeSort(0, n-1, data, res);
    }
};

Solution 3 (tree array optimization)

ideas

Tree arrays are arrays as shown, which can accumulate prefixes and sums

Summary on 1D and 2D Prefix Sum & Difference --> go down

Summary of Prefix Sum & Difference Hard Core Graphics and Text - Explanation of 4 Classical Example Questions Next, enter m queries, each with a pair of l, r. For each query, output the sum from the lth to the rth number in the original sequence. The first line of the input format contains two integers n and m. The second line contains n integers, representing a sequence of integers. The next m lines, each containing two integers l and r, represent the interval range of a query. The output format consists of m lines, and each line outputs a query result. Data range 1≤l≤r≤n1≤l≤r≤n,1≤n,m≤1000001≤n, m≤100000 ,−1000≤value of element in sequence≤1000−1000≤value of element in sequence≤https ://blog.csdn.net/Luoxiaobaia/article/details/105903362

  • For example, 4 counts the prefix sum of 123, and 8 counts the prefix of 1234567, and because it is a tree, the operation is O(logn).
  • We first perform a discretization operation on the original array, and after the sorted operation plus the subsequent binary search mapping, the array [1 5000 2 400 30] is mapped to -> [1 5 2 4 3], even if they are connected, reducing the space Need, because there are no repeated elements given in the title, so there is no need to deduplicate, it is still n numbers.
  • Then traverse each element from front to back to find the prefix sum in the tree array, indicating how many times this element appears in the tree array, the difference between the prefix and the sum, query(n)−query(data[i]), indicating The number of times the value appears in [data[i]+1,m], that is, the number of inverse numbers.

Complexity Analysis

  • Time complexity: O(nlogn), the sort function sorting is O(nlogn); the time complexity of the dichotomy in the discretization process is O(logn), a total of n times; in the process of statistical inversion pairs, the query update is O(logn ), a total of n times
  • Space complexity: O(n), the length of the auxiliary array temp and the length of the tree array are both n

code

class BIT {
private:
    vector<int> tree;
    int n;
    
public:
    BIT(int m) : n(m), tree(m + 1) {} //初始化

    int lowbit(int x){ //位操作,使数组呈现2、4、8、16这种树状
        return x & (-x);
    }

    int query(int x){ //查询序列1到x的前缀和
        int res = 0;
        while(x){
            res += tree[x];
            x -= lowbit(x);
        }
        return res;
    }
    
    void update(int x){ //序列x位置的数加1
        while(x <= n){
            tree[x]++;
            x += lowbit(x);
        }
    }
};

class Solution {
public:
    int mod = 1000000007;
    int InversePairs(vector<int> data) {
        int n = data.size();
        int res = 0;
        vector<int> temp = data;

        //离散化
        sort(temp.begin(), temp.end()); //排序
        for(int i = 0; i < n; i++) //二分法重新映射
            data[i] = lower_bound(temp.begin(), temp.end(), data[i]) - temp.begin() + 1;
        BIT bit(n); //建立树状数组
        for(int i = 0; i < n; i++){ //统计逆序对
            res = (res + bit.query(n) - bit.query(data[i])) % mod;
            bit.update(data[i]);
        }
        return res;
    }
};

Reference thanks : Lone Sail, Far Shadow, and the Blue Sky_Niu Ke Blog

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325203231&siteId=291194637