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;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值