题目链接: leetcode.
这种0 <= 数组长度 <= 50000的O(N^2)一般都会超时,下次不用试了
/*
暴力 超时 35 / 139 个通过测试用例
*/
class Solution {
public:
int reversePairs(vector<int>& nums) {
int N = nums.size();
int ans = 0;
for(int i = 0;i < N;++i)
{
for(int j = 0;j < i;++j)
{
if(nums[j] > nums[i])
ans++;
}
}
return ans;
}
};
分治法
- 时间复杂度O(nlogn)
- 空间复杂度O(n)
利用归并排序
merge(num, left, right)
1) 将其分解为递归调用merge(num, left, mid)对左半边排序
2) 递归调用merge(num, mid+1, right)对右半边排序
3) 合并各自有序的两边在合并时,使用两个指针
i,j分别指向左右两边需要合并的数 如果num[i] < num[j],把num[i]放入合并数组的正确位置
否则,num[j]放入正确位置,此时num[i]到num[mid]的数都比num[j]大, 其位置也在num[j]之前,所以共会构成(mid - i + 1)个逆序对
/*
执行用时:420 ms, 在所有 C++ 提交中击败了25.90%的用户
内存消耗:106.1 MB, 在所有 C++ 提交中击败了19.80%的用户
*/
class Solution {
public:
int mergee(vector<int>& nums, int left, int right)
{
if(left >= right) //如果相等(指向同一个数)或大于(0,-1)返回0
return 0;
int mid = left + (right - left) / 2;
//左半边包含的逆序对
int cnt_left = mergee(nums, left, mid);
//右半边包含的逆序对
int cnt_right = mergee(nums, mid + 1, right);
//合并
vector<int> tmp(right - left + 1);//临时数组存放合并后的正确顺序
int i = left, j = mid + 1;
int cnt = 0;
for(int k = 0;k < right - left + 1;++k)
{
//边界判断,i,j不能超出范围
if(i == mid + 1)//左边合并完毕,只剩右边
{
tmp[k] = nums[j];
j++;
}
else if(j == right + 1)//右边合并完毕,只剩左边
{
tmp[k] = nums[i];
i++;
}
//边界合法,才进行比较
else if(nums[i] <= nums[j])//用等于,保证稳定排序
{
tmp[k] = nums[i];
i++;
}
else
{
tmp[k] = nums[j];
j++;
cnt += mid - i + 1;
}
}
//将合并好的数组覆盖nums
for(int i = 0, j = left;j <= right;++i,++j)
{
nums[j] = tmp[i];
}
//返回逆序对个数 左边+右边+合并时两者中间出现的
return cnt_left + cnt_right + cnt;
}
int reversePairs(vector<int>& nums) {
int N = nums.size();
return mergee(nums, 0, N - 1);
}
};
还有树状数组的解法,没看,下次遇到再研究吧orz
本文介绍了一种解决LeetCode上逆序对问题的有效方法。通过对数组进行分治法处理,采用归并排序的思想,实现了O(nlogn)的时间复杂度。文中详细解释了如何在合并过程中计算逆序对的数量,并附带了C++代码实现。
505

被折叠的 条评论
为什么被折叠?



