315.计算右侧小于当前元素的个数
离散化树状数组:要计算一个区间中小于某个元素的个数和,可以先看每个元素的个数。比如,对于示例数组[5,2,6,1],就有如下散列表:
nums: 0 1 2 3 4 5 6 7 8 9
count: 0 1 1 0 0 1 1 0 0 0
要计算某个元素右侧小于它的总和,使用树状数组来存储每个元素的情况,从右到左遍历原数组,先计算出当前元素右侧小于它的元素个数,写入结果数组,再讲当前元素插入树状数组,完成遍历后,再反转结果数组,就得到了目标结果。
但是,由于数组中可能存在很大的元素,导致空间浪费很大,就需要使用离散化的方式,优化空间。
代码如下:
class Solution {
vector<int> c;
vector<int> a;
void initi(int length) {
c.resize(length,0);
}
int lowBit(int x) {
return x&(-x);
}
void Update(int pos) {
while(pos<c.size()) {
c[pos]+=1;
pos+=lowBit(pos);
}
}
int query(int pos) {
int res=0;
while(pos>0) {
res+=c[pos];
pos-=lowBit(pos);
}
return res;
}
void discretization(vector<int>& nums) {//离散化数组
a.assign(nums.begin(),nums.end());//将原数组元素全部复制到数组a中
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end())/*元素去重*/,a.end());//删除多余的元素
}
int getId(int x) {
return lower_bound/*返回数值第一个出现的位置*/(a.begin(),a.end(),x)-a.begin()+1;
}
public:
vector<int> countSmaller(vector<int>& nums) {
vector<int> res;
discretization(nums);
int n=nums.size();
initi(n+5);
for(int i=n-1;i>=0;i--) {
int id=getId(nums[i]);//求出这个数离散化后的值
res.push_back(query(id-1));//查找比这个数小的数的总和,压入结果数组
Update(id);//这个数插入树形数组中
}
reverse(res.begin(),res.end());//得到的结果是反的,需要反转数组
return res;
}
};
时间复杂度O(nlogn),空间复杂度O(n)