题目:计算右侧小于当前元素的个数
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
/*
使用前缀和的解法,但是需要对原始的数据做一些处理
1、反转后的数组,nums 倒叙反转所得,因为倒叙输入才能转换为前置的 前缀和数组
2、排序后的数组,排序时重复元素归类为同一个,所以排序后的总元素个数是小于等于原始的数组元素个数的
3、频率数组,依次遍历反转后的数组,按照排序数组记录的前后关系,得到前缀和数组
4、前缀和数组,根据频率数组所得,频率数组记录的是频次,
5、最后的输出结果,是倒序的前缀和数组
注意这里的频率数组仅记录次序,因为如果直接使用元素值的话,值会非常大,使内存爆掉
*/
// 树状数的类原封不动的搬过来
class FenwickTree
{
public:
// 5、这个忘了写了,构造函数,初始化对象要用的呀,没有构造函数怎么可以的呐~~
// 注意这里使用 初值列 的方式进行初始化
FenwickTree (int n) : sums_(n + 1, 0){};
// 3、定义 update tree
void update (int i, int val)
{
while(i < sums_.size())
{
sums_[i] += val;
i += lowbit(i);
}
}
// 4、定义 query tree
// 错误之处:没有加const
int query (int i) const
{
int sum = 0;
while(i > 0)
{
sum += sums_[i];
i -= lowbit(i);
}
return sum;
}
private:
// 1、定义一个私有成员 用来存储部分和
vector<int> sums_;
// 2、定义求 二进制最低有效位 的函数
// 错误之处:这里写的没加 静态和内联
static inline int lowbit(int x)
{
return x & (-x);
}
};
class Solution {
public:
vector<int> countSmaller(vector<int>& nums)
{
// 1、单一不重复元素排序,选用 set 容器,可以直接去重
set<int> sorted(nums.begin(), nums.end());
// 2、对排序后的数组,进行序号的标定,存储为一个 哈希映射,key 对应元素值, value是下标也就是大小的次序
unordered_map<int, int> ranks;
// 3、很妙的处理,set容器的遍历,用range-for,这里就不能是通过下标来进行遍历访问了
int rank = 0;
for(const int num : sorted)
{
ranks[num] = ++rank; // 顺序依次为 1,2,3,4,5... sorted.size()
}
vector<int> ans;
// 4、实例化一个树状数对象,并将树的节点个数初始化为 排序后的数组的个数
FenwickTree tree(ranks.size());
// 5、倒叙遍历 nums 数组
for (int i = nums.size() - 1; i >= 0; --i)
{
// 先查询树中有多少元素是比目前的值小的,就把它插入结果中
ans.push_back(tree.query(ranks[nums[i]] - 1)); // 因为树的下标从1开始,所以需要 -1
// 将这个值早 rank 中的排名在树中更新,也就是前缀和的更新
tree.update(ranks[nums[i]], 1); //这里的更新也就是做 +1 的操作
}
reverse(ans.begin(), ans.end());
return ans;
}
};