在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 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(NlogN),其中 N 为数组 record 长度。
空间复杂度:O(N), 辅助数组 temp占用 O(N)大小的额外空间。