315、计算右侧小于当前元素的个数

  1. 315、计算右侧小于当前元素的个数
    1. 示例:
  2. 题解
    1. 1、暴力
    2. 2、离散化树状数组
      1. 树状数组
      2. 转化成动态维护前缀和问题
      3. 离散化优化空间

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 个更小的元素.

链接:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self

题解

求逆序数问题,可以用归并排序统计总数。

1、暴力

时间复杂度:$O(n^2)$,显然超时!!!

class Solution {
    public List<Integer> countSmaller(int[] nums) {
        // 暴力
        int len = nums.length;
        int[] count = new int[len];
        for (int i = len - 1;i >= 0;i--) {
            count[i] = 0;
            // 存在重复计算
            for (int j = len - 1;j > i;j--) {
                if (nums[i] > nums[j]) {
                    count[i]++;
                }
            }
        }
        ArrayList<Integer> res = new ArrayList<>();
        for (int c : count) {
            res.add(c);
        }
        return res;
    }
}

2、离散化树状数组

树状数组

树状数组 是一种可以动态维护序列前缀和的数据结构,它的功能是:

  • 单点更新 update(i,v):把序列i的位置的数加上一个值v,在该题中v = 1
  • 区间查询 query(i):查询序列[1...i]区间的区间和,即i位置的前缀和

修改和查询的时间代价是$O(logn)$,其中n为需要维护前缀和的序列长度

转化成动态维护前缀和问题

前缀和counnt[i]表示:nums[i]之后小于nums[i]数量总和

离散化优化空间

  • 值域映射
class Solution {
    private int[] c;
    private int[] a;

    public List<Integer> countSmaller(int[] nums) {
        List<Integer> resultList = new ArrayList<Integer>();
        discretization(nums);
        init(nums.length + 5);
        for (int i = nums.length - 1;i >= 0;--i) {
            int id = getId(nums[i]);
            resultList.add(query(id-1));
            update(id);
        }

        Collections.reverse(resultList);
        return resultList;
    }

    // 初始化前缀和
    private void init(int length) {
        c = new int[length];
        Arrays.fill(c,0);
    }

    private int lowBit(int x) {
        // -x <==> (~x + 1)
        return x & (-x);
    }

    private void update(int pos) {
        while(pos < c.length) {
            c[pos] += 1;
            pos += lowBit(pos);
        }
    }

    private int query(int pos) {
        int ret = 0;
        while (pos > 0) {
            ret += c[pos];
            pos -= lowBit(pos);
        }

        return ret;
    }

    private void discretization(int[] nums) {
        // hash表去重
        Set<Integer> set = new HashSet<Integer>();
        for (int num : nums) {
            set.add(num);
        }

        int size = set.size();
        a = new int[size];
        int index = 0;
        for (int num : set) {
            a[index++] = num;
        }

        Arrays.sort(a);
    }

    private int getId(int x) {
        return Arrays.binarySearch(a,x) + 1;
    }
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

💰

Title:315、计算右侧小于当前元素的个数

Count:639

Author:攀登

Created At:2020-07-26, 00:19:44

Updated At:2024-06-15, 15:52:32

Url:http://jiafeimao-gjf.github.io/2020/07/26/315%E3%80%81%E8%AE%A1%E7%AE%97%E5%8F%B3%E4%BE%A7%E5%B0%8F%E4%BA%8E%E5%BD%93%E5%89%8D%E5%85%83%E7%B4%A0%E7%9A%84%E4%B8%AA%E6%95%B0/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

×

Help us with donation