一、剑指Offer 51 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
这里的思路主要就是利用了归并的思想,举个例子,对于[1,4,5,7] ,[2,3,6,8]这两个待归并的序列,
当a[i] > a[j]
的时候 显然 [i, m]
这个闭区间的所有元素都大于a[j]
,此时可以将j
为2时候的逆序对全部加入,个数为 m - i + 1
,当i > m
的时候对于当前的j
来说就没有逆序对了。
还有一种思路是当a[i] <= a[j]
的时候,对于i来说[m+1, j - 1]
这个闭区间的所有元素都是小于a[i]
的,数量为j - m - 1
,在 j > r
的时候对于当前i
之后位置的每个元素来说都有j - m - 1 也等于r - m
个逆序对。这种方式计算的就是对于当前的i,他右边的逆序对的个数,这个思想下一道题会用到。
class Solution {
int m_count;
public:
int reversePairs(vector<int>& nums) {
m_count = 0;
mergeSort(nums, 0, nums.size() - 1);
return m_count;
}
void merge(vector<int>& a, int l, int m, int r) {
int i = l, j = m + 1;
vector<int> aux(r - l + 1);
for(int k = 0; k < r - l + 1; k++) {
if(i > m) {
aux[k] = a[j++];
}
else if(j > r) {
//m_count += j - m - 1;
aux[k] = a[i++];
}
else if(a[i] <= a[j]) {
//m_count += j - m - 1;
aux[k] = a[i++];
}
else {
m_count += (m - i + 1);
aux[k] = a[j++];
}
}
// while (i <= m && j <= r){
// if(a[i] <= a[j]){
// aux[k++] = a[i++];
// }else {
// aux[k++] = a[j++];
// m_count = m_count + (m - i + 1);
// }
// }
// while (i <= m){
// aux[k++] = a[i++];
// }
// while (j <= r){
// aux[k++] = a[j++];
// }
::copy(aux.begin(), aux.end(), a.begin() + l);
}
void mergeSort(vector<int>& a, int l, int r) {
if(l >= r) return;
int m = l + (r - l) / 2;
mergeSort(a, l, m);
mergeSort(a, m + 1, r);
merge(a, l, m, r);
}
};
二、LeetCode 315 计算右侧小于当前元素的个数
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
输入:nums = [5,2,6,1]
输出:[2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
提示:
0 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
这道题有个比较特殊的地方是要返回原来每个位置元素右边逆序的个数,由于在归并的过程中某个元素的下标会不断改变,那么可以思考这样的思路:将每个元素和他的初始下标用pair关联起来,在交换元素的时候就可可以查看到原始的下标,再根据上题目的第二种思路就可以得到某个元素i
右边的逆序数的个数。
class Solution {
vector<pair<int, int>> m_vpairs;
public:
vector<int> countSmaller(vector<int>& nums) {
int n = nums.size(), l = 0, r = n - 1;
vector<int> ans(n);
for(int i = 0; i < n; i++){
m_vpairs.push_back({nums[i], i});
}
mergeSort(nums, ans, l, r);
return ans;
}
void merge(vector<int>& ans, int l, int m, int r) {
int i = l, j = m + 1;
vector<pair<int, int>> sort_vpairs(r - l + 1);//为了节约时间,每次不必复制整个数组,只需要复制待归并的区间就行
for(int k = 0; k < r - l + 1; k++){
if(i > m) {
sort_vpairs[k] = m_vpairs[j++];
}
else if(j > r) {
ans[m_vpairs[i].second] += j - m - 1;
sort_vpairs[k] = m_vpairs[i++];
}
else if(m_vpairs[i].first <= m_vpairs[j].first) {
ans[m_vpairs[i].second] += j - m - 1;
sort_vpairs[k] = m_vpairs[i++];
}
else{
sort_vpairs[k] = m_vpairs[j++];
}
}
::copy(sort_vpairs.begin(), sort_vpairs.end(), m_vpairs.begin() + l);
}
void mergeSort(vector<int>& nums, vector<int>& ans, int l, int r) {
if(l >= r) return;
int m = l + (r - l) / 2;
mergeSort(nums, ans, l, m);
mergeSort(nums, ans, m + 1, r);
merge(ans, l, m, r);
}
};