You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_04_3_week;
// 小红书
// 3.13 笔试
// 给定一个数组,想随时查询任何范围上的最大值
// 如果只是根据初始数组建立、并且以后没有修改,
// 那么RMQ方法比线段树方法好实现时间复杂度O(N*logN)额外空间复杂度O(N*logN)
public class Code02_RMQ {
public static class RMQ {
public int[][] max;
// 下标一定要从1开始没有道理就是约定俗成
public RMQ(int[] arr) {
// 长度!
int n = arr.length;
// 2的几次方可以拿下n
int k = power2(n);
// n*logn
max = new int[n + 1][k + 1];
for (int i = 1; i <= n; i++) {
// i 0从下标i开始往下连续的2的0次方个数最大值
// 1...1个
// 2...1个
// 3...1个
max[i][0] = arr[i - 1];
}
for (int j = 1; (1 << j) <= n; j++) {
// i...连续的、2的1次方个数这个范围最大值
// i...连续的、2的2次方个数这个范围最大值
// i...连续的、2的3次方个数这个范围最大值
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
// max[10][3]
// 下标10开始连续的8个数最大值是多少
// 1) max[10][2]
// 2) max[14][2]
max[i][j] = Math.max(
max[i][j - 1],
max[i + (1 << (j - 1))][j - 1]);
}
}
}
public int max(int l, int r) {
// l...r -> r - l + 1 -> 2的哪个次方最接近它
int k = power2(r - l + 1);
return Math.max(max[l][k], max[r - (1 << k) + 1][k]);
}
private int power2(int m) {
int ans = 0;
while ((1 << ans) <= (m >> 1)) {
ans++;
}
return ans;
}
}
// 为了测试
public static class Right {
public int[][] max;
public Right(int[] arr) {
int n = arr.length;
max = new int[n + 1][n + 1];
for (int l = 1; l <= n; l++) {
max[l][l] = arr[l - 1];
for (int r = l + 1; r <= n; r++) {
max[l][r] = Math.max(max[l][r - 1], arr[r - 1]);
}
}
}
public int max(int l, int r) {
return max[l][r];
}
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = (int) (Math.random() * v);
}
return arr;
}
// 为了测试
public static void main(String[] args) {
int N = 150;
int V = 200;
int testTimeOut = 20000;
int testTimeIn = 200;
System.out.println("测试开始");
for (int i = 0; i < testTimeOut; i++) {
int n = (int) (Math.random() * N) + 1;
int[] arr = randomArray(n, V);
int m = arr.length;
RMQ rmq = new RMQ(arr);
Right right = new Right(arr);
for (int j = 0; j < testTimeIn; j++) {
int a = (int) (Math.random() * m) + 1;
int b = (int) (Math.random() * m) + 1;
int l = Math.min(a, b);
int r = Math.max(a, b);
int ans1 = rmq.max(l, r);
int ans2 = right.max(l, r);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
}
System.out.println("测试结束");
}
}