剑指Offer-题51(Java版):数组中的逆序对

参考自:《剑指Offer——名企面试官精讲典型编程题》

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

主要思路
  类似于归并排序。先把数组等分成子数组,统计出子数组的逆序对数目,在统计子数组的过程中,同时对子数组进行从小到大排序。然后,递归统计前后相邻子数组之间的逆序对数目。
  统计前后相邻子数组逆序对的过程如下:使用两个指针分别指向前后子数组的末尾,然后比较指针指向的数字大小。

  1. 若前面的数字大于后面的数字,说明有逆序对,且逆序对的数目等于后面数组剩余数字的数目(因为,后数组左边的数字都小于或等于后数组指针指向的数字)。
  2. 若前面的数字小于或等于后面的数字,说明无逆序对。

  每次比较完,都把较大的数字从后向前复制到辅助数组,保证辅助数组按从小到大排序,有序的辅助数组将用于求下一次更大的相邻子数组逆序对数目。
  这个过程就相当于在归并排序的过程中,统计逆序对的数目。

关键点:归并排序,递归,双指针

时间复杂度:O(nlogn)

public class InversePairs {
    public static void main(String[] args) {
        int[] data = {1, 2, 3, 4, 7, 6, 5};
        int[] data1 = {2, 1};
        //3
        System.out.println(getInversePairsCount(data));
        //1
        System.out.println(getInversePairsCount(data1));
    }

    private static long getInversePairsCount(int[] data) {
        if (data == null || data.length == 0) {
            return 0;
        }
        int length = data.length;
        int[] copy = new int[length];
        //复制数组到辅助数组
        System.arraycopy(data, 0, copy, 0, length);
        return inversePairsCount(data, copy, 0, length - 1);
    }

    private static long inversePairsCount(int[] data, int[] copy, int start, int end) {
        //子数组只有一个数
        if (start == end) {
            copy[start] = data[start];
            return 0;
        }

        int middle = start + (end - start) / 2;

        //copy和data数组在这里交换位置
        //相当于每次递归后data的前后半段都是有序的
        long leftCount = inversePairsCount(copy, data, start, middle);
        long rightCount = inversePairsCount(copy, data, middle + 1, end);

        //前半段最后一个数字的下标
        int leftLast = middle;
        //后半段最后一个数字的下标
        int rightLast = end;
        //从后向前复制数字到辅助数组,保证从小到大排序
        int indexCopy = end;
        long count = 0;
        //从后向前遍历
        while (leftLast >= start && rightLast >= middle + 1) {
            //前半段指针指向的数字大于后半段指针指向的数字
            if (data[leftLast] > data[rightLast]) {
                copy[indexCopy--] = data[leftLast--];
                //逆序对的数目等于后半段剩余数字的个数
                //因为,后半段左边的数字都小于或等于后半段指针指向的数字
                count += rightLast - middle;
            } else {
                copy[indexCopy--] = data[rightLast--];
            }
        }

        //复制子数组剩余的数字
        while (leftLast >= start) {
            copy[indexCopy--] = data[leftLast--];
        }
        while (rightLast >= middle + 1) {
            copy[indexCopy--] = data[rightLast--];
        }

        return leftCount + rightCount + count;
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,这是一个关于数组逆序重存放的问。根据引用,解代码提供了两种解法。解法一将数组存储在下标为0~n-1的位置,解法二将数组存储在下标为1~n的位置。其中,解法一的代码如下: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n, a << ' '; return 0; } ``` 解法二的代码如下: ```cpp #include <bits/stdc++.h> using namespace std; int main() { int n, a << ' '; return 0; } ``` 另外,引用和也提供了类似的代码。 综上所述,这是一个关于数组逆序重存放的问,供参考的代码包括解法一和解法二,它们分别将数组存储在不同的位置,并按逆序输出。你可以根据需求选择适合的解法进行实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [信息学奥赛一本通 1105:数组逆序重存放 | OpenJudge NOI 1.6 04:数组逆序重放](https://blog.csdn.net/lq1990717/article/details/112800322)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [信息学奥赛一本通(C++)1105:数组逆序重存放](https://blog.csdn.net/m0_63998667/article/details/130651312)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [1105:数组逆序重存放](https://blog.csdn.net/bbbb8989/article/details/127911246)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值