树状数组(一)

news2025/1/11 8:54:08

文章目录

  • 前言
  • 一、树状数组简介
  • 二、树状数组的原理与相应模块
  • 三、实战演练
    • 3.1 区域和检索 - 数组可修改
      • 3.1.1 题目链接
      • 3.1.2 题目描述
      • 3.1.3 题目代码
      • 3.1.4 解题思路
    • 3.2 数字流的秩
      • 3.2.1 题目链接
      • 3.2.2 题目描述
      • 3.2.3 题目代码
      • 3.2.4 解题思路
  • 总结


前言

给定一段数字,需要求前缀和和修改其中的数字,使用数组进行前缀和初始化和暴力修改在数据量很大的情况下已经不满足我们的需求,此时便需要树状数组来帮助我们解决问题。那么什么是树状数组呢,本篇文章将通过概念+实战的方式,让读者了解树状数组的概念与用法。


一、树状数组简介

树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为Fenwick树。现多用于高效计算数列的前缀和, 区间和。

二、树状数组的原理与相应模块

例子引入:假如我们需要计算数字1、5、7、9、3、4、5、8的前缀和,区间和并且修改其中的元素,我们该如何利用树状数组来解决问题呢?

先看一幅图片:
在这里插入图片描述
如图所示,我们可以利用最上面的数组来对这8个数字来进行所需要的操作,为什么是这8个数字,首先我们要知晓这8个数字怎么来的。
(1) 我们要知晓数字1、5的和,我们直接可以通过1+5得到。这是暴力的做法,在树状数组中我们可以通过22直接得到。

(2) 如果想要得到1、5、7、9的和,我们可以根据1+5+7+9得到,也可以根据6+16得到,那么我们肯定选择6+16,因为操作的数很少。当然在树状数组中,我们自然可以通过22。

(3) 那我们想要得到1+5+7呢,根据树状数组,我们可以通过6+7来得到。这个时候我们会发现一个规律,在树状数组下面的每一行,偶数的矩形不被我们需要,去掉之后正好剩余8个矩形,组成我们的树状数组。

通过上述所描述,我们可以通过这8个数组成的树状数组得到任意的区间和。那么首先我们要知晓,如何用这8个数字建立树状数组呢。

我们观察树状数组,第一个元素在数组下标为1的位置(不是下标为0)。而1的二进制形式为1。那么我们可以很容易知晓1的二进制最低位为第一位,即该树状数组元素包含了a[1]计算出来的。因为二进制中只有一位,所以该树状数组的第一个元素即为原来数组中的一个元素。

那么树状数组中的3#元素呢,3的二进制最低位为1,所以存储的即为长度为1的元素,即为原来数组中的7。

有了上面的性质,我们就来尝试如何从原来的数组建立树状数组。遍历原来的数组nums,得下标为i(从0开始一直到7)。
那么我们称建立的树状数组为Fenwick[10]。
建立过程为

(1) 首先我们要知道一个lowbit函数,用来求一个数字的最低位的。

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

探论其原理,设一个数的八位二进制位X XXXXXXX
5的二进制形式为 0 0000101
-5是5进行按位取反+1 即为 1 1111011
则进行位运算则为1,即为最位了。

(2) 接着进行建树过程

void build(vector<int> &nums, vector<int> &Fenwick){
	for(int i = 0; i < nums.size(); ++i){
		int index = i+1;
		while(index <= 8){
			Fenwick[index] += nums[i];
			index += lowbit(index); 
		}
	}
}

(3) 那我们我们怎么求出前x个元素的和呢。
还是回到例子中,我们想要前7个元素,取得的是树状数组中的7#,6#,4#。即为7依次减去二进制最低位的结果。
7 - 0 = 7;
7 - 1 = 6;
6 - 2 = 4;
4 - 4 = 0;

int calculate(vector<int> &Fenwick, int k){
	int ret = 0;
	while(k > 0){
		ret += Fenwick[k];
		k -= lowbit(k);
	}
return ret;
}

(4) 如果第几个元素修改了,参考建树过程对相应的树状数组中的元素进行计算即可。

(5) 如果求的是第4个到第7个元素之和,相当于求的是前7个元素和 减去 前3个元素之和。

三、实战演练

3.1 区域和检索 - 数组可修改

3.1.1 题目链接

点击跳转到题目位置

3.1.2 题目描述

给你一个数组 nums ,请你完成两类查询。

其中一类查询要求 更新 数组 nums 下标对应的值
另一类查询要求返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 ,其中 left <= right
实现 NumArray 类:

  • NumArray(int[] nums) 用整数数组 nums 初始化对象
  • void update(int index, int val) 将 nums[index] 的值 更新 为 val
  • int sumRange(int left, int right) 返回数组 nums 中索引 left 和索引 right 之间( 包含 )的nums元素的 (即,nums[left] + nums[left + 1], …, nums[right])

3.1.3 题目代码

class NumArray {
    vector<int> Fenwick;
    vector<int> num;
    int n ;
    int lowbit(int x){
        return x&(-x);
    }

public:
    NumArray(vector<int>& nums) {
        num = nums;
        n = nums.size();
        Fenwick.resize(n+1);
        for(int i = 0; i < n; ++i){
            int index = i + 1;
            while(index <= n){
                Fenwick[index] += nums[i];
                index += lowbit(index);
            }
        }
    }
    
    void update(int index, int val) {
        int change = (val - num[index]);
        num[index] = val; 
        index++;
        while(index <= n){
            Fenwick[index] += change; 
            index += lowbit(index); 
        }
    }
    
    int calculate(vector<int> &Fenwick, int k){
	    int ret = 0;
	    while(k > 0){
		    ret += Fenwick[k];
		    k -= lowbit(k);
	    }
    return ret;
    }

    int sumRange(int left, int right) {
        return calculate(Fenwick, right+1) - calculate(Fenwick, left);    
    }
};

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray* obj = new NumArray(nums);
 * obj->update(index,val);
 * int param_2 = obj->sumRange(left,right);
 */

3.1.4 解题思路

(1) 这是一道典型的树状数组的模板题,与概念中所指出的背景相同。所以只需要完整套用树状数组的模板即可。

3.2 数字流的秩

3.2.1 题目链接

点击跳转到题目位置

3.2.2 题目描述

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

实现 track(int x) 方法,每读入一个数字都会调用该方法;

实现 getRankOfNumber(int x) 方法,返回小于或等于 x 的值的个数。

注意:本题相对原题稍作改动

3.2.3 题目代码

class StreamRank {
    vector<int> Fenwick;
public:
    int lowbit(int x){
        return x&(-x);
    }

    StreamRank() {
        Fenwick.resize(50010);
    }
    
    void track(int x) {
        x++;
        while(x <= 50001){
            Fenwick[x]++;
            x += lowbit(x); 
        }
    return ;
    }
    
    int getRankOfNumber(int x) {
        int ans = 0;
        x++;
        while(x > 0){
            ans += Fenwick[x];
            x -= lowbit(x);
        }
        return ans;
    }
};

/**
 * Your StreamRank object will be instantiated and called as such:
 * StreamRank* obj = new StreamRank();
 * obj->track(x);
 * int param_2 = obj->getRankOfNumber(x);
 */

3.2.4 解题思路

(1) 这道题目也可以作为树状数组的模板题,只不过与前面概念中所说的有变化。概念中数组中的数换成了0~50000,即在梳妆数组中要安排下标1到50001的位置。原来树状数组所求的前缀和变成了小于x的元素有多少个。

(2) 每次插入数字x即在树状数组中的相应位置增加一个原来数组中下标为x+1的元素。

(3) 要找树状数组中小于数字x的元素,即求前面0到x-1数字有多少个。即套用原来求前缀和的公式即可。


总结

相信读者读完了,对于树状数组有了相应的理解,当读者尝试去完成LeetCode上树状数组的两道例题,便能对树状数组的实际应用有了一个深刻的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/558594.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多元回归预测 | Matlab麻雀算法(SSA)优化BP神经网络回归预测,SSA-BP回归预测,多变量输入单输出模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | 麻雀算法(SSA)优化BP神经网络回归预测,SSA-BP回归预测,多变量输入单输出模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %-------------…

Windows10家庭版安装WSL

记录Windows10家庭版安装linux子系统WSL 查看自己的windows版本是否支持安装wsl2&#xff0c;cmd里输入ver查看。 系统版本&#xff1a;Windows 10 1903及以上版本。 系统内部版本&#xff1a; 18362及以上。 启用适用于Linux的windows子系统 右键命令提示符&#xff0c;以管…

小航编程题库2022年NOC决赛图形化(小低组)(含题库教师账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;_程序猿下山的博客-CSDN博客 单选题3.0分 删除编辑 答案:C 第1题对小猫编程&#xff0c;程序运行后&#xff0c;看到的小猫最终方向是多少&#xff1f; A、120B…

Compose二三事:初步认识

Compose 是什么&#xff1f; Compose是Jetpack系列中用于构建原生Android界面的工具库&#xff0c;Jetpack是Google推出的一系列帮助开发者规范代码的库。简单来说就是用代码写UI&#xff0c;也就是声明式UI。 声明式UI和命令式UI的区别在于&#xff0c;声明式UI更关心做什么&…

Python系列模块之标准库re详解

感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01; 目录 一、Python 正则表达式 1.1 re模块常用操作 1.2 re.match 1.3 re.search 1.4 re.findall 1.5 re.compile 函数 1.6 re.sub 检索和替换 1.7 re.split拆分 1.8 实战案例&#xff1a;根据文…

多看一眼多进步,python入门到放弃

python相关工具都安装完成后&#xff0c;就可以开始学习了&#xff0c;以下在pycharm中&#xff0c;以下学习内容来自b站边学习边整理的笔记&#xff0c;好记性不如赖笔头&#xff0c;多总结多记录&#xff0c;总是不错的 print()函数的使用 print函数可以输出哪些内容 &…

华为OD机试真题 Java 实现【优雅数组】【2023Q1 200分】

一、题目描述 如果一个数组中出现次数最多的元素出现大于等于k次&#xff0c;被称为k-优雅数组&#xff0c;k也可以被称为优雅阈值。 例如&#xff0c;数组[1, 2, 3, 1, 2, 3, 1]&#xff0c;它是一个3-优雅数组&#xff0c;因为元素1出现次数大于等于3次&#xff0c;数组[1,…

华为OD机试真题 Java 实现【取出尽量少的球】【2023Q1 200分】

一、题目描述 某部门开展 Family Day 开放日活动&#xff0c;其中有个从桶里取球的游戏。 游戏规则如下&#xff1a; 有 N 个容量一样的小桶等距排开&#xff0c;且每个小桶都默认装了数量不等的小球&#xff0c;每个小桶装的小球数量记录在数组 bucketBallNums 中。 游戏开…

eu.org申请免费域名 免费域名申请教程

EU.org是由Paul Mockapetris在1996年创建的免费域名服务&#xff0c;给没有资金买域名的个人或公司提供永久免费的域名。虽然是二级域名&#xff0c;但是已经被一些网络公司&#xff08;当然是国外的&#xff09;认定为顶级域名。 优缺点 优点&#xff1a;稳定性高、几乎没有…

04.Python Dash网页开发:ubuntu服务器部署DASH网站(uWSGI+nginx)

<~生~信~交~流~与~合~作~请~关~注~公~众~号生信探索> Dash官网只有付费的部署方式❌ 我的简单理解&#xff0c;uWSGI去运行dash app并且与nginx通讯&#xff1b;nginx处理浏览器传来的请求并把需求给uWSGI Python enviroment mkdir bioquestvi ~/bioquest/dash.yamlmicro…

docker搭建简单elk日志系统6(kibana设置)

1.进入kibana的索引管理界面清理调之前生成的测试数据流 2.模拟dev、uat、prod三个环境产生日志 修改filebeat配置文件&#xff0c;重启filebeat fields: application: testenv: devlog_type: normalfilebeat -c .\filebeat-test.yml产生日志 查看kibana数据流(已经生成dev环…

C++11 -- 类的新功能

文章目录 类的新功能默认成员函数类成员变量初始化强制生成默认函数的关键字default禁止生成默认函数的关键字delete继承和多态中的final和override关键字 类的新功能 默认成员函数 原来在C类中,有6个默认成员函数: 1: 构造函数 2: 拷贝构造函数 3: 拷贝赋值重载 4: 析构函数…

mysql 索引有哪几种?主键索引、唯一索引

面试题&#xff1a;mysql索引有哪几种&#xff1f; 答&#xff1a; 索引有两类&#xff0c;一是单列索引&#xff0c;二是组合索引。 单列索引&#xff0c;即一个索引只包含单个列&#xff0c;一个表可以有多个单列索引&#xff0c;但这不是组合索引。组合索引&#xff0c;即一…

SQL查询语言(3) 聚集查询和窗口函数的概念

查询结果排序 排序 规则如下: 1.语句: SELECT A1,A2.... FROM 表名 WHERE 选择条件 order by 属性1(ASC升序),属性3(DESC降序); 如果没有说明默认是升序排列: 2.对于空值的处理 如果是升序排列 NULL放在最后一行&#xff0c;如果是降序则放在第一行 上图为 按升序排列查询…

MyBatis动态SQL,基本语法加实战,一篇搞懂

问题&#xff1a; 有的时候我们需要实现批量删除&#xff1a;delete from t_car where id in(1,2,3,4,5,6,…这⾥的值是动态的&#xff0c;根据⽤户选择的 id不同&#xff0c;值是不同的); 多条件查询:有时我们需要根据多个不同地条件来进行查询&#xff0c;比如&#xff1a;se…

数据集成平台之kettle优缺点分析

数据集成平台前言 数据在业务中发挥着重要的作用&#xff0c;但并非所有数据都具有相同的价值和影响力。事实上&#xff0c;大部分数据业务的核心价值主要来自其中的少部分关键数据。这些关键数据可能包含着重要的业务指标、关键客户信息、市场趋势数据等&#xff0c;它们直接…

【机器学习】之Anaconda中使用的命令

操作之前&#xff0c;点击上图入口&#xff0c;进入Prompt。 //示例是在base环境下&#xff0c;cls清屏 (base) C:\Users\bubusa>cls1、base环境下的操作 //&#xff08;1&#xff09;列出所有虚拟环境 (base) C:\Users\bubusa>conda env list # conda environments: #…

Radeon Vii 系统分析 001记——工具

0. 简介 为了对 vega 7nm 有更感性的编程使用体验&#xff0c;故对 vega 7nm做各种测试&#xff1b; 工具&#xff1a; CLRadeonExtender ubuntu ROCm 资料&#xff1a; &#xff08;1&#xff09; 一张安装了 Radeon Vii vega 7nm 的台式机&#xff0c;win10 或 ubunt…

Mit6.006-lecture08-BinaryHeaps

一、优先队列接口 记录一些项目&#xff0c;快速地访问/移除最重要的 例&#xff1a;有限带宽的路由器&#xff0c;必须优先某些信息 例&#xff1a;操作系统内核中的进程调度 例&#xff1a;离散事件模拟&#xff08;下一件事何时发生&#xff09; 例&#xff1a;图算法&am…

js程序运行时在本机与外部app交互

js程序运行时在本机与外部app交互 目录 js程序运行时在本机与外部app交互 一、序言 1.1、问题 1.2、简要回答 二、原理 2.1、插件/web扩展/应用配置/权限 2.2、获取权限-原生应用交换信息的权限nativeMessaging 2.2.1、runtime(运行时的API) 2.3、连接本地应用程序的…