LeetCode LCR 170. 交易逆序对的总数

文章介绍了如何利用归并排序算法解决股票交易中交易逆序对的问题,通过分治法将数组排序,然后统计在合并过程中形成的逆序对数量。时间复杂度为O(NlogN),空间复杂度为O(N)。
摘要由CSDN通过智能技术生成

LCR 170. 交易逆序对的总数

在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 record,返回其中存在的「交易逆序对」总数。

示例 1:

输入:record = [9, 7, 5, 4, 6]
输出:8
解释:交易中的逆序对为 (9, 7), (9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4)。

限制:

0 <= record.length <= 50000

解法:分而治之 归并排序

「归并排序」与「逆序对」是息息相关的。归并排序体现了 “分而治之” 的算法思想,具体为:

分: 不断将数组从中点位置划分开(即二分法),将整个数组的排序问题转化为子数组的排序问题;
治: 划分到子数组长度为 1 时,开始向上合并,不断将 较短排序数组 合并为 较长排序数组,直至合并至原数组时完成排序;

class Solution {
    int count = 0;
    public int reversePairs(int[] record) {
        mergeSort(record, 0, record.length - 1);
        return count;
    }

    private void mergeSort(int[] record, int left, int right) {
        if (left >= right) {
            return;
        }
        int mid = left + (right - left) / 2;
        mergeSort(record, left, mid);
        mergeSort(record, mid + 1, right);
        mergeTwoSortedArray(record, left, mid, right);
    }

    private void mergeTwoSortedArray(int[] record, int left, int mid, int right) {
        int length = right - left + 1;
        int[] temp = new int[length];
        for (int i = 0; i < length; i++) {
            temp[i] = record[left + i];
        }
        int l = 0;
        int r = mid + 1 - left;
        for (int i = 0; i < length; i++) {
            if (l > mid - left) {
                record[left + i] = temp[r++];
            } else if (r > right - left) {
                record[left + i] = temp[l++];
            } else if (temp[l] <= temp[r]) {
                record[left + i] = temp[l++];
            } else {
                // 因为左右两个数组都是有序(递增)的
                // 左数组的一个数 x 大于右数组的一个数 y 时,左数组的后边所有数都会大于右数组的那个数
                count += (mid - left + 1) - l;
                record[left + i] = temp[r++];
            }
        }
    }
}

另一种写法: 

class Solution {
    int count = 0;

    public int reversePairs(int[] record) {
        if (record.length == 0) {
            return 0;
        }
        int[] temp = new int[record.length];
        mergeSort(record, 0, record.length - 1, temp);
        return count;
    }

    private void mergeSort(int[] record, int left, int right, int[] temp) {
        if (left == right) {
            return ;
        }
        int mid = left + (right - left) / 2;
        mergeSort(record, left, mid, temp);
        mergeSort(record, mid + 1, right, temp);
        mergeTwoSortedArray(record, left, mid, right, temp);
    }

    private void mergeTwoSortedArray(int[] record, int left, int mid, int right, int[] temp) {
        for (int i = left; i <= right; i++) {
            temp[i] = record[i];
        }
        int l = left;
        int r = mid + 1;
        for (int i = left; i <= right; i++) {
            if (l > mid) {
                record[i] = temp[r++];
            } else if (r > right) {
                record[i] = temp[l++];
            } else if (temp[l] <= temp[r]) {
                record[i] = temp[l++];
            } else {
                count += mid - l + 1;
                record[i] = temp[r++];
            }
        }  
    }
}

复杂度分析:
时间复杂度:O(Nlog⁡N),其中 N 为数组 record 长度。
空间复杂度:O(N), 辅助数组 temp占用 O(N)大小的额外空间。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值