当前位置:网站首页>树状数组+离散化
树状数组+离散化
2022-07-13 17:55:00 【早日拿offer】
树状数组的优点
- 快速修改某个数 O ( l o g n ) O(logn) O(logn)
- 快速求前缀和 O ( l o g n ) O(logn) O(logn)
对比原数组:
- 修改某个数 O ( 1 ) O(1) O(1)
- 求前缀和 O ( n ) O(n) O(n)
对比前缀和数组
- 修改某个数 O ( n ) O(n) O(n)
- 求前缀和 O ( 1 ) O(1) O(1)
树状数组的实现
原理看博客:主要就是使用二进制思想,将原数组分成块状,进而对其进行修改和求和
主要两个操作:
- 修改操作:在某个位置+c,就是在当前块和后续块+c
public void add(int x, int c) {
for(int i = x; i <= n; i += lowbit(i)) {
tr[i] += c;
}
}
- 求和操作:将 a [ 1 ∼ x ] a[1\sim x] a[1∼x]的元素相加
public int sum(int x) {
int res = 0;
for(int i = x; i >= 1; i -= lowbit(i)) {
res += tr[i];
}
}
(其中,lowbit(x)是求x的二进制表示中最后一位1,即x&(-x))
- 但是题目中经常会出现n很大的情况,例如 n > 1 0 6 n>10^6 n>106,或者存在负数的情况,那么树状数组就会非常大或者下标越界,导致内存溢出。所以在此时就需要原数组进行离散化。离散化有两步操作,分别是排序+去重,这个可以借助有序集合实现。但是用有序集合实现后,对应的数下标无法快速确定,此时需要借助哈希表,将有序集合中的数映射到[1,n]上,此时就满足了树状数组的要求。(离散化实现:有序集合+哈希表)
例题
LeetCode327. 区间和的个数
给你一个整数数组 n u m s nums nums 以及两个整数 l o w e r lower lower 和 u p p e r upper upper。求数组中,值位于范围 [ l o w e r , u p p e r ] [lower, upper] [lower,upper] (包含 l o w e r lower lower 和 u p p e r upper upper)之内的区间和的个数 。
区间和 S ( i , j ) S(i, j) S(i,j) 表示在 n u m s nums nums中,位置从 i i i到 j j j的元素之和,包含 i i i和 j j j ( i ≤ j i ≤ j i≤j)。
提示:
- 1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
- − 2 31 < = n u m s [ i ] < = 2 31 − 1 -2^{31} <= nums[i] <= 2^{31} - 1 −231<=nums[i]<=231−1
- − 1 0 5 < = l o w e r < = u p p e r < = 1 0 5 -10^5 <= lower <= upper <= 10^5 −105<=lower<=upper<=105
- 题目数据保证答案是一个 32 位 的整数
思路:
使用前缀和求出 s u m [ i ] sum[i] sum[i],那么对于 i i i,可以暴力遍历 j , ( 1 ≤ j ≤ i − 1 ) j,(1\leq j\le i-1) j,(1≤j≤i−1)来计算 s u m [ i ] − s u m [ j ] sum[i]-sum[j] sum[i]−sum[j]来得到满足区间和 [ l o w e r , u p p e r ] [lower,upper] [lower,upper]的个数。此时整个的时间复杂度 O ( n 2 ) O(n^2) O(n2),必然超时。此时想到可以使用树状数组来求解。
l o w e r ≤ s u m [ i ] − s u m [ j ] ≤ u p p e r ⇒ s u m [ i ] − u p p e r ≤ s u m [ j ] ≤ s u m [ i ] − l o w e r lower\leq sum[i]-sum[j]\leq upper\Rightarrow sum[i]-upper\leq sum[j]\leq sum[i]-lower lower≤sum[i]−sum[j]≤upper⇒sum[i]−upper≤sum[j]≤sum[i]−lower。
即计算在 [ s u m [ i ] − u p p e r , s u m [ i ] − l o w e r ] [sum[i]-upper,sum[i]-lower] [sum[i]−upper,sum[i]−lower]的数的个数。使用树状数组可以快速在 O ( l o g n ) O(logn) O(logn)下得到。但是 s u m [ i ] sum[i] sum[i]的数据范围很大,对应的树状数组 t r [ n + 1 ] tr[n+1] tr[n+1]也很大,且会越界。所以需要离散化。离散化借助有序集合+哈希表即可。离散化需要将所有用到的数都存入有序集合中,然后将这些数映射到 [ 1 , m a x ] [1,max] [1,max]。后续操作只需到对 [ 1 , m a x ] [1,max] [1,max]上进行操作即可。
class Solution {
int[] tr;
int max;
public int countRangeSum(int[] nums, int lower, int upper) {
int n = nums.length;
long[] sum = new long[n+1];
for(int i = 1; i <= n;i++) {
sum[i] = sum[i-1] + nums[i-1];
}
TreeSet<Long> set = new TreeSet<>();
set.add(0l);
for(long x : sum) {
set.add(x);
set.add(x - lower);
set.add(x - upper - 1);
}
Map<Long,Integer> map = new HashMap<>();
int idx = 1;
for(long x : set) {
map.put(x,idx++);
}
tr = new int[idx+1];
max = idx;
int res = 0;
for(long x : sum) {
res += sum(map.get(x - lower)) - sum(map.get(x - upper - 1));
add(map.get(x),1);
}
return res;
}
public int lowbit(int x) {
return x & (-x);
}
public void add(int x, int c) {
for(int i = x; i <= max;i += lowbit(i)) {
tr[i] += c;
}
}
public int sum(int x) {
int res = 0;
for(int i = x; i >= 1; i -= lowbit(i)) {
res += tr[i];
}
return res;
}
}
边栏推荐
- 交易模块开发
- 线性代数知识回顾:矩阵的秩,矩阵的范数,矩阵的条件数,矩阵的特征值和特征向量
- [Go语言入门] 06 Go语言循环语句
- TypeScript基础配置使用教程(在VScode中自动编译)
- [Go语言入门] 09 Go语言切片详解
- LeetCode 刷题 第六天
- 【C语言】 大学生考勤管理系统
- ROS communication mechanism
- Use of go language JSON parsing library jsoniter (replace standard library encoding/json)
- How to select embedded single chip microcomputer?
猜你喜欢

Comparison and application of DHT11 and dht22 (am2302)

Record: vscode connects to Alibaba cloud via SSH

Train yolov3 on colab (I)

01 machine learning: evaluation indicators

C language to realize Hanoi Tower (detailed explanation of program execution steps)

寶塔面板在同一服務器下創建多個端口部署項目(輕量應用服務器一鍵部署網站、博客、GltLab完整版)

ROS 通信机制
![[introduction to go language] 08 go language array](/img/f6/6e113d9090a0c58a68b2e379e64500.png)
[introduction to go language] 08 go language array

Getting started with spark

Vectorization of gradient descent method
随机推荐
多个else if嵌套时的作用域
IIC communication
go语言json解析库jsoniter的使用(替换标准库encoding/json)
js知识点
STM32 uses a simple method to control many lights to achieve the effect of flowing water
SSM整合(借鉴版)
Distributed theory
LeetCode 刷题 第十一天
Redis is the fastest to get started in history (attach redis on ECs)
[introduction to go language] 05 go language branch statement
Implementation of array flattening
Stm32-tim3 output PWM signal to drive mg996r steering gear (key control)
LeetCode 刷题 第九天
DL第二天
Swagger快速入门(接口文档)
LeetCode 第十八天
DL第六天
Promise --- synchronize? Asynchronous?
寶塔面板在同一服務器下創建多個端口部署項目(輕量應用服務器一鍵部署網站、博客、GltLab完整版)
TypeScript基础配置使用教程(在VScode中自动编译)