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] 内的所有数,每操作一次查询中位数. 遇到这题真的算是巧合,然而就是这种冥冥之中的缘分,给了我线 ...
随机推荐
- 【Golang】Demo
并发控制 package main // demo 参考地址https://studygolang.com/articles/25950 import ( "github.com/siddo ...
- MySQL count(*) 和 count(字段) 区别
count(字段)不会取Null的 select count(*) from test01 7条 select count(0) from test01 ...
- 谈谈Selenium中的日志
谈谈Selenium中的日志 来源于一位同学,"老师为啥firefox执行后会有日志文件,chrome没有呢?" 比对 你打开chrome浏览器 from selenium imp ...
- HDFS写操作(简单源码解读)
HDFS最重要的就是写流程了,学校老师教的时候也是重点介绍这个过程(虽然我并没有在任何面试中被问到过).下面从画图和文字两个过程介绍写流程,这次读了源代码之后对整个过程更加清晰了. 一.图解 二.文字 ...
- 为什么说 ICMP 协议是网络最强辅助
大家好,我是风筝 轻解网络系列又来了.已有高清 PDF 版本可以离线阅读了,全册 65 页,如果有需要离线版的高清 PDF 可以直接下载. 今天咱们说说 ICMP 协议.ICMP 可谓是网络世界中的最 ...
- 【实战】SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 基于SpringBoot+uniapp简单通讯聊天软件 项目介绍 JavaDog Chat 简单通讯聊天软件是基于SpringBoot+MybatisPlus+ ...
- 解决vue中滚轮事件报错 Added non-passive event listener to a scroll-blocking 'mousewheel' event.告警
参考:https://www.jianshu.com/p/23850d4cade8 参考:让页面滑动流畅得飞起的新特性:Passive Event Listeners
- FileReader之获取文本文件内容为字符串
FileReader之获取文本文件内容为字符串 FileReader官网描述: FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 Fil ...
- 电商平台趋势妙手采集类API接口
电商平台趋势,平台化.大家可以看到大的电商都开始有自己的平台,其实这个道理很清楚,就是因为这是充分利用自己的流量.自己的商品和服务大效益化的一个过程,因为有平台,可以利用全社会的资源弥补自己商品的丰富 ...
- C++库封装JNI接口——实现java调用c++
1. JNI原理概述 通常为了更加灵活高效地实现计算逻辑,我们一般使用C/C++实现,编译为动态库,并为其设置C接口和C++接口.用C++实现的一个库其实是一个或多个类的简单编译链接产物.然后暴露其实 ...