【LeetCode】无法吃午餐的学生数量Java题解

74 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

题目描述

学校的自助午餐提供圆形和方形的三明治,分别用数字 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:

输入:students = [1,1,1,0,0,1], sandwiches = [1,0,0,0,1,1]
输出:3

思路分析

  • 今天的算法题目是数组类型题目。题目比较长,简单来说,就是学校提供两种规格的三明治,学生只吃自己喜欢的三明治,当遇到不喜欢的三明治的时候,需要重新排队获取三明治,需要返回无法吃午餐的学生数量。
  • 我们首先可以使用朴素解法,直接模拟这个过程。采用双端队列,首先将students和sandwiches一起放入队列,然后比较sandwiches队首是否和students队首相同,如果相同,同时出队。如果不同,则调整 students 队列的顺序。在实际操作中,我们使用Deque这种数据结构来操作这个过程,Deque的特性是一个可以在队首/队尾插入或删除元素的队列。相当于是栈与队列功能的结合,使用起来非常方便。
  • 具体实现代码如下,供参考。

通过代码

class Solution {
    public int countStudents(int[] students, int[] sandwiches) {
        Deque<Integer> studentsStack = new ArrayDeque<>();
        Deque<Integer> sandwichesStack = new ArrayDeque<>();
        for (int student : students) {
            studentsStack.offerLast(student);
        }
        for (int sandwich : sandwiches) {
            sandwichesStack.offerLast(sandwich);
        }
        int cnt = 0;
        while (!studentsStack.isEmpty() && !sandwichesStack.isEmpty()) {
            int n = studentsStack.size();
            if (sandwichesStack.getFirst().equals(studentsStack.getFirst())) {
                sandwichesStack.removeFirst();
                studentsStack.removeFirst();
                cnt = 0;
            } else {
                studentsStack.offerLast(studentsStack.removeFirst());
                cnt++;
            }
            if (cnt >= n) {
                break;
            }
        }
        return studentsStack.size();
    }
}

总结

  • 上述算法的时间复杂度是O(n),空间复杂度是O(n)
  • 坚持算法每日一题,加油!我会继续更新,也欢迎算法爱好者一起交流学习。