树状数组求逆序数

来源:互联网 发布:pdf阅读器下载 知乎 编辑:程序博客网 时间:2024/05/20 04:50

树状数组的简介见:
http://blog.csdn.net/x_iya/article/details/8943264

什么是逆序数?

在一个排列中,如果一对数的前后顺序与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序数的总数就是这个排列的逆序数。

一般的解法:
当数据的范围较小时,比如maxn=100000,那么我们可以开一个数组C[maxn],来记录前面数据的出现情况,初始化为0。
当数据a出现时,就令C[a]=C[a]+1。这样的话,欲求某个数a的逆序数,只需要算出在当前状态下C[a+1]到C[maxn]中有多少个1,因为这些位置的数在a之前出现且比a大。但是若每添加一个数据a时,就得从a+1到maxn搜一遍,复杂度太高了。

树状数组却能很好的解决这个问题,同样开一个数组C[maxn],初始化为0,C[i]记录下i结点所管辖范围内当前状态有多少个数被添加;当添加数据a时,就向上更新C,这样一来,欲求a的逆序数时,只需要算getSum(maxn)-getSum(a);sum(a)表示a之前出现了多少个1,也即有多少小于等于a的元素个数。
或者用i记录添加数据的次序(记录添加了几个数据了),i-getSum(a)也即为a的逆序数。 

public class Solution {    private int[] arr;    private int maxn = 100000;    private int LowBit(int x) {        return x & (-x);    }    private int getSum(int pos) {        int sum = 0;        while (pos > 0) {            sum += arr[pos];            pos -= LowBit(pos);        }        return sum;    }    private void update(int pos, int val) {        while (pos <= maxn) {            arr[pos] += val;            pos += LowBit(pos);        }    }    public int resolve(int[] nums) {        int count = 0;        arr = new int[maxn];        for (int i = 0; i < nums.length; i++) {            update(nums[i], 1);            count += (i + 1 - getSum(nums[i]));        }        return count;    }    public static void main(String[] args) {        Solution solution = new Solution();        int[] arr = {5, 3, 4, 2, 1};        System.out.println(solution.reversePairs(arr));    }}
原创粉丝点击