LeetCode493翻转对(树状数组+离散化)

题目链接:Leetcode493
LeetCode493翻转对(树状数组+离散化)_第1张图片

思路:同求逆序数一样的更新查询,关键在于离散化部分,我们要得到原序列与2倍序列所对应的位置,并且为了最后能够常数时间查到原序列对应位置的2倍序列的数值的位置,用个哈希函数 i d % n id\%n id%n表示同位置的对应的位置,设一个rnk1表示原序列位置,rnk2表示2倍序列的位置,题就解决了。关于离散化那个用二分处理的可能不好操作,用结构体排序会快点

Code

class Discretization {
public:
    int id; //组号
    //小于n表示第i组原序列 大于n表示第i%n组原序列得2倍
    long long val;
    bool operator < (const Discretization& A) {
        return val < A.val;
    }
};

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        n = nums.size();
        memset(c, 0, sizeof(c));
        //关键:离散化
        //找到原序列和2倍原序列对应得位置
        for (int i=0; i<n; i++) {
            discrete[i].id=i;
            discrete[i].val=nums[i];
            discrete[i+n].id=i+n;
            discrete[i+n].val=nums[i]*2LL;
        }
        sort(discrete, discrete+2*n);
        int tag=0; //去重标记
        for (int i=0; i<2*n; i++) { //预处理两个序列的离散化序列
            if (i==0 || discrete[i].val!=discrete[i-1].val) tag++;
            
            if (discrete[i].id<n) rnk1[discrete[i].id]=tag;
            else rnk2[discrete[i].id-n]=tag;
        }
        
        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans += i-query(rnk2[i]); //查询两倍i的数所得到的贡献
            update(rnk1[i], 1); //i位置对后面的贡献            
        }
        return ans;
    }
private:
    int c[100005], n;
    Discretization discrete[100005];
    int rnk1[50005],rnk2[50005];
    inline int lowbit(int x) {
        return x & (-x);
    }
    void update(int idx, int num) {
        while(idx <= 100000) {
            c[idx] += num;
            idx += lowbit(idx);
        }
    }
    int query(int idx) {
        int sum = 0;
        while (idx > 0) {
            sum += c[idx];
            idx -= lowbit(idx);
        }
        return sum;
    }
};

你可能感兴趣的:(思维,树状数组,LeetCode)