• 数据结构——树状数组(区间更新、求和问题)


    假设你正在读取一串整数。每隔一段时间,你希望能找出数字 x 的秩(小于或等于 x 的值的个数)。请实现数据结构和算法来支持这些操作,也就是说:
    实现 track(int x) 方法,每读入一个数字都会调用该方法;
    实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。
    leetcode

    解题思路:这是一道树状数组地模版题。

    什么是树状数组呢?

    就是将数组元素信息整合在一些关键节点上,这样,需要获取某些信息的时候,就不需要去遍历每一个节点,只需要去检索这些关键的节点,就能把时间复杂度降到O(logn)。

    如何构建树状数组

    在这里插入图片描述
    设C即为红色节点,每个红色节点的值就是其子节点的总和。树状数组中,节点值的表达式为

    C [ i ] = A [ i − 2 k + 1 ] + A [ i − 2 k + 2 ] + . . . + A [ i ] ; C[i] = A[i - 2^k+1] + A[i - 2^k+2] + ... + A[i]; C[i]=A[i2k+1]+A[i2k+2]+...+A[i];

    k为i的二进制中从最低位到高位连续零的长度。

    其中,如何求2的k次方呢?这个方法叫做lowbit 利用计算机补码和位与的特性:x & -x;

    求和问题

    这里需要快速求某个黑色节点一下的和。通过树状数组的思想。这里的遍历步长就是lowbit。

    在添加节点的时候,就遍历他的父节点,把他们的值都加一。

    在获取值的时候,累加小于等于其值的关键节点。

    为什么每次从x + 1开始枚举呢?
    0位不用啊,因为0的lowbit还是0,这样就进入死循环了。

    class StreamRank {
        int[] nums;
        int n = 50010;
        public StreamRank() {
            nums = new int[50010];
        }
        
        public void track(int x) {
            for(int i = x + 1; i <= n; i += lowbit(i)) {
                nums[i] += 1;
            }
        }
        
        public int getRankOfNumber(int x) {
            int res = 0;
    
            for(int i = x + 1; i != 0; i -= lowbit(i)) {
                res += nums[i];
            }
    
            return res;
        }
    
        int lowbit(int x) {
        	// 获取x的最低位值 奇数就是1 偶数就是能整除这个数的最大的2的幂 0就为0
            return x & -x;
        }
    }
    
    
  • 相关阅读:
    FastDFS集群安装说明
    关于Sentaurus的日常(一)(Basics)
    关于Sentaurus的日常(三)
    记录程序运行时间之clock 函数
    Mysql 使用经验 2013
    proxy ip 收集方式总结
    操作系统的默认格式的陷阱
    VNC server 使用手记
    div body 间距
    asp.net处女作
  • 原文地址:https://www.cnblogs.com/lippon/p/14117667.html
Copyright © 2020-2023  润新知