LeetCode 315. 計算右側小於當前元素的個數(樹狀數組)

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章