初识队列 (例题)

队列的学习可以类比栈。队列是实现广度优先搜索的重要数据结构。 

queue<int> aa; //定义一个队列

——队列的基本操作——

aa.front() //返回队列的第一个元素
aa.back()  //返回队列的最后一个元素
aa.empty() //如果队列为空则返回真
aa.push()  //在队列末尾加一个元素
aa.pop()   //删除队列首端的一个元素
aa.size()  //返回队列中的元素个数

例一  无法吃午餐的学生数量 (leetcode 1700)

https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/

 题目描述:

学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。
餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个栈里,每一轮:

如果队列最前面的学生喜欢栈顶的三明治,那么会拿走它并离开队列。
否则,这名学生会放弃这个三明治并回到队列的尾部。
这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。

给你两个整数数组students和sandwiches,其中 sandwiches[i] 是栈里面第 i​​​​​​ 个三明治的类型(i = 0 是栈的顶部,students[j] 是初始队列里第 j​​​​​​ 名学生对三明治的喜好(j = 0 是队列的最开始位置)。请你返回无法吃午餐的学生数量。

示例:

题目分析:

题目的要求是有一个食物栈和一个学生队列,栈和队列的长度相同。根据题意,使用循环
每一次循环中,比较栈顶数据是否和队头数据相同;
相同,出栈,出队;
不同,出队,入队(中间变量);
当队列中所有元素的数据与栈顶的数据不同时,返回队列元素的个数即为解。

循环的次数
由于无法确定何时跳出循环,不知道下一次循环会不会有学生可以获得三明治。
但是我们知道当队列中所有学生都不吃栈顶的三明治时就可以跳出循环;
所以可以把循环次数设为一个变量,是队列的长度。
每当队列长度发生变化,将循环变量i置为-1,即可进入下一次的循环。

题解代码:

class Solution {
public:
    int countStudents(vector<int>& students, vector<int>& sandwiches) {
         stack<int> aa;
         queue<int> bb;

         for(int i=sandwiches.size()-1;i>=0;i--){
             aa.push(sandwiches[i]);
         }

         for(int j=0;j<students.size();j++){
             bb.push(students[j]);
         }

         int k=0;
         while(1){
             if(bb.empty()){
                 break;
             }

             if(bb.front()==aa.top()){
                 bb.pop();
                 aa.pop();
                 k=0;

             }else{
                 bb.push(bb.front());
                 bb.pop();
                 k++;      //用k来记录剩余元素是否与栈顶元素比较

                 if(k==bb.size()){
                      break;
                 }
             }

         }

         return bb.size();
    }
};

例二  跳跃游戏 VI(leetcode 1696) 

https://leetcode-cn.com/problems/jump-game-vi/https://leetcode-cn.com/problems/jump-game-vi/题目描述:

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

一开始你在下标 0 处。每一步,你最多可以往前跳 k 步,但你不能跳出数组的边界。也就是说,你可以从下标 i 跳到 [i + 1, min(n - 1, i + k)] 包含 两个端点的任意位置。

你的目标是到达数组最后一个位置(下标为 n - 1 ),你的得分为经过的所有数字之和。

请你返回你能得到的最大得分 。

示例1:

示例2:

题目分析:

我们维护一个双端的单调递减队列(从队头到队尾的值递减,但是这里只保存下标)对于每个入队的元素,我们依次将其的值与队列尾部元素的值去做比较,如果当前元素更大,我们就将队尾元素弹出,重复这个过程,直到队列为空或者当前元素小于队尾元素,再插入当前元素,最后取出符合条件的队头元素(最大值)即可。

图解:

 题解代码:

class Solution {
public:
    int maxResult(vector<int>& nums, int k) {
        deque<pair<int,int>> aa;

        aa.emplace_back(nums[0],0);

        int n=nums.size();
        int count=nums[0];

        for(int i=1;i<n;i++){
            while(aa.front().second + k < i){
                  aa.pop_front();
            }

            count=nums[i] + aa.front().first;

            while(!aa.empty() && count >= aa.back().first){
                  aa.pop_back();
            }

            aa.emplace_back(count,i);
        }

        return count;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值