zoukankan      html  css  js  c++  java
  • leetcode 315 计算右侧小于当前元素的个数

    简介

    使用了树状数组.

    参考链接

    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);
        }
    }
    
    
    Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
  • 相关阅读:
    Modernizr使用指南(转)
    使用Func<>和Action简化委托
    实现类似MVC ViewBag类型的对象
    更改服务器的SID 加入域控制器提示SID重复
    SQL SERVER 执行大于80M的SQL 脚本
    完全关闭IIS日志,包括System32下的LogFile
    MVC不用302跳转Action,内部跳转
    SHA1l加密
    获取当前时间戳
    invoke反射
  • 原文地址:https://www.cnblogs.com/eat-too-much/p/14880384.html
Copyright © 2011-2022 走看看