Open guodongxiaren opened 4 years ago
class Solution {
public:
int cnt = 0;
int merged[50001];
void merge_sort(int left, int right, vector<int>& A) {
if (left >= right) {
return;
}
int mid = (left + right) / 2;
//int mid = left + (right - left) / 2;
merge_sort(left, mid, A);
merge_sort(mid+1, right, A);
// 这是一处优化,也可以去掉
if (A[mid] <= A[mid+1]) {
return;
}
int pl = left, pr = mid+1, pm = 0;
while (pl <= mid && pr <= right) {
if (A[pl] <= A[pr]) {
merged[pm++] = A[pl++];
} else {
merged[pm++] = A[pr++];
cnt += mid - pl + 1; // 去掉这句就是普通的归并排序
}
}
while (pl <= mid) {
merged[pm++] = A[pl++];
}
while (pr <=right) {
merged[pm++] = A[pr++];
};
for (int i = 0; i < pm; i++) {
// 给原数组相应的部分排好序
A[i + left] = merged[i];
}
}
int reversePairs(vector<int>& nums) {
merge_sort(0, nums.size() -1, nums);
return cnt;
}
};
题目之外的三个要点:
本题 mid = (left + right)/ 2; 可以。 但是left + right有溢出的风险。 历史上好像有个案例,某个二分法出现过bug。
Java有 >>>
无符号右移。C++没有。
通用的解决方案是:mid = left + (right - left) / 2;
<=是稳定排序,<是不稳定排序。
连续的两个递归调用merge_sort是在分解。后面的逻辑是合并。 两个merge_sort调用完,[left, mid] [mid+1, right]两个区间已经各自有序。 如果A[mid] < A[mid+1]那么此时[left, right]也已经整体有序,不会再产生新的逆序对,也不需要再执行下面的合并逻辑!
if (A[mid] <= A[mid+1]) {
return;
}
树状数组
示例 1:
限制:
0 <= 数组长度 <= 50000
出自剑指Offer:51