《六月集训》第十六天——队列


前言

        。。。。。。。。。。。
刷题坚持每一天,以下题目引用自:力扣(LeetCode)

💎一、题目一

🏆1.题目描述

原题链接:933. 最近的请求次数

        写一个 RecentCounter 类来计算特定时间范围内最近的请求。
请你实现 RecentCounter 类:

  • RecentCounter() 初始化计数器,请求数为 0 。
  • int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。

保证 每次对 ping 的调用都使用比之前更大的 t 值。

示例 1:
输入:
[“RecentCounter”, “ping”, “ping”, “ping”, “ping”]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]
解释:
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1
recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2
recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3
recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3

🏆2.解题思路

🔑思路:

​         每一个新请求都入队,然后再判断队首的的请求时间是否在新请求之后的3000里,不在则出队。

🏆3.代码详解

typedef struct {
    int queue[10001];
    int head;
    int tail;
} RecentCounter;


RecentCounter* recentCounterCreate() {
    RecentCounter* obj = (RecentCounter*)malloc(sizeof(RecentCounter));
    obj->head = 0;
    obj->tail = 0;
    return obj;
}

int recentCounterPing(RecentCounter* obj, int t) {
    obj->queue[obj->tail++] = t;
    while(obj->queue[obj->head] < obj->queue[obj->tail-1]-3000){
        ++obj->head;
    } 
    return obj->tail - obj->head;
}

void recentCounterFree(RecentCounter* obj) {
    free(obj);
}

💎二、题目二

🏆1.题目描述

原题链接:1700. 无法吃午餐的学生数量

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

  • 如果队列最前面的学生 喜欢 栈顶的三明治,那么会 拿走它 并离开队列。
  • 否则,这名学生会 放弃这个三明治 并回到队列的尾部。

这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。
给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i​​​​​​ 个三明治的类型(i = 0 是栈的顶部), students[j] 是初始队列里第 j​​​​​​ 名学生对三明治的喜好(j = 0 是队列的最开始位置)。请你返回无法吃午餐的学生数量。

示例 1:
输入:students = [1,1,0,0], sandwiches = [0,1,0,1]
输出:0
解释:

  • 最前面的学生放弃最顶上的三明治,并回到队列的末尾,学生队列变为 students = [1,0,0,1]。
  • 最前面的学生放弃最顶上的三明治,并回到队列的末尾,学生队列变为 students = [0,0,1,1]。
  • 最前面的学生拿走最顶上的三明治,剩余学生队列为 students = [0,1,1],三明治栈为 sandwiches = [1,0,1]。
  • 最前面的学生放弃最顶上的三明治,并回到队列的末尾,学生队列变为 students = [1,1,0]。
  • 最前面的学生拿走最顶上的三明治,剩余学生队列为 students = [1,0],三明治栈为 sandwiches = [0,1]。
  • 最前面的学生放弃最顶上的三明治,并回到队列的末尾,学生队列变为 students = [0,1]。
  • 最前面的学生拿走最顶上的三明治,剩余学生队列为 students = [1],三明治栈为 sandwiches = [1]。
  • 最前面的学生拿走最顶上的三明治,剩余学生队列为 students = [],三明治栈为 sandwiches = []。
    所以所有学生都有三明治吃。

🏆2.解题思路

🔑思路:

​        先统计喜欢方形和圆形的各总人数,然后在根据栈顶三明治形状,判断有多少人吃不到三明治。

🏆3.代码详解

int countStudents(int* students, int studentsSize, int* sandwiches, int sandwichesSize){
    int ans[2] = {0};
    int i;
    for(i = 0; i < studentsSize; ++i)
        ++ans[students[i]];
    for(i = 0; i < sandwichesSize; ++i){
        if(ans[sandwiches[i]] == 0) break;
        --ans[sandwiches[i]];
    }
       
    return ans[0] + ans[1];
}

💎三、题目三

🏆1.题目描述

原题链接:2073. 买票需要的时间

        有 n 个人前来排队买票,其中第 0 人站在队伍 最前方 ,第 (n - 1) 人站在队伍 最后方 。
        给你一个下标从 0 开始的整数数组 tickets ,数组长度为 n ,其中第 i 人想要购买的票数为 tickets[i] 。
        每个人买票都需要用掉 恰好 1 秒 。一个人 一次只能买一张票 ,如果需要购买更多票,他必须走到 队尾 重新排队(瞬间 发生,不计时间)。如果一个人没有剩下需要买的票,那他将会 离开 队伍。
        返回位于位置 k(下标从 0 开始)的人完成买票需要的时间(以秒为单位)。

示例 1:
输入:tickets = [2,3,2], k = 2
输出:6
解释:
第一轮,队伍中的每个人都买到一张票,队伍变为 [1, 2, 1] 。
第二轮,队伍中的每个都又都买到一张票,队伍变为 [0, 1, 0] 。
位置 2 的人成功买到 2 张票,用掉 3 + 3 = 6 秒。

🏆2.解题思路

🔑思路:

​         每次买完票都出队,判断k位置的人是否需要买票,不需要返回时间。需要则在入队,直至k位置的人不需要买票;

🏆3.代码详解

typedef struct {
    int queue[10010];
    int head;
    int tail;
} RecentCounter;

int timeRequiredToBuy(int* tickets, int ticketsSize, int k){
    RecentCounter* obj = (RecentCounter*)malloc(sizeof(RecentCounter));
    obj->head = 0;
    obj->tail = 0;
    int time = 0;
    int flag = 0;
    for(int i = 0; i < ticketsSize; ++i){
        obj->queue[obj->tail++] = tickets[i] -= 1;
        ++time;
        if(i == k && tickets[i] == 0) return time;
    }
    while(1){
        obj->queue[obj->head] -= 1;
        obj->queue[obj->tail++] = obj->queue[obj->head];
        if(obj->queue[obj->head] >= 0) ++time;
        if(k == flag && obj->queue[obj->head] == 0) return time;
        ++obj->head;
        ++flag;
        if(flag == ticketsSize){
            flag = 0;
        }
    }
    return;
}

💎四、题目四

🏆1.题目描述

原题链接:239. 滑动窗口最大值

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

示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 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

🏆2.解题思路

🔑思路:

​         双端队列里保持单调递减,当前元素比队顶元素大则队顶元素出队,当前元素进队,当队列里的元素满足kk以上,把队头放入结果数组。判断队列里元素是否超出k个,超出则队头出队。

🏆3.代码详解

int* maxSlidingWindow(int* nums, int numsSize, int k, int* returnSize){
    
    int* ans = (int*)malloc(sizeof(int)*numsSize);
    int idx = 0;
    int queue[numsSize];
    int head = 0, tail = 0;
    for(int i = 0; i < numsSize; ++i){

        while(head < tail && nums[queue[tail-1]] < nums[i]) --tail;
        queue[tail++] = i;
        if(i >= k-1){
            ans[idx++] =  nums[queue[head]];  
            if(head < tail && i - queue[head] >= k-1) ++head;
        }
    }
    *returnSize = idx;
    return ans;
}

💎五、星球推荐

        星球链接:英雄算法联盟

星球里有什么?
        【朋友圈】一个极致精准的自律、编程、算法的小圈子。
        【算法集训】以月为单位组织算法集训,每天四题,风雨无阻。
        【排行榜】每天、每周都会有榜单,激励大家不断进步,不断成长。
        【个人规划】每个人都写好自己的规划,也可以查看他人的规划,时刻警醒自己不掉队。
        【打卡挑战】每日一题打卡、每日早起打卡、算法集训打卡、规划完成情况打卡。
在星球里做什么?
        目前星球人数达到520+,在星球里你能够遇到一群志同道合之人,因为都是花钱进来的,你不会看到任何浑水摸鱼的人,每个人都有自己的每月规划,星主每月都会组织算法集训,每天一起刷题,你可以看到别人的解题报告,取其之长,补己之短。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值