堆栈、队列、单调栈、单调队列

Stack和Queue——栈和队列

  • 栈的定义:栈是限定仅在表头进行插入和删除操作的线性表(先进后出)
  • 队列的定义:队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。(先进先出)
    stack常用函数:
  • push()——向栈顶压入元素
  • pop()——弹出栈顶元素
  • top()——访问栈顶元素
    queue常用函数:
  • front()——访问队首元素
  • back()——访问队尾元素
  • push()——向队尾插入元素
  • pop()——弹出队首元素

出栈顺序

题目描述:
有n个人,按照1,2,3...n的顺序依次进栈,判读能否以题目所给序列出栈。(n <= 100000)
eg:

  • 4 3 2 1
  • 1 2 3 4
  • 1 3 2 4
  • 1 4 2 3
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N];
int n;
stack<int> stk;
int main() {
	ios;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	int j = 1;
	for (int i = 1; i <= n; i++) {
		stk.push(i);
		while (!stk.empty() && a[j] == stk.top()) {
			stk.pop();
			j++;
		}
	}

	if (!stk.empty()) cout << "No";
	else cout << "Yes";


	return 0;
}

栈和排序

思路:
如果栈顶元素比后面没入栈的元素都大,那么它就应该出栈

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int a[N], maxn[N];	//maxn数组预处理后缀最大值
int n;
stack<int> stk;
int main() {
	ios;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	
	//预处理
	for (int i = n; i >= 1; i--) {
		maxn[i] = max(a[i], maxn[i + 1]);
	}

	for (int i = 1; i <= n; i++) {
		stk.push(a[i]);
		while (!stk.empty() && stk.top() > maxn[i + 1]) {	//还没进栈的元素是否没有比栈顶元素大的
			printf("%d ", stk.top());
			stk.pop();
		}
	}
	
	//如果栈内还有元素,就直接输出
	while (!stk.empty()) {
		printf("%d ", stk.top());
		stk.pop();
	}
	return 0;
}

好串

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
typedef long long LL;

string s;
stack<int> stk;
int main() {
	ios;
	cin >> s;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == 'a') {
			stk.push('a');
		} else {
			if (stk.empty()) {
				cout << "Bad" << endl;
				return 0;
			} else {
				stk.pop();
			}
		}
	}

	if (stk.empty()) cout << "Good";
	else cout << "Bad";
	return 0;
}

合并果子

思路:
思考易得,每次选择当前的果子数最少的两堆进行合并,花费的体力最少
维护两个队列
\(q1\)表示还没有合并的果子从小到大的序列
\(q2\)表示已经合并的果子的序列(自然从小到大,因为越合并果子数越大)
每次判断两个队列的队首元素大小小的出列合并完放入\(q2\)

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int a[N];
int n;
queue<int> q1, q2;
int main() {
	ios;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	sort(a + 1, a + 1 + n);
	for (int i = 1; i <= n; i++) {
		q1.push(a[i]);
	}

	int ans = 0;
	for (int i = 1; i < n; i++) {
		int x[3];
		for (int j = 1; j <= 2; j++) {
			if (q2.empty() || (!q1.empty() && q1.front() < q2.front())) {		//注意取q1的条件,q2为空,或者q1不为空,且q1队首小于q2队首
				x[j] = q1.front();
				q1.pop();
			} else {
				x[j] = q2.front();
				q2.pop();
			}
		}
		ans += x[1] + x[2];
		q2.push(x[1] + x[2]);
	}
	cout << ans << endl;
	return 0;
}

优先队列写法:

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define bug(x) cout<<#x<<"=="<<x<<endl;
using namespace std;
typedef long long LL;

const int N = 1e6 + 10;
int n;
int a[N];
priority_queue<int, vector<int>, greater<int> >q;
int main() {
	ios;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		q.push(a[i]);
	}

	LL ans = 0;
	for (int i = 1; i < n; i++) {
		int tmp1 = q.top();
		q.pop();
		int tmp2 = q.top();
		q.pop();
		ans += tmp1 + tmp2;
		q.push(tmp1 + tmp2);
	}

	cout << ans << endl;
	return 0;
}

滑动窗口(deque)

题目描述:
给定一个长度为n的数列,求长度为k的定长连续子区间{\(a_1,a_2,a_3,...a_{k-1},a_k\)},{\(a_2,a_3,...a_k,a_{k+1}\)}......中每个区间的最大值和最小值。

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long LL;

const int N = 1e6 + 10;
int n, k;
int a[N];
deque<int> maxn, minn;


int main() {
	ios;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}

	for (int i = 1; i <= n; i++) {
		if (!minn.empty() && i - minn.front() >= k) minn.pop_front();
		while (!minn.empty() && a[i] <= a[minn.back()]) {
			minn.pop_back();
		}
		minn.push_back(i);
		if (i >= k) cout << a[minn.front()];
	}

	cout << endl;

	for (int i = 1; i <= n; i++) {
		if (!maxn.empty() && i - maxn.front() >= k) maxn.pop_front();
		while (!maxn.empty() && a[i] >= a[maxn.back()]) {
			maxn.pop_back();
		}
		maxn.push_back(i);
		if (i >= k) cout << a[maxn.front()];
	}


	return 0;
}

Look up

Largest Rectangle in a Histogram

posted @ 2023-01-31 15:47  csai_H  阅读(47)  评论(0)    收藏  举报