給定一個整數數組 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;
}
};