给个数列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;
}