#include <bits/stdc++.h>
using namespace std;
bool FoursNumberFind(vector<int>& nums) {
stack<int> st;
int n = nums.size(), k = INT_MIN, INF = INT_MAX;
//min_r[i] = min(nums[r]), i < r < n。
//表示第i个数(不包括第i个数)右边的最小值
vector<int> min_r(n, INF);
// 用前缀和方法求 min_r 数组
for (int i = n - 2; i >= 0; --i) {
min_r[i] = min(min_r[i + 1], nums[i + 1]);
}
//用单调栈求下标位 nums[c] < nums[a] < nums[b] 的情况
for(int i = 0; i < n; ++i){
// 下标 i 即为 c ,k 即为 nums[a]
if(nums[i] < k) { //如果存在 nums[c] < nums[a] < nums[b] 的情况
//判断 c 的右边是否 有比 nums[c] 小的数, 有则表示存在下标 d ,返回true
if(nums[i] > min_r[i]) return true;
}
// 如果栈不为空并且栈顶元素小于当前访问的元素
while(!st.empty() && st.top() < nums[i]) {
//需要找满足小于nums[b]的最大 k 值
k = max(k,st.top());
st.pop();
}
//压入栈顶,即为更新 nums[b]
st.push(nums[i]);
}
return false;
}
int main() {
int n;
cin >> n;
vector<int> nums(n);
for (int i = 0; i < n; i++) {
scanf("%d", &nums[i]);
}
if (FoursNumberFind(nums)) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
return 0;
}
代码实现了检测一个数组中是否存在特定的索引模式,即 a < b < c < d
且 nums[d] < nums[c] < nums[a] < nums[b]
。
代码分析:
-
函数
FoursNumberFind
接收一个整数数组nums
作为参数,并试图找出是否存在上述模式。如果找到,函数返回true
,否则返回false
。 -
首先,定义一个栈
st
来帮助我们跟踪可能的nums[c]
值,并将整数k
初始化为INT_MIN
来表示我们尚未找到一个有效的nums[a]
。同时,创建一个向量min_r
,用于存放从当前位置起右侧的最小值。 -
接着,使用一个前向遍历循环来填充
min_r
数组,记录数组中每个元素右边的最小值。 -
再使用一个循环从左到右遍历
nums
:-
判断当前元素是否小于
k
,即判断是否nums[c] < nums[a]
。如果是,并且当前元素也大于它右侧的最小值,这意味着存在一个nums[d]
,因此返回true
。 -
使用一个
while
循环和栈来维护和更新可能的nums[b]
值。如果栈非空并且栈顶的值小于当前元素,那么说明找到了一个新的nums[b]
(当前元素),于是更新k
(作为nums[a]
)为栈顶的值,并从栈中弹出这个栈顶元素。 -
将当前元素压入栈中,代表一个新的候选的
nums[b]
。
-
-
如果上述循环结束后没有找到满足条件的下标组合,函数返回
false
。 -
在
main
函数中,程序读取用户输入的数组长度n
和数组元素,然后调用FoursNumberFind
函数来确定是否存在所描述的模式。根据函数返回的布尔值,程序输出YES
或NO
。
代码使用了一个单调栈来优化搜索过程,并避免了暴力枚举的 O(n^4)
复杂度,使得算法的性能得到了显著的提升。标准输入和输出流(cin
和 cout
)用于接收输入和输出结果,提供了与用户交互的接口。