简介

使用了树状数组.

参考链接

https://www.cnblogs.com/xenny/p/9739600.html

TIPS

不建议看我的建议看参考链接, 因为我自己也没有很搞懂

树状数组有两个很重要的函数

int lowbit(int x){
    return x&(-x);
}

返回 x 的层数信息.

单点更新

        // 单点更新:将 index 这个位置 + 1
        public void update(int i, int delta) {
            // 从下到上,最多到 size,可以等于 size
            while (i <= this.len) {
                tree[i] += delta;
                i += lowbit(i);
            }
        }

区域查询

        // 区间查询:查询小于等于 index 的元素个数
        // 查询的语义是"前缀和"
        public int query(int i) {
            // 从右到左查询
            int sum = 0;
            while (i > 0) {
                sum += tree[i];
                i -= lowbit(i);
            }
            return sum;
        }

i -= lowbit(i); // 是什么意思呢? 个人理解, 就是 比如 4(100) 节点 覆盖范围是 1 2 3 4, 找到他前面一个区域 , 就是0,
对于 5 节点, 找到他前面的一个区域 101 - 1 = 100 (4) 就是4区域.
可以通过 + lowbit() - lowbit 找到 前面的区域 与 后面的区域.

对于此题 最后的tree为

[0, 1, 2, 1, 4];
分别对应 左右理解得映射一下
1区域有1
2区域有2(2)个元素 分别是 1 和 2
3区域有1个元素
4区域有4个元素(A1, A2,A3, A4)
因为查询的时候, 还没有填充完毕, 查询的按照未完成的样式查询(QU:其实不太懂)

查询
5261 的映射 3241

对于1的
update tree数组
011010
查询 0 得到 0

对于4
update tree 数组
011020
查询 3 和 2
得到 1

对于 2
update tree 数组
012030
查询1得到1

对于3
update tree数组
012140
此时所有的数据填充完毕, 对于3 只用查询 2
此时2为 2

GU:猜测

感觉是, 边填充, 边用树状数组查询的算法.

code

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class Solution {

    public List<Integer> countSmaller(int[] nums) {
        List<Integer> res = new ArrayList<>();
        int len = nums.length;
        if (len == 0) {
            return res;
        }

        // 使用二分搜索树方便排序
        Set<Integer> set = new TreeSet();
        for (int i = 0; i < len; i++) {
            set.add(nums[i]);
        }

        // 排名表
        Map<Integer, Integer> map = new HashMap<>();
        int rank = 1;
        for (Integer num : set) {
            map.put(num, rank);
            rank++;
        }

        FenwickTree fenwickTree = new FenwickTree(set.size() + 1);
        // 从后向前填表
        for (int i = len - 1; i >= 0; i--) {
            // 1、查询排名
            rank = map.get(nums[i]);
            // 2、在树状数组排名的那个位置 + 1
            fenwickTree.update(rank, 1);
            // 3、查询一下小于等于“当前排名 - 1”的元素有多少
            res.add(fenwickTree.query(rank - 1));
        }
        Collections.reverse(res);
        return res;
    }


    private class FenwickTree {
        private int[] tree;
        private int len;

        public FenwickTree(int n) {
            this.len = n;
            tree = new int[n + 1];
        }

        // 单点更新:将 index 这个位置 + 1
        public void update(int i, int delta) {
            // 从下到上,最多到 size,可以等于 size
            while (i <= this.len) {
                tree[i] += delta;
                i += lowbit(i);
            }
        }


        // 区间查询:查询小于等于 index 的元素个数
        // 查询的语义是"前缀和"
        public int query(int i) {
            // 从右到左查询
            int sum = 0;
            while (i > 0) {
                sum += tree[i];
                i -= lowbit(i);
            }
            return sum;
        }

        public int lowbit(int x) {
            return x & (-x);
        }
    }


    public static void main(String[] args) {
        int[] nums = new int[]{5, 2, 6, 1};
        Solution solution = new Solution();
        List<Integer> countSmaller = solution.countSmaller(nums);
        System.out.println(countSmaller);
    }
}

posted on 2021-06-13 15:36  HDU李少帅  阅读(59)  评论(0编辑  收藏  举报