栈应用 o(n)实现
有时候利用栈可以降低时间复杂度
对于一些右前后关系的 且 暴力要遍历多次的 可以考虑栈优化
例题:
题意:
给你一串长度为n的数 如果一个数前面有比他大的数那么这个数就可以和前面那个大的数连通 求连通块的个数
思路:
看似像并查集 其实可以用栈 O(1)实现
现将第一个数作为一个元素 记录这个元素最大值和最小值(就是a[1])然后逐个遍历后面的数 如果a[i]比栈顶元素的最大值小就将其并入栈顶元素中更新栈的最大值和最小值
否则 就往栈中push一个新的元素 每次判断 栈顶前两个元素 判断是否可以合并 若是则更新合并后元素的最大值和最小值
最后栈中元素的个数即答案
#include <bits/stdc++.h> #include <queue> #define ll long long #define pi acos(-1) #define FF ios::sync_with_stdio(false), cin.tie(0) using namespace std; const int mod = 1e9 + 7; const int maxn = 1e3 + 10; const int N = 1e5 + 10; const int inf = 0x3f3f3f3f; int n, m, k, ans; int a[N]; struct node{ int mx, mi; }pre[N]; stack<node>st; void solve(){ // 栈清空 while(!st.empty()){ st.pop(); } cin >> n; for(int i = 1; i <= n; i++){ cin >> a[i]; } ans = 1; //先push第一个元素 st.push({a[1], a[1]}); for(int i = 2; i <= n; i++){ node tp = st.top(); if(a[i] < tp.mx) { if(a[i] < tp.mi){ st.pop(); st.push({tp.mx, a[i]}); } } else st.push({a[i], a[i]}); //栈往下判断能否合并 while(st.size() >= 2){ node t1 = st.top(); st.pop(); node t2 = st.top(); if(t2.mx > t1.mi){ //注意栈中的元素不能直接更新 必须先出栈然后再把更新后的放入栈中 t2.mx = max(t1.mx, t2.mx); t2.mi = min(t1.mi, t2.mi); st.pop(); st.push(t2); } else { st.push(t1); break; } } } cout << st.size() << "\n"; } int main() { FF; int t = 1; cin >> t; while(t --){ solve(); } return 0; }