问题描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
解题报告
归并排序方法
不解释。
时间复杂度:
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn)
空间复杂度:
O
(
n
)
O(n)
O(n)
BIT【参考官方答案】
【树状数组】是一种可以动态维护序列前缀和的数据结构,它的功能是:
- 单点更新
update(i,v)
:将序列i
位置的数加上一个值v
,这题v
=1 - 区间查询
query(i)
:查询序列[1···i]
区间的区间和,即i
位置的前缀和
修改和查询的时间代价都是 O ( l o g n ) O(log n) O(logn),其中n
为需要维护前缀和的序列的长度。
创建一个数组 tree
,其中 tree[i]
存储的是数值 i
在数组 nums
中出现的次数。
从 nums
的末尾开始遍历,计算 tree[nums[i]]-1
位置的前缀和,然后将 tree[nums[i]]
加 1
。
时间复杂度:离散化时进行排序,时间代价为
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn),单次二分的时间代价为
O
(
l
o
g
n
)
O(log n)
O(logn),一共有
n
n
n次,总时间代价为
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn);循环执行
n
n
n 次,每次进行
O
(
l
o
g
n
)
O(log n)
O(logn) 的修改和
O
(
l
o
g
n
)
O(log n)
O(logn) 的查找,总时间代价为
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn)。故渐进时间复杂度为
O
(
n
l
o
g
n
)
O(nlog n)
O(nlogn)
空间复杂度:树状数组需要使用长度为 n
的数组作为辅助空间,故渐进时间复杂度为
O
(
n
)
O(n)
O(n)
实现代码
归并排序实现
class Solution {
private:
int cnt=0;
public:
void mergesort(int lo,int hi,vector<int>& nums,vector<int>& tmp){
if(lo>=hi) return;
int mid=lo+(hi-lo)/2;
mergesort(lo,mid,nums,tmp);
mergesort(mid+1,hi,nums,tmp);
int i=lo,j=mid+1;
for(int k=lo;k<=hi;k++){
if(i>mid) tmp[k]=nums[j++];//nums[i]到nums[mid]已经全部填入tmp
else if(j>hi) tmp[k]=nums[i++];//nums[mid+1]到nums[j]已经全部填入tmp
else if(nums[i]>nums[j]) {
tmp[k]=nums[j++];
cnt+=mid-i+1;//i肯定小于j,且nums[i]到nums[mid]是升序排序,如果nums[i]>nums[j],说明从nums[i]到nums[mid]和nums[j]都是逆序对
}
else tmp[k]=nums[i++];
}
for(int m=lo;m<=hi;m++) nums[m]=tmp[m];//
}
int reversePairs(vector<int>& nums) {
vector<int> tmp(nums.size(),0);//就是用来记录某个递归函数merge后的情况,然后复制更新nums
mergesort(0,nums.size()-1,nums,tmp);
return cnt;
}
};
BIT实现
class BIT {
private:
vector<int> tree;
int n;
public:
BIT(int _n): n(_n), tree(_n + 1) {}
static int lowbit(int x) {
return x & (-x);
}
int query(int x) {
int ret = 0;
while (x) {
ret += tree[x];
x -= lowbit(x);
}
return ret;
}
void update(int x) {
while (x <= n) {
++tree[x];
x += lowbit(x);
}
}
};
class Solution {
public:
int reversePairs(vector<int>& nums) {
int n = nums.size();
vector<int> tmp = nums;
// 离散化
sort(tmp.begin(), tmp.end());
for (int& num: nums) {
num = lower_bound(tmp.begin(), tmp.end(), num) - tmp.begin() + 1;
}
// 树状数组统计逆序对
BIT bit(n);
int ans = 0;
for (int i = n - 1; i >= 0; --i) {
ans += bit.query(nums[i] - 1);
bit.update(nums[i]);
}
return ans;
}
};
参考资料
[1] Leetcode 46. 全排列
[2] 题解区:guanzhanyi
[3] 题解区:官方答案