返回

无法吃午餐的学生数量解决分析题解详细解析

后端

LeetCode 1700 题:无法吃午餐的学生数量

在 LeetCode 的海量题目中,第 1700 题——无法吃午餐的学生数量,是一个考察算法设计能力和编程语言掌握程度的有趣题目。本文将深入分析这道题,并用 Java、C++ 和 Rust 三种语言进行代码实现,带你领略算法与编程的魅力。

题目要求

小明是一位热心的志愿者,负责分发饼干给一群饥肠辘辘的孩子。每个孩子都有一个胃口值,表示他可以吃掉多少饼干。小明手里也有一袋饼干,每个饼干都有一个大小。请你帮助小明找出无法得到足够饼干来满足胃口的孩子的数量。

算法设计

要解决这道题,我们可以使用贪婪算法。具体步骤如下:

  1. 将孩子们和饼干的胃口值和大小按照从小到大排序。
  2. 使用两个指针,一个指向孩子队列的头部,一个指向饼干队列的头部。
  3. 比较两个指针指向的元素,如果孩子的胃口值小于等于饼干的大小,则孩子可以吃掉饼干,两个指针都后移一位。
  4. 否则,孩子无法吃掉饼干,孩子队列的指针后移一位。
  5. 重复步骤 3 和 4,直到任意一个队列的指针到达队列尾部。
  6. 统计无法得到足够饼干的孩子数量。

代码实现

有了算法设计,我们就可以开始代码实现了。以下是 Java、C++ 和 Rust 三种语言的代码示例:

Java

import java.util.Arrays;

class Solution {
    public int countStudents(int[] children, int[] cookies) {
        Arrays.sort(children);
        Arrays.sort(cookies);

        int childIndex = 0;
        int cookieIndex = 0;

        int count = 0;
        while (childIndex < children.length && cookieIndex < cookies.length) {
            if (children[childIndex] <= cookies[cookieIndex]) {
                childIndex++;
                cookieIndex++;
            } else {
                count++;
                childIndex++;
            }
        }

        while (childIndex < children.length) {
            count++;
            childIndex++;
        }

        return count;
    }
}

C++

#include <algorithm>
#include <vector>

using namespace std;

class Solution {
public:
    int countStudents(vector<int>& children, vector<int>& cookies) {
        sort(children.begin(), children.end());
        sort(cookies.begin(), cookies.end());

        int childIndex = 0;
        int cookieIndex = 0;

        int count = 0;
        while (childIndex < children.size() && cookieIndex < cookies.size()) {
            if (children[childIndex] <= cookies[cookieIndex]) {
                childIndex++;
                cookieIndex++;
            } else {
                count++;
                childIndex++;
            }
        }

        while (childIndex < children.size()) {
            count++;
            childIndex++;
        }

        return count;
    }
};

Rust

use std::collections::VecDeque;

struct Solution;

impl Solution {
    pub fn count_students(children: Vec<i32>, cookies: Vec<i32>) -> i32 {
        let mut children = children;
        let mut cookies = cookies;

        children.sort_unstable();
        cookies.sort_unstable();

        let mut child_index = 0;
        let mut cookie_index = 0;

        let mut count = 0;

        while child_index < children.len() && cookie_index < cookies.len() {
            if children[child_index] <= cookies[cookie_index] {
                child_index += 1;
                cookie_index += 1;
            } else {
                count += 1;
                child_index += 1;
            }
        }

        while child_index < children.len() {
            count += 1;
            child_index += 1;
        }

        count
    }
}

常见问题解答

  1. 为什么需要排序?
    排序可以确保我们贪婪地分配饼干,从而得到最优解。

  2. 为什么使用两个指针?
    两个指针分别指向孩子队列和饼干队列的头部,可以高效地比较和更新元素。

  3. 算法的时间复杂度是多少?
    算法的时间复杂度为 O(n log n),其中 n 是孩子和饼干的总数。

  4. 算法的空间复杂度是多少?
    算法的空间复杂度为 O(1),因为我们不需要额外的空间。

  5. 如何提高算法的效率?
    如果我们知道孩子和饼干队列中元素的最大值和最小值,我们可以通过二分查找来进一步优化算法。