Day9 数组模拟双向链表 数组模拟栈、队列 单调栈 滑动窗口(单调队列) KMP

数组模拟单链表其实就是链式前向星
只不过是多条链而已

双向链表的话,只需要多做几步即可
注意idx的起点
上一个单链表中起始是0,那么第k个就是k-1

现在idx起始时1,第k个就是k+1
传送门

#include

using namespace std;
const int N=1e5+10;
int l[N],r[N],val[N],idx;

void add(int k,int x){
    val[idx]=x;
    r[idx]=r[k],l[idx]=k;
    l[r[k]]=idx,r[k]=idx++;
}

void remove(int k){
    l[r[k]]=l[k];
    r[l[k]]=r[k];
}

int main(){
    int m;
    cin>>m;
    l[1]=0;
    r[0]=1;
    idx=2;
    while(m--){
        string op;
        cin>>op;
        int k,x;
        if(op=="L"){
            scanf("%d",&x);
            add(0,x);
        }else if(op=="R"){
            scanf("%d",&x);
            add(l[1],x);
        }else if(op=="D"){
            scanf("%d",&k);
            remove(k+1);
        }else if(op=="IL"){
            scanf("%d%d",&k,&x);
            add(l[k+1],x);
        }else {
            scanf("%d%d",&k,&x);
            add(k+1,x);
        }
    }
    for(int i=r[0];i!=1;i=r[i])cout<

数组模拟栈只需要一个tail变量就可以模拟
传送门

#include
using namespace std;
const int N=1e5+10;
int sta[N],tt;

void push(int x){
    sta[++tt]=x;
}

void pop(){
    tt--;
}

void ask(){
    printf("%d\n",sta[tt]);
}

int main(){
    int n;
    cin>>n;
    for(int i=0;i>op;
        if(op=="push"){
            scanf("%d",&x);
            push(x);
        }else if(op=="pop"){
            pop();
        }else if(op=="empty"){
            if(!tt){
                printf("YES\n");
            }else {
                printf("NO\n");
            }
        }else {
            
            ask();
        }
    }
    return 0;
}

数组模拟队列

也很简单
只需要头指针hh和尾指针tt
注意队列不为空时tt>=hh
传送门

#include

using namespace std;
const int N=1e5+10;
int q[N],tt=-1,hh;

void push(int x){
    q[++tt]=x;
}

void pop(){
    hh++;
}


int main(){
    int n;
    cin>>n;
    for(int i=0;i>op;
        int x;
        if(op=="push"){
            cin>>x;
            push(x);
        }else if(op=="pop"){
            pop();
        }else if(op=="empty"){
            if(hh>tt){
                printf("YES\n");
            }else {
                printf("NO\n");
            }
        }else {
            printf("%d\n",q[hh]);
        }
    }
    return 0;
}

单调栈

单调栈就是对于数组每个数,找到其左边最近的小于此数 的数

那么就是使得栈有单调性就可以
传送门

#include
using namespace std;
const int N=1e5+10;
int sta[N],tt;
int main(){
    int n,x;
    scanf("%d",&n);
    
    for(int i=0;i=x)tt--;//清除队列中比x大的数字
        
        if(tt)printf("%d ",sta[tt]);
        else printf("-1 ");
        sta[++tt]=x;                //x入栈
    }
    return 0;
}

单调队列
注意滑动窗口的滑出情况和单调情况即可
q[hh] a[q[tt]]<=a[i]这会使得队列递减
a[q[tt]]>=a[i]使得队列递增
传送门

#include

using namespace std;
const int N=1e6+10;
int q[N],a[N];

int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    
    for(int i=0;iq[hh])hh++;//滑动窗口左端滑出
        while(hh<=tt&&a[q[tt]]>=a[i])tt--;
        
        q[++tt]=i;
        if(i>=k-1)printf("%d ",a[q[hh]]);
    }
    
    puts("");
    
    tt=-1,hh=0;
    for(int i=0;i=a[q[tt]])tt--;
        
        q[++tt]=i;
        if(i>=k-1)printf("%d ",a[q[hh]]);
    }
    
    puts("");
    return 0;
}

关于KMP
以前我写的东西,自己现在也不想看了。。。

这个过程还是很复杂的
大概就是next[i]数组存放的是以i为终点的与前缀相同的长度
然后匹配目标串时就可以通过j=ne[j]来快速移动模式串

求next数组过程和匹配的过程一样,求next数组时注意要从2开始
还有不能用next编码
i、j从1开始计算,因为当j==0时,j=ne[j]是无意义的

传送门

#include
using namespace std;

const int N=1e5+10,M=1e6+10;
char p[N],s[M];
int n,m,ne[N];

int main(){
    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);
        }
    }
    return 0;
}

你可能感兴趣的:(日更学习)