码农小汪-剑指Offer之33 -数组中的逆序对 冒泡排序 归并排序

本文介绍了一种利用归并排序算法解决数组中逆序对问题的方法,通过分而治之的策略,提高了效率,从原始的n^2复杂度降低至n*logN。详细解释了归并排序的三个关键步骤,并通过代码实例展示了实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

解题思路

我一看到这道题,首先就想到了冒泡排序,总是两两比较然后统计次数!

public class Sloution33 {
    /**
     * 冒泡解决问题
     * @param array
     * @return
     */
    public int InversePairs(int[] array) {

        int count=0;
        for(int i=0;i<array.length;i++){
            for(int j=i+1;j<array.length;j++){
                if(array[i]>array[j]){
                    count++;
                    Swap(array[i], array[j]);
                }
            }
        }
        return count;

    }
    public void Swap(int a,int b){
        int temp=a;
        a=b;
        b=temp;
    }
}

但是上面的太耗时了效率n*n;
当时想过使用flag来表识,排好序的改进~但是这个题目不可以,排好序la,人家还是比你大~
后来看到大神使用归并排序,我自己也想了一下,反正我冒泡的思路也是排序,归并排序也是这样子弄 n*logN效率肯定不一样。用到了分而冶之的思路.
左边的逆序数,右边的逆序数。合并的逆序数
所以当前排好序的逆序数等于这三个部分组成的。

归并排序的三个要点:
1。首先分成小部分,不管排序。这个和快排不一样
2。分了之后,就是合并嘛,合并的时候处理顺序问题
就是这货,需要格外的空间处理

下面就是这个啦~

package JianzhiOffer;

public class Slution33_2 {

    public int InversePairs(int[] array) {
        int len = array.length;
        if (len < 2)
            return 0;
        return mergeSort(array, 0, len - 1);
    }

    /**
     * 归并排序,先分解,在合并
     * 
     * @param array
     * @param start
     * @param end
     * @return
     */
    private int mergeSort(int[] array, int start, int end) {
        // TODO Auto-generated method stub
        if (start >= end) {
            return 0;
        }
        int mid = start + (end - start) / 2;
        /**
         * 我们的数量等于左边+右边的数量在加上合并的数量,等于最后的数量
         */
        int countL = mergeSort(array, start, mid);
        int countR = mergeSort(array, mid + 1, end);
        int arrayTemp[] = new int[end - start + 1];
        /**
         * 格外的空间,保存排好序的信息~
         */
        for (int i = 0; i < arrayTemp.length; i++) {
            arrayTemp[i] = 0;
        }
        int mergeCount = 0;
        int iMid = mid;
        int jEnd = end;
        int kElementCount = end - start;
        // 合并的操作
        // satrt mid mid+1 end
        // 前面半截有序的哦 有序的合并

        while (iMid >= start && jEnd >= mid + 1) {
            if (array[iMid] > array[jEnd]) {
                mergeCount += (jEnd - mid);// 当前的比后面的都大从 mid+1 dao end
                                            // 一共end-(mind+1)+1
                arrayTemp[kElementCount] = array[iMid];// 保存最大的个
                kElementCount--;
                iMid--;
            } else {
                // 前面的元素没有后面的最大的大
                arrayTemp[kElementCount] = array[jEnd];
                kElementCount--;
                jEnd--;
            }
        }
        // 下面的可能单向的就完了,所以要排序的放入tmp中;
        while (iMid >= start) {
            arrayTemp[kElementCount] = array[iMid];
            kElementCount--;
            iMid--;
        }
        while (jEnd >= mid + 1) {
            arrayTemp[kElementCount] = array[jEnd];
            kElementCount--;
            jEnd--;
        }
        /**
         * 把排好序的赋值给我们的array
         */
        for (int i = start, j = 0; i <= end; i++) {
            array[start] = arrayTemp[j++];
        }
        /**
         * 其实这里用到了分冶思想 我们的count=左边+右边+合并的数量; 这里处理的不错。就是个排序嘛~通过排序统计次数。直接就是合并排序
         */
        return countL + countR + mergeCount;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值