数组模拟单链表
模板
int head, e[N], ne[N], idx;
void init()
{
head = -1;
idx = 0;
}
void insert(int a)
{
e[idx] = a, ne[idx] = head, head = idx ++ ;
}
void remove()
{
head = ne[head];
}
例题Acwing826
#include<iostream>
using namespace std;
const int N=100010;
int idx,head,e[N],ne[N];
int a;
void add_head(int x){
e[idx]=x;
ne[idx]=head;
head=idx++;
}
void add(int k,int x){
e[idx]=x;
ne[idx]=ne[k];
ne[k]=idx++;
}
void remove(int k){
ne[k]=ne[ne[k]];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
head=-1;idx=0;
cin>>a;
while(a--){
string op;
int k,x;
cin>>op;
if(op=="D")
{
cin>>k;
if(!k)head=ne[head];
remove(k-1);
}
else if(op=="H")
{
cin>>x;
add_head(x);
}
else if(op=="I"){
int k,x;
cin>>k>>x;
add(k-1,x);
}
}
for(int i=head;i!=-1;i=ne[i])
cout<<e[i]<<" ";
return 0;
}
数组模拟单链表注意点:
忘记单独考虑删除头结点是经常犯的错误!!!
1.超时多半是没有调用init()函数进行初始化
2.因为前后两个节点没有练习,所以不能调用
ne[k+1],应该用ne[ne[k]]
3.注意删除结点的时候要单独考虑头结点!!!
数组模拟双链表
模板
int e[N], l[N], r[N], idx;
void init()
{
r[0] = 1, l[1] = 0;
idx = 2;
}
void insert(int a, int x)
{
e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx, r[a] = idx ++ ;
}
void remove(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
例题Acwing827
#include<iostream>
using namespace std;
const int N = 1e5+10;
int m, k, x;
int e[N], l[N], r[N], idx;
void init(){
r[0] = 1, l[1] = 0;
idx = 2;
}
void insert(int k, int x){
e[idx] = x;
l[idx] = k, r[idx] = r[k];
l[r[k]] = idx, r[k] = idx++;
}
void remove(int k){
l[r[k]] = l[k];
r[l[k]] = r[k];
}
int main(){
init();
cin >> m;
string op;
while(m--){
cin >> op;
if(op == "L"){
cin >> x;
insert(0, x);
}
else if(op == "R"){
cin >> x;
insert(l[1], x);
}
else if(op == "IL"){
cin >> k >> x;
insert(l[k + 1], x);
}
else if(op == "IR"){
cin >> k >> x;
insert(k + 1, x);
}
else if(op == "D"){
cin >> k;
remove(k + 1);
}
}
for(int i = r[0]; i != 1; i = r[i] )
cout << e[i] << " ";
return 0;
}
模板
int stk[N], tt = 0;
stk[ ++ tt] = x;
tt -- ;
stk[tt];
if (tt > 0)
{
}
例题Acwing828
#include<iostream>
using namespace std;
const int N = 1e5+10;
int stk[N], top;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int m, x;
string op;
cin >> m;
while(m--){
cin >> op;
if(op == "push"){
cin >> x;
stk[top++] = x;
}
else if(op == "pop"){
--top;
}
else if(op == "empty"){
if(top) printf("NO\n");
else printf("YES\n");
}
else
printf("%d\n", stk[top-1]);
}
return 0;
}
模拟队列
int q[N], hh = 0, tt = -1;
q[ ++ tt] = x;
hh ++ ;
q[hh];
if (hh <= tt)
{
}
例题
#include<iostream>
using namespace std;
const int N = 1e5+10;
int q[N], hh, tt;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int m, x;
string op;
cin >> m;
while(m--){
cin >> op;
if(op == "push"){
cin >> x;
q[tt++] = x;
}
else if(op == "pop"){
hh++;
}
else if(op == "empty"){
if(hh < tt) printf("NO\n");
else printf("YES\n");
}
else printf("%d\n", q[hh]);
}
return 0;
}
单调栈
找出每个数左边离它最近的比它大/小的数
模板
常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
例题Acwing830
#include<iostream>
using namespace std;
const int N = 1e5+10;
int stk[N], tt;
int main(){
int m;
scanf("%d", &m);
while(m--){
int x;
scanf("%d", &x);
while(tt && stk[tt] >= x) tt--;
if(!tt) printf("-1 ");
else printf("%d ", stk[tt]);
stk[++tt] = x;
}
return 0;
}
单调队列
单调队列应用->滑动窗口问题
模板
常见模型:找出滑动窗口中的最大值/最小值
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
while (hh <= tt && check_out(q[hh])) hh ++ ;
while (hh <= tt && check(q[tt], i)) tt -- ;
q[ ++ tt] = i;
}
例题Acwing154
因为本题涉及的窗口每次只滑动一个位置,所以只需要用一个if来判断就可以了,但是如果是一次移动两个以上的位置,就需要用while循环来判断是否将队头元素滑出队列q 关于判断是否滑出:i - k + 1是当前元素结尾时候窗口的最左侧窗口元素的下标,和q[hh] (前一步的窗口最左侧元素下标) 每次输出q[hh]有递归的感觉 注意每次往q中入队的都是i,即下标,不是元素
#include<iostream>
using namespace std;
const int N = 1e6+10;
int a[N], q[N], hh, tt;
int main(){
int m, k;
scanf("%d%d", &m, &k);
for(int i = 0; i < m; i++){
scanf("%d", &a[i]);
if(i - k + 1 > q[hh]) hh++;
while(hh <= tt && a[i] <= a[q[tt]]) tt--;
q[++tt] = i;
if(i + 1 >= k) printf("%d ", a[q[hh]]);
}
printf("\n");
hh = 0, tt = 0;
for(int i = 0; i < m; i++){
if(i - k + 1 > q[hh]) hh++;
while(hh <= tt && a[i] >= a[q[tt]]) tt--;
q[++tt] = i;
if(i + 1 >= k) printf("%d ", a[q[hh]]);
}
return 0;
}
KMP字符串
模板
求模式串的Next数组:
for (int i = 2, j = 0; i <= m; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
for (int i = 1, j = 0; i <= n; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == m)
{
j = ne[j];
}
}
注意while循环是找到p[i] != p[j+1]过后就停止了,不会再进行一步j = ne[j]。关键理解找不相等字符对应的j位置,再更新ne[i]
例题Acwing831
因为下标要从1开始,所以读入的时候要进行加1操作
#include<iostream>
using namespace std;
const int M = 1e5+10, N = 1e6+10;
char p[M], s[N];
int ne[M];
int main(){
int n, m;
cin >> n >> p + 1 >> m >> s + 1;
for(int i = 2, j = 0; i <= n; i++){
while(j && p[i] != p[j+1]) j = ne[j];
if(p[i] == p[j + 1]) j++;
ne[i] = j;
}
for(int i = 1, j = 0; i <= m; i++){
while(j && s[i] != p[j + 1]) j = ne[j];
if(s[i] == p[j + 1]) j++;
if(j == n){
printf("%d ", i - n);
j = ne[j];
}
}
return 0;
}
|