2022-07-05:给定一个数组,想随时查询任何范围上的最大值。 如果只是根据初始数组建立并且以后没有修改, 那么RMQ方法比线段树方法好实现,时间复杂度O(N*logN),额外空间复杂度O(N*

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;


执行结果如下:


左神java代码

以上是关于2022-07-05:给定一个数组,想随时查询任何范围上的最大值。 如果只是根据初始数组建立并且以后没有修改, 那么RMQ方法比线段树方法好实现,时间复杂度O(N*logN),额外空间复杂度O(N*的主要内容,如果未能解决你的问题,请参考以下文章

惯用地查找给定值在数组中出现的次数

处理大型数组时超出时间限制

使用数组作为 GraphQL 查询的变量

存储过程与数组连接查询

对给定数组的 XOR 查询

同一公式中的查询,数组和排序函数