♥
不开 O2 / O3 优化时
用数组模拟 STL 的速度更快
♥
单链表
//这样写就是,比较浪费空间(大概)
int head = -1, cnt = 0; // 头结点初始化为 -1
int a[N], nxt[N]; // a 存自身数据,nxt 存相邻结点下标
// 在第 k 个插入的结点后插入 x, k == 0 时表示在表头处插入
int Insert(int k, int x)
{
a[cnt] = x;
if(k == 0)
{
nxt[cnt] = head;
head = cnt ++ ;
}
else
{ // 先与后面的结点相连,以免断开
nxt[cnt] = nxt[k - 1]; // 下标从 0 开始,故要减一
nxt[k - 1] = cnt ++ ;
}
}
//删除第 k 个插入的结点后 的结点, k == 0 时表示删除头结点
int Delete(int k)
{
if(k == 0) head = nxt[head];
else
{
int nt = nxt[k - 1];
nxt[k - 1] = nxt[nt]; // 直接与下下个结点连接
}
}
♥
双链表
输入样例
10
R 7
D 1
L 3
IL 2 10
D 3
IL 2 7
L 8
R 9
IL 4 7
IR 2 2
♥
输出样例
8 7 7 3 2 9
♥
代码
//♥
#include <iostream>
using namespace std;
const int N= 1e5 + 5;
int m, x, cnt;
int a[N], l[N], r[N];
// 在第 k 个插入的数右边插入 x
void Add(int k, int x)
{
a[cnt] = x;
l[cnt] = k;
r[cnt] = r[k];
l[r[k]] = cnt;
r[k] = cnt;
cnt ++ ;
}
void Del(int k)
{
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main()
{
cin >> m;
//初始化,设 0 为起始结点,1 为末尾结点
r[0] = 1; // 起始节点仅有右边有结点相连,初始时与末尾结点相连
l[1] = 0;
cnt = 2; // 输入的结点从 2 开始
while(m -- )
{
string op;
cin >> op >> x;
if(op == "L") Add(0, x);
else if(op == "R") Add(l[1], x); // 在最右端,即是末尾结点左边结点的右边
else if(op == "D") Del(x + 1);
else
{
int k;
cin >> k;
if(op == "IL") Add(l[x + 1], k); // 因为下标从 2 开始 → x + 1
// 插入该结点的左侧 → 左相邻结点的右侧
else Add(x + 1, k);
}
}
for(int i = r[0]; i != 1; i = r[i]) printf("%d ",a[i]);
return 0;
}
♥
栈
先进后出
//♥
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int m, cnt = 0;
int a[N];
int main()
{
int m;
cin >> m;
while(m -- )
{
string op;
cin >> op;
if(op == "push")
{
int x;
cin >> x;
a[cnt++] = x;
}
else if(op == "pop") cnt--;
else if(op == "empty")
if(cnt == 0) puts("YES");
else puts("NO");
else printf("%d\n",a[cnt - 1]);
}
return 0;
}
♥
Tips:C++ 中 整除默认向0取整
仅包含
+,- , *, /
以及括号 ‘(’ ‘)’ 的表达式
其中保证 ‘-’ 在算式中,只代表减号,不会表示负数。
♥
代码
//♥
#include <iostream>
#include <stack>
#include <unordered_map>
using namespace std;
const int N = 1e5 + 5;
stack<int> a; // 存放 数
stack<char> op; // 存放 操作符
// 限定运算符的优先级
// 使用无序的更省时间,否则每次插入都会进行排序
unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
//判断是否是数字
bool check(char x)
{
return x >= '0' && x <= '9';
}
void Cal()
{
// 栈 先进后出,减和除的顺序都不能反,所以在开头取值的时候纠正了
int y = a.top();
a.pop();
int x = a.top();
a.pop();
char p = op.top();
op.pop();
int res;
if(p == '+') res = x + y;
else if(p == '-') res = x - y;
else if(p == '*') res = x * y;
else res = x / y;
a.push(res);
}
int main()
{
string s;
cin >> s;
for(int i = 0; i < s.size(); i ++ )
{
if(check(s[i]))
{
int j = i, x = 0;
while(j < s.size() && check(s[j])) x = x * 10 + (s[j++] - '0'); // 提取数字
a.push(x);
i = j - 1;
}
else if(s[i] == '(') op.push(s[i]);
else if(s[i] == ')')
{
while(op.top() != '(') Cal();
op.pop(); // 把 '(' 取出
}
else
{
while(op.size() && op.top() != '(' && pr[op.top()] >= pr[s[i]]) Cal();
op.push(s[i]);
}
}
while(op.size()) Cal();
cout << a.top() << endl;
return 0;
}
♥
队列
队列嘛,懂得都懂,前进先出!
♥
代码
//♥
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int m, l = 1, r = 0;
int a[N];
int main()
{
cin >> m;
while(m -- )
{
string op;
cin >> op;
if(op == "push")
{
int x;
cin >> x;
a[++r] = x;
}
else if(op == "pop") l++;
else if(op == "empty") (l>r) ? puts("YES") : puts("NO");
else cout << a[l] << endl;
}
return 0;
}
♥
单调栈
♥
int cnt = 0;
for(int i = 1; i <= n; i ++ )
{
while( cnt && check()) cnt--;
st[++cnt] = i;
}
输出每个数左边,第一个比 它本身 小的数
♥
代码
//♥
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, cnt = 0;
int a[N], st[N];
int main()
{
cin >> n;
for(int i = 0; i < n; i ++ ) cin >> a[i];
for(int i = 0; i < n; i ++ )
{
while(cnt && st[cnt] >= a[i]) cnt--;
if(cnt == 0) printf("-1 ");
else printf("%d ",st[cnt]);
st[++cnt] = a[i];
}
return 0;
}
♥
单调队列
♥
int l = 0, r = -1;
for(int i = 0; i < n; i ++ )
{
while(l <= r && check_out()) l++; // 判断队头是否在窗口内
while(l <= r && check()) r --;
q[++r] = i;
}
//♥
#include <iostream>
using namespace std;
const int N = 1e6 + 5;
int n, k;
int l = 1, r = 0;
int a[N], q[N];
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) scanf("%d",&a[i]);
//取窗口内 最小值
for(int i = 1; i <= n; i ++ )
{
while(l <= r && i - q[l] + 1 > k) l ++ ; // 确保 队头元素位置 未滑出窗口
while(l <= r && a[q[r]] >= a[i]) r -- ; // 若队尾元素大于 a[i] , 则往后可选a[q[r]]的,一定可选a[i]最佳
q[++r] = i; // 若 a[i] 大于 队尾元素, 在队尾元素滑出窗口后, a[i] 仍可能作为答案
if(i >= k) printf("%d ",a[q[l]]);
}
puts("");
l = 1, r = 0; // 初始化,清空一下队列
for(int i = 1; i <= n; i ++ )
{
while(l <= r && i - q[l] + 1 > k) l ++ ;
while(l <= r && a[q[r]] <= a[i]) r -- ;
q[++r] = i;
if(i >= k) printf("%d ",a[q[l]]);
}
return 0;
}
♥