LeetCode 剑指51 用归并排序求逆序对个数

本文详细解析了如何通过归并排序算法解决LeetCode 51题——数组中逆序对的数量。讲解了逆序对的概念,以及在归并过程中如何计数逆序对,以示例[7,5,6,4]为例演示算法过程,最终输出5个逆序对。

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

  • 逆序对问题 leetCode 剑指51
  • 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
  • 输入一个数组,求出这个数组中的逆序对的总数。
  • 输入: [7,5,6,4]
  • 输出: 5
  • 思路: 在归并排序的过程中就能得到逆序对个数 如果在合并数组的过程中 右数组当前的数字小于 左数组当前的数字
  • 那么左数组从当前的数字 一直到结束 都与右数组形成逆序对
  • 例如 [7,5,6,4]
  • 在叶子节点合并后为可得逆序对:[7,5] [6,4]
  • 然后[5,7] [4,6]合并的时候4小于5 故5之后所有数字都与4组成逆序对 即[5,4] [7,4]
  • 同理可得[7,6]
  • 所以全部逆序对个数为[7,5] [6,4] [5,4] [7,4] [7,6] 5个
public class Solution {

    public int reversePairs(int[] nums) {

        int[] temp = new int[nums.length];
        return sort(nums, 0, nums.length-1, temp);
    }

    // 分为两个数组 [l , (l+r)/2] 和 [(l+r)/2+1, r] 前闭后闭
    private static int sort(int[] arr, int l, int r, int[] temp) {
        if (l >= r) {
            return 0;
        }
        int res = 0;
        int mid = (l + r) / 2;

        // 左右数组递归完 返回逆序对个数
        res += sort(arr, l, mid, temp);
        res += sort(arr, mid+1, r, temp);

        if (arr[mid] > arr[mid+1]) {
            // 合并完返回逆序对个数
            res += merge(arr, l, mid, r, temp);
        }
        return res;
    }

    // 合并两数组
    private static int merge(int[] arr, int l, int mid, int r, int[] temp) {

        System.arraycopy(arr, l, temp, l, (r-l)+1);
        int i = l, j = mid+1, res = 0;

        for (int k = l; k <= r; k++) {
            if (i > mid) {
                arr[k] = temp[j];
                j++;
            } else if (j > r) {
                arr[k] = temp[i];
                i++;
            } else if (temp[i] <= temp[j]) {
                arr[k] = temp[i];
                i++;
            } else {
                // 只有当右数组当前元素小于左数组当前元素时候才会产生逆序对
                // 逆序对个数为 左数组当前元素(含当前元素)之后的所有元素 即为(mid-i+1)
                res += mid - i + 1;
                arr[k] = temp[j];
                j++;
            }
        }
        return res;
    }

    public static void main(String[] args) {
        int[] arr = {7,5,6,4};
        System.out.println(new Solution().reversePairs(arr));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值