zoukankan      html  css  js  c++  java
  • 数组模拟队列&栈

    数组模拟队列&栈

    #include<iostream>
    
    using namespace std;
    
    const int N=100010;
    
    int stk[N],tt;//栈一般定义为stk[N],tt为栈点下标,栈习惯上从0开始
    //插入 
    skt[++tt]=x;//表示在栈顶加入一个新的元素 
    //弹出
    tt--;
    //判断栈是否为空
    if(tt>0)//说明不空
    else //empty 
    //栈顶元素
    stk[tt]; 
    

    队列

    //模拟队列
    int q[N],hh,tt=-1;//队列习惯上从-1开始
    //插入
    q[++tt]=x;
    //弹出
    hh++;//将队头的指针向后移动一位则为弹出
    //判断是否为空
    if(hh<=tt) not empty
    else empty
    //取出队头元素
    q[hh];
    //还可以取出队尾
    q[tt]; 
    

    单调栈

    题目:

    输入一串数字,找到每一个数字所对应的在他左边离他最近且比他小的数,如果有这个数,则输出,若无,则输出-1

    #include<iostream>
    
    using namespace std;
    
    const int N=100010;
    
    int n;
    int stk[N],tt;
    
    int main()
    {
    	cin>>n;
    	for(int i=0;i<n;i++)
    	{
    		int x;
    		cin>>x;
    		while(tt&&stk[tt]>=x) tt--;//当栈非空并且栈顶元素大于此时读入的这个x,那么这个栈顶元素就再也不会被用到了,因为要让序列为单调递增 
    		if(tt) cout<<stk[tt]<<' ';//若栈非空,则说明该栈顶元素为离他最近的一个小于它的元素
    		else	cout<<-1<<' ';//否则说明找不到这样的数,则返回-1
    		
    		stk[++tt]=x;//最后要记得把该数再插回到队列当中
    	}
    	return 0;
    }
    

    单调队列

    题目:

    给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

    返回滑动窗口中的最小值和最大值。

    示例 1:
    
    输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
    输出:	[-1,-3,-3,-3,3,3]
    	  [3,3,5,5,6,7]
    解释:
    滑动窗口的位置                最大值
    
    ---------------               -----
    
    [1  3  -1] -3  5  3  6  7       3
     1 [3  -1  -3] 5  3  6  7       3
     1  3 [-1  -3  5] 3  6  7       5
     1  3  -1 [-3  5  3] 6  7       5
     1  3  -1  -3 [5  3  6] 7       6
     1  3  -1  -3  5 [3  6  7]      7
    
    

    思路:

    用一个队列来存,当窗口在滑动时,将即将要滑到的元素插入到队尾,将即将要划走的元素从队头弹出来。

    在找到最值时,若用遍历枚举的话,会造成时间复杂度高,则此处和单调栈相同思路,先用暴力做法,再看在栈和队列中有哪些元素是没有用到的,将这些元素删掉后,再去看剩下的元素是否具有单调性,即可优化:

    若取极值则取端点,若取某个点则用二分法

    代码:

    #include<iostream>
    
    using namespace std;
    
    const int N=1000010;
    
    int n,k;
    int a[N],q[N];//a存原来的值,q存的是单调队列
     
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=0;i<n;i++) scanf("%d",&a[i]);
    	
    	//最小值队列 
    	int hh=0,tt=-1;//定义一下队头和队尾 
    	for(int i=0;i<n;i++)
    	{
    		//判断队头是否已经滑出窗口 
    		if(hh<=tt &&i-k+1>q[hh])//前者判断是否空 ,后者判断是否已经滑出窗口 
    			hh++;
    		while(hh<=tt && a[q[tt]]>=a[i])
    			tt--;//若队尾的数大于或等于即将进来的数,则将队尾的数出队 
    		q[++tt]=i;//将当前的数插到队列中 
    		if(i>=k-1) printf("%d ",a[q[hh]]);// 
    	}
    		puts("");
    		
    		
    	//最大值与最小值完全一致	
    	hh=0,tt=-1;//定义一下队头和队尾 
    	for(int i=0;i<n;i++)
    	{
    		//判断队头是否已经滑出窗口 
    		if(hh<=tt &&i-k+1>q[hh])//前者判断是否空 ,后者判断是否已经滑出窗口 
    			hh++;
    		while(hh<=tt && a[q[tt]]<=a[i])
    			tt--;//若队尾的数大于或等于即将进来的数,则将队尾的数出队 
    		q[++tt]=i;//将当前的数插到队列中 
    		if(i>=k-1) printf("%d ",a[q[hh]]);// 
    	}
    		puts("");
    		return 0;
    } 
    
  • 相关阅读:
    MIne FirstBlog
    P6563 [SBCOI2020]一直在你身旁
    P6563 [SBCOI2020]一直在你身旁
    T122085 [SBCOI2020]时光的流逝
    LC 918. Maximum Sum Circular Subarray
    1026 Table Tennis
    LC 1442. Count Triplets That Can Form Two Arrays of Equal XOR
    LC 1316. Distinct Echo Substrings
    LC 493. Reverse Pairs
    1029 Median (二分)
  • 原文地址:https://www.cnblogs.com/fzujly/p/14648064.html
Copyright © 2011-2022 走看看