上一篇文章讲解了如何用维护一个单调栈来解决求子数组的最小值长度的最大值问题,且如何处理当遍历之后一个元素栈不为空的处理技巧。最大矩形面积问题和上一题很相似,都可以用单调栈来解决。
问题描述
小R最近遇到了一个数组问题。他有一个包含 N个元素的数组,记作 。为了分析这个数组的特性,小R定义了两个函数 L(i) 和 R(i),并希望通过这两个函数来找到一些有趣的结论。
- L(i) 是满足以下条件的最大的 j 值:
- j<i
- a[j]>a[i]
- 如果找不到这样的 j,那么 L(i)=0;如果有多个满足条件的 j,选择离 i 最近的那个。
- R(i) 是满足以下条件的最小的 k 值:
- k>i
- a[k]>a[i]
- 如果找不到这样的 k,那么 R(i)=0;如果有多个满足条件的 k,选择离 i 最近的那个。
最终,小R定义 MAX(i)=L(i)∗R(i),他想知道在 1≤i≤N 的范围内,MAX(i)的最大值是多少。
测试样例
样例1:
输入:
n = 5, array = [5, 4, 3, 4, 5]
输出:8
样例2:
输入:
n = 6, array = [2, 1, 4, 3, 6, 5]
输出:15
样例3:
输入:
n = 7, array = [1, 2, 3, 4, 5, 6, 7]
输出:0
思路
这题如果题目读懂了,其实是一个求左右边界的问题,相当于a[i]表示[j, k]区间内的最小值,然后确定这个区间。上一题是确定这个区间内的最小值乘以长度的最大值,这题解题思路一行,只不过得到结果的方式不一,过程是一样的。
算法步骤
-
计算
L(i):- 从左到右遍历数组,使用栈来维护一个递减序列。
- 对于每个元素
a[i],如果栈顶元素比a[i]小,则弹出栈顶元素,直到栈为空或者栈顶元素比a[i]大。 - 栈顶元素的索引就是
L(i)。
-
计算
R(i):- 从右到左遍历数组,使用栈来维护一个递减序列。
- 对于每个元素
a[i],如果栈顶元素比a[i]小,则弹出栈顶元素,直到栈为空或者栈顶元素比a[i]大。 - 栈顶元素的索引就是
R(i)。
-
计算
MAX(i):- 遍历数组,计算
MAX(i) = L(i) * R(i),并记录最大值。
- 遍历数组,计算
import java.util.*;
public class Main {
public static int solution(int n, int[] array) {
// Edit your code here
Stack<Integer> stack = new Stack<>();
int max = 0;
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && array[i] > array[stack.peek()]) {
if (array[i] == stack.pop()) continue;
int l = stack.isEmpty() ? -1 : stack.peek();
max = Math.max(max, (l + 1) * (i + 1));
}
stack.push(i);
}
return max;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(5, new int[]{5, 4, 3, 4, 5}) == 8);
}
}
总结
求子数组边界问题用栈处理真的很优雅