题目地址:
https://leetcode.com/problems/maximum-of-minimum-values-in-all-subarrays/
给定一个长 n n n的数组 A A A,要求返回一个数组 B B B,使得 B [ i ] B[i] B[i]是 A A A中所有长 i + 1 i+1 i+1的区间的最小值的最大者。
设询问的答案 q i q_i qi是所有长 i i i的区间的最小值的最大者。思路是单调栈。考虑一个严格单调递增的栈 s s s,栈存下标。那么当 s [ k ] s[k] s[k]需要弹出的时候,假设是遍历到了 A [ i ] A[i] A[i],并且此时栈顶为 j j j,那么我们就知道了 A [ i ] A[i] A[i]一定是 A [ j + 1 : i − 1 ] A[j+1:i-1] A[j+1:i−1]这一段的最小数,从而 A [ i ] A[i] A[i]是 q i − 1 − j q_{i-1-j} qi−1−j的备选。如果栈空,或者遍历完成之后清空栈的时候,也可以得到若干类似的结论。我们将这个暂时得到的所有询问的答案记为 C C C。显然 ∀ i , q i ≥ q i + 1 \forall i, q_i\ge q_{i+1} ∀i,qi≥qi+1,所以最后我们要逆序遍历 C C C,并且将 C [ i ] C[i] C[i]更新为 max { C [ i ] , C [ i + 1 ] } \max\{C[i],C[i+1]\} max{C[i],C[i+1]}。最后得到的 C C C即为答案。算法正确性可以由如下观察得知:设 x = q k x=q_k x=qk,并且此处的 k k k取最大,那么 x x x这个数一定在某个时刻成为了栈顶,并且 x x x恰好会去更新 q k q_k qk。代码如下:
class Solution {
public:
vector<int> findMaximums(vector<int>& A) {
int n = A.size();
vector<int> res(n);
stack<int> stk;
for (int i = 0; i <= n; i++) {
while (stk.size() && (i == n || A[stk.top()] > A[i])) {
int t = stk.top(), k = i - 1;
stk.pop();
if (stk.size()) k -= stk.top() + 1;
res[k] = max(res[k], A[t]);
}
stk.push(i);
}
for (int i = res.size() - 1; i; i--) res[i - 1] = max(res[i - 1], res[i]);
return res;
}
};
时空复杂度 O ( n ) O(n) O(n)。