问题描述
对于一个有 N 个元素的数组,包含如下的元素 a1, a2, ..., an,我们定义了两个函数:
-
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 最近的那一个
最后,我们定义 MAX(i) = L(i) * R(i),我们需要找到 MAX(i) 的最大值,其中 1 <= i <= N。
输入格式
总共有两行,第一行是数组长度 N,第二个是空格分割的所有数组的内容。
输出格式
输出 MAX(i) 的最大值。
输入样例
5
5 4 3 4 5
输出样例
8
解释说明
- L(1) = 0,所以 MAX(1) = 0
- L(2) = 1, R(2) = 5,所以 MAX(2) = 1 * 5 = 5
- L(3) = 2, R(3) = 4,所以 MAX(3) = 2 * 4 = 8
- L(4) = 1, R(4) = 5,所以 MAX(4) = 1 * 5 = 5
- R(5) = 0,所以 MAX(5) = 0
数据范围
- 1<=𝑁<=1051<=N<=105
- 1<=𝑎[𝑖]<=1091<=a[i]<=109
思路
这个题要求的L函数存放的是数组中第i个元素的左侧离它最近且大于它的值,而R函数同理,是右侧最近且大于的数。由此可以想到栈中后进先出的特性,当栈顶元素大于a[i]时,就可以把栈顶元素的索引存入l中,否则,弹出栈顶元素,判断下一个元素(当栈不为空)。
案例图解
图中只展示了L函数的存入过程,但是R函数的存入过程与L是差不多的。
AC代码
import java.util.*;
public class Main {
public static int solution(int n, int[] array) {
// Edit your code here
//定义两个数组存放离元素最近且大于元素的索引
int[] left=new int[n];
int[] right=new int[n];
Stack<Integer> stk=new Stack<>();
for(int i=0;i<n;i++){
while(!stk.isEmpty()&&array[stk.peek()]<=array[i]){
stk.pop();
}
left[i]=stk.isEmpty()?0:stk.peek()+1;
stk.push(i);
}
stk.clear();
for(int i=n-1;i>=0;i--){
while(!stk.isEmpty()&&array[stk.peek()]<=array[i]){
stk.pop();
}
right[i]=stk.isEmpty()?0:stk.peek()+1;
stk.push(i);
}
int max=0;
for(int i=0;i<n;i++){
max=Math.max(max,left[i]*right[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);
}
}
核心代码的要点:
- 循环比较栈顶元素的值。
- 当栈为空时,L或R数组存入0。
- 判断和存入结束后,栈中压入元素。
总结
题目的重点就是利用栈来实现对元素的撤销操作,在满足题目要求的情况下将不满足条件的元素撤销,实现了循环遍历数组做不到的操作。
学习心得
这道题十分清晰的展现了使用栈来解决问题的过程,从这道题目中我更深刻的体会到栈对于操作的销毁的方便性(题目中将不合格的栈顶元素弹出),虽然这道题的难度不高,但是对于栈的理解却是很有帮助的。