2022-07-05:给定一个数组,想随时查询任何范围上的最大值。 如果只是根据初始数组建立、并且以后没有修改, 那么RMQ方法比线段树方法好实现,时间复杂度O(N*logN),额外空间复杂度O(N*
2022-07-05:给定一个数组,想随时查询任何范围上的最大值。
如果只是根据初始数组建立、并且以后没有修改,
那么RMQ方法比线段树方法好实现,时间复杂度O(NlogN),额外空间复杂度O(NlogN)。
来自小红书。3.13笔试。
答案2022-07-05:
RMQ范围最大值和最小值查询,不支持更新。
空间复杂度:O(N*logN)。
查询复杂度:O(1)。
代码用rust编写。代码如下:
use rand::Rng;
fn main() {
let nn: i32 = 150;
let vv = 200;
let test_time_out = 20000;
let test_time_in = 200;
println!("测试开始");
for i in 0..test_time_out {
let n = rand::thread_rng().gen_range(0, nn) + 1;
let mut arr = random_array(n, vv);
let mut arr2=arr.clone();
let m = arr.len() as i32;
let mut rmq = RMQ::new(&mut arr);
let mut right = Right::new(&mut arr2);
for _ in 0..test_time_in {
let a = rand::thread_rng().gen_range(0, m) + 1;
let b = rand::thread_rng().gen_range(0, m) + 1;
let l = get_min(a, b);
let r = get_max(a, b);
let ans1 = rmq.max(l, r);
let ans2 = right.max(l, r);
if ans1 != ans2 {
println!("出错了!{}", i);
println!("ans1 = {}", ans1);
println!("ans2 = {}", ans2);
break;
}
}
}
println!("测试结束");
}
pub struct RMQ {
pub max: Vec<Vec<i32>>,
}
impl RMQ {
// 下标一定要从1开始,没有道理!就是约定俗成!
pub fn new(arr: &mut Vec<i32>) -> Self {
// 长度!
let n = arr.len() as i32;
let mut ans: RMQ = RMQ { max: vec![] };
// 2的几次方,可以拿下n
let k = ans.power2(n);
// n*logn
let mut max: Vec<Vec<i32>> = vec![];
for i in 0..n + 1 {
max.push(vec![]);
for _ in 0..k + 1 {
max[i as usize].push(0);
}
}
for i in 1..=n {
// i 0:从下标i开始,往下连续的2的0次方个数,中,最大值
// 1...1个
// 2...1个
// 3...1个
max[i as usize][0] = arr[(i - 1) as usize];
}
ans.max = max;
let mut j = 1;
while (1 << j) <= n {
// i...连续的、2的1次方个数,这个范围,最大值
// i...连续的、2的2次方个数,这个范围,最大值
// i...连续的、2的3次方个数,这个范围,最大值
let mut i = 1;
while i + (1 << j) - 1 <= n {
// max[10][3]
// 下标10开始,连续的8个数,最大值是多少
// 1) max[10][2]
// 2) max[14][2]
ans.max[i as usize][j as usize] = get_max(
ans.max[i as usize][(j - 1) as usize],
ans.max[(i + (1 << (j - 1))) as usize][(j - 1) as usize],
);
i += 1;
}
j += 1;
}
return ans;
}
pub fn max(&mut self, l: i32, r: i32) -> i32 {
// l...r -> r - l + 1 -> 2的哪个次方最接近它!
let k = self.power2(r - l + 1);
return get_max(
self.max[l as usize][k as usize],
self.max[(r - (1 << k) + 1) as usize][k as usize],
);
}
fn power2(&mut self, m: i32) -> i32 {
let mut ans = 0;
while (1 << ans) <= (m >> 1) {
ans += 1;
}
return ans;
}
}
// 为了测试
pub struct Right {
pub max: Vec<Vec<i32>>,
}
impl Right {
pub fn new(arr: &mut Vec<i32>) -> Self {
let n = arr.len() as i32;
let mut max: Vec<Vec<i32>> = vec![];
for i in 0..n + 1 {
max.push(vec![]);
for _ in 0..n + 1 {
max[i as usize].push(0);
}
}
for l in 1..=n {
max[l as usize][l as usize] = arr[(l - 1) as usize];
for r in l + 1..=n {
max[l as usize][r as usize] =
get_max(max[l as usize][(r - 1) as usize], arr[(r - 1) as usize]);
}
}
Self { max }
}
pub fn max(&mut self, l: i32, r: i32) -> i32 {
self.max[l as usize][r as usize]
}
}
fn get_max<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
}
fn get_min<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
}
// 为了测试
fn random_array(n: i32, v: i32) -> Vec<i32> {
let mut arr: Vec<i32> = vec![];
for _i in 0..n {
arr.push(rand::thread_rng().gen_range(0, v));
}
return arr;
}
执行结果如下:
2022-07-05:给定一个数组,想随时查询任何范围上的最大值。 如果只是根据初始数组建立、并且以后没有修改, 那么RMQ方法比线段树方法好实现,时间复杂度O(N*logN),额外空间复杂度O(N*的更多相关文章
- 差分数组&&定义&&使用方法&&与线段树的区别
**1.定义**对于一个有n个元素的数组a[n],我们令a[i]-a[i-1]=d[i],且d[1]=a[1]-0=a[1];那么我们将d[i]称为**差分数组**---即记录数组中的每项元素与前一项 ...
- 蓝书4.1-4.4 树状数组、RMQ问题、线段树、倍增求LCA
这章的数据结构题很真实 T1 排队 bzoj 1699 题目大意: 求静态一些区间的最大值-最小值 思路: ST表裸题 #include<iostream> #include<cst ...
- CodeForces992E 二分 + 树状数组(线段树)
http://codeforces.com/problemset/problem/992/E 题意:给定一个序列 ai ,记其前缀和序列为 si ,有 q 个询问,每次单点修改,询问是否存在一个 ...
- Dynamic Rankings(树状数组套权值线段树)
Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...
- st表、树状数组与线段树 笔记与思路整理
已更新(2/3):st表.树状数组 st表.树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题. 一.ST表(Sparse ...
- POJ 1804 Brainman(5种解法,好题,【暴力】,【归并排序】,【线段树单点更新】,【树状数组】,【平衡树】)
Brainman Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10575 Accepted: 5489 Descrip ...
- 2018.07.07 BZOJ2212: Poi2011Tree Rotations(线段树合并)
2212: [Poi2011]Tree Rotations Time Limit: 20 Sec Memory Limit: 259 MB Description Byteasar the garde ...
- 小结:线段树 & 主席树 & 树状数组
概要: 就是用来维护区间信息,然后各种秀智商游戏. 技巧及注意: 一定要注意标记的下放的顺序及影响!考虑是否有叠加或相互影响的可能! 和平衡树相同,在操作每一个节点时,必须保证祖先的tag已经完全下放 ...
- 计蒜客 1460.Ryuji doesn't want to study-树状数组 or 线段树 (ACM-ICPC 2018 徐州赛区网络预赛 H)
H.Ryuji doesn't want to study 27.34% 1000ms 262144K Ryuji is not a good student, and he doesn't wa ...
- 线段树&树状数组与离散化的妙用
牛客2019多校联盟Day7 Fine the median 题意: 每次给数组插入区间[Li,Ri] 内的所有数,每操作一次查询中位数. 遇到这题真的算是巧合,然而就是这种冥冥之中的缘分,给了我线 ...
随机推荐
- windows10环境下的RabbitMQ安装步骤(图文)(转载)
第一步:下载并安装erlang 原因:RabbitMQ服务端代码是使用并发式语言Erlang编写的,安装Rabbit MQ的前提是安装Erlang. 下载地址:http://www.erlang.or ...
- RealWorldCTF渗透赛第二期复现-ctfshow
比赛概述 开始时间:2023年3月10日15时 环境保留时间:72小时 环境重置时间:20分钟 官方wp链接:Docs (feishu.cn) [本次复现跟着官方WP进行,只做记录学习之用] 0x1 ...
- Java线程池和Spring异步处理高级篇
开发过程中我们会遇到很多使用线程池的场景,例如异步短信通知,异步发邮件,异步记录操作日志,异步处理批量Excel解析.这些异步处理的场景我们都可以把它放在线程池中去完成,当然还有很多场景也都可以使用线 ...
- vmware workstation 版本合集
各版本序列号 10.x:1Z0G9-67285-FZG78-ZL3Q2-234JG 11.x:YG74R-86G1M-M8DLP-XEQNT-XAHW2 12.x:ZC3TK-63GE6-481JY- ...
- Nacos 实现 AP+CP原理[Raft 算法 NO]
来源于网络 一.什么是 Raft算法 Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它.为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导 ...
- 玩转Mybatis高级特性:让你的数据操作更上一层楼
目录 动态SQL 缓存机制 插件机制 自定义类型转换 总结 Mybatis高级特性能够帮助我们更加灵活地操作数据库,包括动态SQL.缓存机制.插件机制.自定义类型转换等.学习这些特性可以让我们更好地利 ...
- QGIS 导入文本数据(WKT)
在做GIS数据处理的时候,经常会遇到原始数据是 text.csv.Excel 等格式的数据.要使用数据前提是要先转换数据. 这里是介绍用 QGIS 导入数据.打开导入方式如下(根据自己的文本类型选择不 ...
- docker方式实现postgres数据持久化离线安装
保存镜像 root@hello:~# docker pull postgres Using default tag: latest latest: Pulling from library/postg ...
- Seal AppManager发布:基于平台工程理念的全新应用部署管理体验
4月12日,数澈软件Seal(以下简称"Seal")宣布推出新一代应用统一部署管理平台 Seal AppManager,采用平台工程的理念,降低基础设施操作的复杂度为研发和运维团队 ...
- 【Git GitHub Idea集成】
1 Git介绍 分布式版本控制工具 VS 集中式版本控制工具 git是一个免费开源的分布式版本控制系统,可以快速高效地处理从小型到中型的各种项目. 1.1 Git进行版本控制 集中式版本控制工具:如C ...