剑指offer-数组中的逆序对

问题

题目:[剑指offer-数组中的逆序对]

思路

我的思路就是暴力,显然过不去。
可以参考[求数组中逆序对的个数]

这个题思路的关键就是,如果给你一个序列,我要是把所有的逆序对都找出来,并且找出来的同时也把它交换了,那么最后的序列是没有逆序的。因为,如果有逆序,我就把它换回来就好了,最后肯定是一个有序序列。所以,就是一个找逆序对,交换排序。

思路是用归并,用归并主要是便于计数,其实我觉得对于交换排序,因为交换排序就是找逆序对,也应该是可行的。

两个注意点:
1. arr[i] > arr[j]时可以计数,但是实际走的是arr[j++]
2. (a+b)%c =( (a%c) + (b%c) )%c
3. 判断,c-1 + c-1会不会导致变量溢出。这点要考虑

总之,还是道非常好的题目。

代码

class Solution {
public:
    int InversePairs(vector<int> data) {
        int sz = data.size();
        if(!sz) return 0;
        int count = 0;

        merge_sort( data, 0, sz-1, count );
        return count%1000000007; // 这里也要加
    }
private:
    void merge_sort(vector<int>& arr, int low, int high, int& count){
        if(low < high){
            int mid = (low+high) / 2;

            merge_sort( arr, low, mid, count );
            merge_sort( arr, mid + 1, high, count );
            merge( arr, low, mid, high, count );
        }
    }
    void merge(vector<int>& arr, int low, int mid, int high, int& count){
        int i = low, m = mid;
        int j = mid+1, n = high;
        int k = 0;

        vector<int> tmp( high - low + 1, 0 );

        while( i <= m && j <= n ){
            if( arr[i] > arr[j] ){ // 这种情形才需要计算逆序,此时arr[i] - arr[m] 均大于arr[j]
                count += m - i + 1;
                count %= 1000000007; // 这里加
                tmp[k++] = arr[j++]; // 这里要小心,arr[j] < arr[j],所以是j++
            }
            else tmp[k++] = arr[i++];
        }
        while( i <= m ) tmp[k++] = arr[i++];
        while( j <= n ) tmp[k++] = arr[j++];

        for(int p = low, k = 0; p <= high; ++p, ++k){
            arr[p] = tmp[k];
        }

    }
};

补充

就说一点,对于二分查找而言,循环条件low <= high,但是对于归并排序low < high。区别在于,这两者就是 low == high的区别。对于查找而言,low == high,还是可能找出这个元素的,就是arr[low]。但是,对于排序而言, low == high,就一个数子,没有排序的必要,所以条件写成low < high.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值