数据结构往往可以在不改变主算法的前提下题高运行效率,具体做法可能千差万别,但思路却是有规律可循
经典问题:滑动窗口 单调队列O(n)
POJ 2823
我开始写的: TLE 说明STL的库还是有点慢
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<deque> #include<set> #include<map> #include<cmath> #include<stack> const double PI = acos(-1.0); #define INF 0x3f3f3f3f typedef long long ll; using namespace std; struct Deq { int idx; int w; }; deque<Deq> q; deque<Deq> qq; int Max[1000005]; int main() { int n, k; int x; int cnt = 0; scanf("%d%d", &n, &k); for (int i = 0; i < n; i++) { if (i < k) { scanf("%d", &x); Deq qqq; qqq.idx = i; qqq.w = x; if (q.empty()) q.push_back(qqq); if (qq.empty()) qq.push_back(qqq); else { while (!q.empty() && q.back().w < x) q.pop_back(); q.push_back(qqq); while (!qq.empty() && qq.back().w > x) qq.pop_back(); qq.push_back(qqq); } if (i == k - 1) { printf("%d", qq.front().w); Max[cnt++] = q.front().w; } } else { scanf("%d", &x); Deq qqq; qqq.idx = i; qqq.w = x; if (q.empty()) q.push_back(qqq); if (qq.empty()) qq.push_back(qqq); else { while (!q.empty() && q.back().w < x) q.pop_back(); q.push_back(qqq); while (!qq.empty() && qq.back().w > x) qq.pop_back(); qq.push_back(qqq); } while (q.front().idx < i + 1 - k) q.pop_front(); while (qq.front().idx < i + 1 - k) qq.pop_front(); printf(" %d", qq.front().w); Max[cnt++] = q.front().w; } } printf("\n"); for (int i = 0; i < cnt; i++) { i == 0 ? printf("%d", Max[i]) : printf(" %d", Max[i]); } return 0; }
洛谷题解:
直接用下标存进队列 手写双端队列
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<deque> #include<set> #include<map> #include<cmath> #include<stack> const double PI = acos(-1.0); #define INF 0x3f3f3f3f typedef long long ll; using namespace std; const int maxn = 1000005; int n, m; int q1[maxn], q2[maxn]; int a[maxn]; void Min_que() { int h = 1; //head int t = 0; //tail for (int i = 1; i <= n; i++) { while (h <= t && q1[h] + m <= i) h++; while (h <= t && a[i] < a[q1[t]]) t--; q1[++t] = i; if (i >= m) printf("%d ", a[q1[h]]); } printf("\n"); } void Max_que() { int h = 1; int t = 0; for (int i = 1; i <= n; i++) { while (h <= t && q2[h] + m <= i) h++; while (h <= t && a[i] > a[q2[t]]) t--; q2[++t] = i; if (i >= m) printf("%d ", a[q2[h]]); } } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); Min_que(); Max_que(); return 0; }
单调栈:
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<set> #include<map> #include<cmath> #include<stack> const double PI = acos(-1.0); #define INF 0x3f3f3f3f typedef long long ll; using namespace std; struct S { int idx; int w; }; stack<S> s; int a[3000005]; vector<int> f; int main() { int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); for (int i = n - 1; i >= 0; i--) { if (i == n - 1) { f.push_back(0); s.push({ i,a[i] }); } else { if (s.empty()) { f.push_back(0); s.push({ i,a[i] }); } else { while (!s.empty()&&s.top().w <= a[i]) s.pop(); if (!s.empty()) f.push_back(s.top().idx+1); else f.push_back(0); s.push({ i,a[i] }); } } } for (auto it = f.rbegin(); it != f.rend(); it++) { if (it == f.rbegin()) printf("%d", *it); else printf(" %d", *it); } return 0; }
HDU 1506
题目题意:题目给了n个矩形的高度,问最大连续矩形的公共面积(底乘以这段连续矩形中最短的高度),每个矩形的底是1
感觉有点像贪心,想了很久没想出单调栈的做法 事实上需要维护一个递增的矩形,每次出栈维护最大值
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<deque> #include<set> #include<map> #include<cmath> #include<stack> const double PI = acos(-1.0); #define INF 0x3f3f3f3f typedef long long ll; using namespace std; const int maxn = 100005; int a[maxn]; int s[maxn], w[maxn]; ll ans; int main() { int n; while (scanf("%d", &n) != EOF) { if (!n) break; int p = 0; ans = 0; for (int i = 1; i <=n; i++) scanf("%d", &a[i]); a[n+1] = 0; //注意设置a[0]=0,a[n+1]=0,因为最后一个也可能出栈 for (int i = 1; i <= n+1; i++) { if (a[i] > s[p]) s[++p] = a[i], w[p] = 1; //维护单调递增的栈 else { int wid = 0; while (s[p] > a[i]) { wid += w[p]; ans = max(ans, (ll)wid * s[p]); //core p--; } s[++p] = a[i]; w[p] = wid + 1; } } printf("%lld\n", ans); } return 0; }
POJ 3494 求一个0-1矩阵中全为1的最大子矩阵。
#include<iostream> #include<cstdio> #include<string> #include<algorithm> #include<queue> #include<deque> #include<set> #include<map> #include<cmath> #include<stack> const double PI = acos(-1.0); #define INF 0x3f3f3f3f typedef long long ll; using namespace std; const int maxn = 2010; int mp[maxn][maxn]; int h[maxn][maxn]; int L[maxn], R[maxn], st[maxn]; int main() { int n, m; while (scanf("%d%d", &n, &m) != EOF) { for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { scanf("%d", &mp[i][j]); } } for (int i = 0; i < m; i++) { int high = 0; for (int j = n - 1; j >= 0; j--) { if (mp[j][i]) high++; else high = 0; h[j][i] = high; } } int ans = 0; for (int i = 0; i < n; i++) { int pos = 0; for (int j = 0; j < m; j++) { while (pos > 0 && h[i][st[pos - 1]] >= h[i][j]) pos--; L[j] = pos == 0 ? 0 : st[pos - 1] + 1; st[pos++] = j; } pos = 0; for (int j = m - 1; j >= 0; j--) { while (pos > 0 && h[i][st[pos - 1]] >= h[i][j]) pos--; R[j] = pos == 0 ? m - 1 : st[pos - 1] - 1; st[pos++] = j; } for (int j = 0; j < m; j++) { ans = max(ans, h[i][j] * (R[j] - L[j] + 1)); } } printf("%d\n", ans); } return 0; }