问题描述
小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组,记作 a1,a2,...,aN。为了分析这个数组的特性,小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
前置知识
单调栈参考题解:
juejin.cn/post/743456…
解题思路
-
简化一下题意:对于,找到左右两边第一个大于的数的下标(下标从1开始),两个下标的乘积记作,求最大的
-
朴素做法,遍历数组,内嵌往左和往右的循环
- 简单实现
-
for(int i=0; i < a.size(); i++) { int l,r; for(l = i -1; l >= 0 && a[l] <= a[i]; l--); for(l = i + 1; r < a.size() && a[r] <= a[i]; r++); if(r == a.size())r = 0; ans = max(ans, (l + 1) * r); }
-
考虑优化做法
-
先考虑左边的情况,我们如果优化找到左边第一个大于的数的下标
- 很容易想到使用单调栈来解决,不断出栈直到,此时,此时栈中存放的下标,+1是因为下标从1开始
-
考虑右边的情况,两种做法
- 仿照左边的做法,从右往左遍历数组即可
- 将当前作为右端点,那么栈中的元素的右端点就是
-
举个例子
-
,设左栈,右栈,数组记录乘积
-
-
左栈无值,加入下标0, ;右栈无值,加入下标,
-
- 左栈出栈直到栈顶大于, 此时(左边下标+1)
- 此时设为右端点,右栈中均大于等于
-
左栈加入,;右栈加入
-
- 左栈...,
- 设为右端点, 此时栈顶, 那么,此时, 可以看出,此时已经记录了左右端点的下标乘积
-
...
-
核心代码
int solution(int n, std::vector<int> array) {
int ans = 0;
stack<int>l, r ;
vector<int>cnt(n);
for(int i = 0; i < n; i++) {
while(!l.empty() && array[l.top()] <= array[i])
l.pop();
if(!l.empty())
cnt[i] = l.top() + 1;
while(!r.empty() && array[i] > array[r.top()]) {
cnt[r.top()] *= i+1;
ans = max(ans, cnt[r.top()]);
r.pop();
}
l.push(i);
r.push(i);
}
return ans;
}