1.LeetCode:剑指 Offer 51. 数组中的逆序对
在数组中的两个数字,
如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
经典题目了,树状数组,线段树,归并排序等等做法都适用于这题。因为该题涉及到了单点修改和区间查询,所以用来练习线段树是十分合适的。
做法就很简单了,先把数组中的各个元素离散化后,从后往前先去查询该元素之前的区间比他小的元素个数然后再将其插入即可。本题l,r可以不存储,当然存储了也是没问题的。
标准的线段树版本:
const int maxn=5e4+10;
class Solution {
vector<int> idx;
struct node{
int l,r;
int sum;
}tr[4*maxn];
int get_idx(int x){
int l=0,r=idx.size()-1;
while(l<=r){
int mid=l+((r-l)>>1);
if(idx[mid]==x) {
return mid;
}else if(idx[mid]>x){
r=mid-1;
}else l=mid+1;
}
return -1;
}
int getval(int x){
return idx[x];
}
void push_up(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
/*void push_down(u){
tr[u<<1].sum+=tr[u].add;
tr[u<<1|1].sum+=tr[u].add;
tr[u].add=0;
}*/
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
if(l==r){
tr[u].sum=0;
return ;
}else {
int mid=l+((r-l)>>1);
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
}
void modify(int u,int x,int v){
if(tr[u].l==x&&tr[u].r==x) {
tr[u].sum+=v;
return ;
}else {
int mid=(tr[u].l+tr[u].r)>>1;
//push_down(u);
if(x<=mid) modify(u<<1,x,v);
if(x>mid) modify(u<<1|1,x,v);
push_up(u);
}
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].sum;
}
int ans=0;
int mid=(tr[u].l+tr[u].r)>>1;
//push_down(u);
if(r<=mid)return query(u<<1,l,r);
if(l>mid) return query(u<<1|1,l,r);
push_up(u);
return query(u<<1,l,r)+query(u<<1|1,l,r);
}
unordered_map<int,int> map;
public:
int reversePairs(vector<int>& nums) {
if(nums.size()==0){
return 0;
}
for(auto i:nums){
idx.push_back(i);
}
sort(idx.begin(),idx.end());
idx.erase(unique(idx.begin(),idx.end()),idx.end());
for(int i=0;i<idx.size();++i){
map[idx[i]]=i+1;
}
int n=idx.size();
int ans=0;
build(1,1,n);
for(int i=0;i<nums.size();++i){
int idex=map[nums[i]];
if(idex+1<=n)ans+=query(1,idex+1,n);
modify(1,idex,1);
}
return ans;
}
};
针对该题的版本:
class Solution {
#define maxn 50010
vector<int> idx;
struct node{
int sum;
}tr[4*maxn];
int get_idx(int x){
int l=0,r=idx.size()-1;
while(l<=r){
int mid=l+((r-l)>>1);
if(idx[mid]==x) {
return mid;
}else if(idx[mid]>x){
r=mid-1;
}else l=mid+1;
}
return -1;
}
int getval(int x){
return idx[x];
}
void push_up(int u){
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
/*void push_down(u){
tr[u<<1].sum+=tr[u].add;
tr[u<<1|1].sum+=tr[u].add;
tr[u].add=0;
}*/
void build(int u,int l,int r){
if(l==r){
tr[u].sum=0;
}else {
int mid=l+((r-l)>>1);
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
push_up(u);
}
}
void modify(int u,int l,int r,int x){
if(x<l||x>r) return ;
if(l==r) {
tr[u].sum++;
return ;
}
int mid=(l+r)>>1;
//push_down(u);
modify(u<<1,l,mid,x);
modify(u<<1|1,mid+1,r,x);
push_up(u);
}
void query(int u,int l,int r,int ql,int qr,int& ans){
if(qr<l||ql>r) return;
if(ql<=l&&r<=qr){
ans+=tr[u].sum;
return ;
}
int mid=(l+r)>>1;
//push_down(u);
query(u<<1,l,mid,ql,qr,ans);
query(u<<1|1,mid+1,r,ql,qr,ans);
push_up(u);
}
public:
int reversePairs(vector<int>& nums) {
if(nums.size()==0){
return 0;
}
for(auto i:nums){
idx.push_back(i);
}
sort(idx.begin(),idx.end());
idx.erase(unique(idx.begin(),idx.end()),idx.end());
for(int i=0;i<nums.size();++i){
nums[i]=get_idx(nums[i]);
}
int l=0,r=nums.size()-1;
int ans=0;
build(1,l,r);
for(int i=nums.size()-1;i>=0;--i){
int sum=0;
query(1,l,r,0,nums[i]-1,sum);
ans+=sum;
modify(1,l,r,nums[i]);
}
return ans;
}
};