困难:493. 翻转对
思路
首先我想的是使用map,遍历到一个数时,统计这个数前面有多少个符合条件的数,但是这样会超时
得想新的思路,我想起了昨天使用的二分法,通过一半一半的方式来减少时间复杂度,所以这道题是不是也可以这样做呢,
答案是可以的,通过对0mid,mid+1len的递归,得到两部分的翻转对结果,然后还需要对0~len范围内的翻转对进行计算,由于左半部分和有半部分已经计算过了,并且此时已经排好序了,这时计算翻转数就很方便了,紧接着将两部分进行归并排序,形成一个有序数组,方向回溯后进行翻转数的统计。
这里记录一下超时代码
class Solution {
public:
int reversePairs(vector<int>& nums) {
map<long long,int> m;
int res = 0;
for(int i=0;i<nums.size();i++){
long long t = nums[i];
long long tar = 2*t;
// for(auto a:m){
// if(a.first > tar){
// res += a.second;
// }
// }
for(map<long long,int>::reverse_iterator rit=m.rbegin();rit!=m.rend();rit++)
if((*rit).first > tar){
res += (*rit).second;
}else
break;
if(m.count(t)==0){
m[t] = 1;
}else{
m[t]++;
}
}
return res;
}
};
归并排序代码
class Solution {
public:
int reversePairsRecursive(vector<int>& nums, int left, int right) {
if (left == right) {
return 0;
} else {
int mid = (left + right) / 2;
int n1 = reversePairsRecursive(nums, left, mid);
int n2 = reversePairsRecursive(nums, mid + 1, right);
int ret = n1 + n2;
// 首先统计下标对的数量
int i = left;
int j = mid + 1;
while (i <= mid) {
while (j <= right && (long long)nums[i] > 2 * (long long)nums[j]) j++;
ret += (j - mid - 1);
i++;
}
// 随后合并两个排序数组
vector<int> sorted(right - left + 1);
int p1 = left, p2 = mid + 1;
int p = 0;
while (p1 <= mid || p2 <= right) {
if (p1 > mid) {
sorted[p++] = nums[p2++];
} else if (p2 > right) {
sorted[p++] = nums[p1++];
} else {
if (nums[p1] < nums[p2]) {
sorted[p++] = nums[p1++];
} else {
sorted[p++] = nums[p2++];
}
}
}
for (int i = 0; i < sorted.size(); i++) {
nums[left + i] = sorted[i];
}
return ret;
}
}
int reversePairs(vector<int>& nums) {
if (nums.size() == 0) return 0;
return reversePairsRecursive(nums, 0, nums.size() - 1);
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/reverse-pairs/solution/fan-zhuan-dui-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。