Leetcode--Java--315. 计算右侧小于当前元素的个数

题目描述

给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

样例描述

示例 1:

输入:nums = [5,2,6,1]
输出:[2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (21)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
示例 2:

输入:nums = [-1]
输出:[0]

思路

树状数组 (动态维护前缀和数组)
树状数组主要两个功能:①给某个位置加一个数 ②求1~x的前缀和
修改和查询的代价都是O(logn)

  1. 将数组的值作为至于,对应value记录这个数出现的次数。
    在这里插入图片描述
  2. 从后往前遍历(因为是找右边,所以从右边开始),比某个数x小的数的个数就相当于x - 1的前缀和(value统计的都是个数),之后将x的个数加一。这样能实现动态维护前缀和数组(记录个数)
  3. **细节:**树状数组是从1开始的,这里数的范围是-10000到10000,所以可以将数加上10001,让范围变成1~20001。
  4. int[]数组转list,要么遍历一遍一个个加入到list。要么用流来包装然后转化为list。如果用Arrays.asList(),要用Integer数组表示

代码

class Solution {
    
    
    int tree[];
    int n = 20001;
    public int lowbit(int x) {
    
    
        return x & (-x);
    }
    public int query(int x) {
    
    
        int ans = 0;
        for (int i = x; i > 0; i -= lowbit(i)) {
    
    
             ans += tree[i];
        }
        return ans;
    }
    public void add(int x, int u) {
    
    
        for (int i = x; i <= n; i += lowbit(i)) {
    
    
            tree[i] += u;
        }
    }
    public List<Integer> countSmaller(int[] nums) {
    
    
        tree = new int[n + 1];
         int len = nums.length;
        int res[] = new int[len];
        for (int i = len - 1; i >= 0; i --) {
    
    
            //加上偏移10001 使得从1开始
               int x = nums[i] + 10001;
               res[i] = query(x - 1);
               //将x的个数加一,动态维护前缀和数组
               add(x, 1);
        }
        //int数组转化为list要包装成Integer[]
    return Arrays.stream(res).boxed().collect(Collectors.toList());
    }
}

猜你喜欢

转载自blog.csdn.net/Sherlock_Obama/article/details/121739795