给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例:
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.
链接:🔗
这道题是我用来练习树状数组的题目
发现了一些自己容易犯错的小细节:
1. 树状数组的add()函数for循环中的i的起始点要保证大于1,不能为0,如果为0的话0 & -0 还是0,就会死循环
2. 由1知树状数组的存放数组trie的下标为0的元素是不能用的,至少从1开始
本题的思路:
1.本题输入的nums数组中可能会有负数,要先将负数映射成整数,即 nums[i] - min_num + 1,最后+1是为了min_num映射为1而非0
2.因为求得是右边比其小得元素个数,所以倒着向树状数组中插入元素nums[i]
3.计算右边有多少比其小得元素得时候,计算得是get_sum(nums[i] - min_num),即get_sum()中得res不能加上trie[num[i] - min_num + 1] 因为是要算比其小的元素,也不能写成get_sum(nums[i] - min_num + 1) - 1,因为trie[num[i] - min_num + 1]不一定为1 (重点理解!!)
class Solution {
public:
int min_num = 0x3f3f3f3f,max_num;
vector<int> ans;
vector<int> trie;
int lowbit(int x){
return x & -x;
}
void add(int x,int c){
for (int i = x; i <= max_num - min_num + 1 ; i += lowbit(i))
trie[i] += c;
}
int get_sum(int x){
int res = 0;
for (int i = x; i; i -= lowbit(i))
res += trie[i];
return res;
}
vector<int> countSmaller(vector<int>& nums) {
if (nums.size() == 0) return {};
int n = nums.size();
max_num = -1 * min_num;
for (auto x:nums){
max_num = max(max_num,x);
min_num = min(min_num,x);
}
trie.resize(max_num - min_num + 10);
for (int i = n - 1; i >= 0; --i){
ans.push_back(get_sum(nums[i] - min_num));
add(nums[i] - min_num + 1,1);
}
reverse(ans.begin(),ans.end());
return ans;
}
};