剑指Offer:数组中的逆序对

剑指Offer:数组中的逆序对


题目

在这里插入图片描述

插入排序解法(复杂度过高)

这个方法不能 AC,运行结果是:
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为75.00%
然而还是写在这里吧...
在这里插入图片描述
代码如下:

class Solution {
public:
    int InversePairs(vector<int> data) {
        vector<int> sortedData(data.size(), INT_MIN);
        long long result = 0, n = 0;
        for (long long i = 0; i < data.size(); ++i) {
            result += insertSort(sortedData, n, data[i]);
            if (result >= 1000000007) result %= 1000000007;
            ++n;
        }
        return result;
    }
    long long insertSort(vector<int>& sortedData, long long n, int k) {
        long long result = 0;
        while (n > 0 && sortedData[n - 1] > k) {
            sortedData[n] = sortedData[n - 1];
            --n;
            ++result;
        }
        sortedData[n] = k;
        return result;
    }
};

归并排序解法

归并排序伪代码:

void MergeSort(vector<int>&data, int left, int right) {
	// left 和 right 表示首元素和尾(而不是尾后)元素
	if (left == right) return;
	MergeSort(data, left, (left + right) / 2);
	MergeSort(data, (left + right) / 2 + 1, right);
	Merge(data, left, right);
}
void Merge(vector<int>&data, int left, int right) {
	// end1 和 end2 也是尾(而不是尾后)元素
	int p1 = left, end1 = (left + right) / 2, p2 = end1 + 1, end2 = right;
	// 开始归并
	// 注意归并过程中应该有一个 tmp 向量用于储存排序后的 data
	// 全归并完之后再把 data 在对应位置的元素都替换成 tmp 中的值 
    // 详见后面的代码
}

归并过程中统计逆序对的原理:由于用于归并的两个数组都是有序的,在归并过程中,如果 arr1(在前面的数组)中还有元素,但是较小的数却取自 arr2(在后面的数组),就说明此时出现了逆序对:从 arr1 的当前头位置到 arr1 的结尾的每个元素与 arr2 的当前头位置元素(即这次归并操作拿出的较小数)组成的二元组都是逆序对.
在这里插入图片描述
代码:

class Solution {
public:
    int result = 0;
    int InversePairs(vector<int> data) {
        if (data.size() <= 1) return 0;
        MergeSort(data, 0, data.size() - 1);
        return result;
    }
    void MergeSort(vector<int>& data, int left, int right) {
        if (left == right)
            return;
        MergeSort(data, left, (left + right) / 2);
        MergeSort(data, (left + right) / 2 + 1, right);
        Merge(data, left, (left + right) / 2 + 1, right);
    }
    void Merge(vector<int>& data, int begin, int mid, int end) {
        int p1 = begin, p2 = mid, end1 = p2 - 1, end2 = end, n = 0;
        vector<int> sortTmp(end - begin + 1, 0);
        while (p1 <= end1 && p2 <= end2) {
            if (data[p1] < data[p2]) {
                sortTmp[n++] = data[p1];
                ++p1;
            }
            else {
                sortTmp[n++] = data[p2];
                ++p2;
                result += (end1 - p1 + 1);
                if (result > 1000000007) result %= 1000000007;
            }
        }
        if (p1 > end1)
            for (int i = p2; i <= end2; ++i) sortTmp[n++] = data[i];
        if (p2 > end2)
            for (int i = p1; i <= end1; ++i) sortTmp[n++] = data[i];
        n = 0;
        for (int i = begin; i <= end; ++i) {
            data[i] = sortTmp[n++];
        }
    }
};

还有一个坑是:
每次 result 加完值之后都要判断它是否大于 1000000007,if yes,就取模.
不要以为最后的结果 return 一个 result % 1000000007 就可以了.这会导致计算过程中 result 溢出.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值