给个数列
A
,问是否存在
这题是我在面试的时候碰到的题目,当时没想到
O(n)
解,所以当时假设没有
O(n)
解。今天早上上班的路上,又想了一下这道题。发现确实有
O(n)
解,特地写了这个题解。
首先,由于i位于最左边,所以首先可以处理
leftj=min(A1,A2,...,Aj−1)
且
leftj<Aj
。显然对于
Aj
需要求一个
Ak>leftj
&&
Ak<Aj
。
其次,需要强调一点,
left
数组是一个单调不增的数列。于是考虑从右往左扫描数列,维护一个单调递减栈,维护时,对于当前放入栈的
Aj
, 将栈顶小于
Aj
的数弹出。于是在维护单调栈的同时,判断栈顶元素是否是满足的
Ak
即可。即
stack.top()>leftj
&&
stack.top()<Aj
。
这种做法确实是一个必要解,现在证明充分性。
证明:现在证明,对于
Aj
来说
Ak(k>j)
在放入栈中时,不会因为将在栈顶元素
s(s>leftj
&&
s<Aj)
弹出,而导致无解。
1.假如
Aj>Ak
,显然如果栈顶元素
s
弹出,
2.假如
Aj<=Ak
,显然,如果存在栈顶元素
s
。由于
而如果
s<=leftk
,则显然可以弹出。
s>=Ak
, 显然可以直接将
Ak
放入栈顶。
所以得证。
#include <bits/stdc++.h>
using namespace std;
bool solve(const vector<int>& A) {
vector<int> left(A.size());
left[0] = 0x3f3f3f3f;
for (int i = 1; i < A.size(); ++i) {
left[i] = min(left[i - 1], A[i - 1]);
}
stack<int> S;
for (int i = A.size() - 1; --i) {
if (S.empty()) {
S.push(A[i]);
} else {
if (left[i] < A[i] && left[i] < S.top() && S.top() > A[i]) {
return true;
} else {
while (!S.empty() && S.top() < A[i]) {
S.pop();
}
S.push(A[i]);
}
}
}
return false;
}