文章

[LeetCode] 每日一题 781. 森林中的兔子(贪心 + 计数)

题目描述

森林中有未知数量的兔子。提问其中若干只兔子 "还有多少只兔子与你(指被提问的兔子)颜色相同?" ,将答案收集到一个整数数组 answers 中,其中 answers[i] 是第 i 只兔子的回答。

给你数组 answers ,返回森林中兔子的最少数量。

题目链接

https://leetcode.cn/problems/rabbits-in-forest

示例输入

示例 1

输入:answers = [1,1,2]
输出:5
解释:
两只回答了 "1" 的兔子可能有相同的颜色,设为红色。 
之后回答了 "2" 的兔子不会是红色,否则他们的回答会相互矛盾。
设回答了 "2" 的兔子为蓝色。 
此外,森林中还应有另外 2 只蓝色兔子的回答没有包含在数组中。 
因此森林中兔子的最少数量是 5 只:3 只回答的和 2 只没有回答的。

示例 2

输入:answers = [10,10,10]
输出:11

提示

  • 1 <= answers.length <= 1000

  • 0 <= answers[i] < 1000

解题思路

这道题属于典型的贪心 + 计数类问题,题目要求我们根据若干只兔子的回答,推测森林中兔子的最少数量。

每只兔子的回答是:还有多少只兔子和它颜色相同。例如,如果某只兔子回答 2,意味着它知道还有 2 只兔子和它颜色相同,它们组成了一个大小为 3 的同色兔子群体(它自己加上回答的数量)

那我们的问题就转化成了:如何用这些回答去拼出森林中最少的兔子数量

贪心思路

如果我们看到有很多兔子都回答 2,我们自然倾向于把这些兔子尽可能多地归入同一个颜色组(这样可以减少总的兔子数量)。

更具体地说:

  • 如果有 cnt 只兔子都回答了 y

  • 那我们最多每 (y + 1) 个兔子分为一组,表示一组颜色;

  • 需要的组数是 ceil(cnt / (y + 1))

  • 每组都要补齐成 y + 1 个兔子,所以兔子总数为:ceil(cnt / (y + 1)) * (y + 1)

代码实现

class Solution {
    public int numRabbits(int[] answers) {
        HashMap<Integer, Integer> count = new HashMap<>();
        for (int answer : answers) {
            count.put(answer, count.getOrDefault(answer, 0) + 1);
        }
        int ans = 0;
        for (Integer key : count.keySet()) {
            int cnt = count.get(key);
            ans += (cnt + key) / (key + 1) * (key + 1);
        }
        return ans;
    }
}

复杂度分析

  • 时间复杂度:O(n) 🚀
    遍历一次 answers 数组,之后遍历哈希表中的 key,都是线性操作

  • 空间复杂度:O(n) 🧠
    最坏情况下,每只兔子的回答都不同,需要一个长度为 n 的哈希表

总结

这题的本质是抽象建模 + 贪心分组。关键在于理解每一个回答实际上在定义一个颜色组的大小,而题目让我们以最节省的方式进行分组。这种题目非常适合培养我们对“最值问题”的贪心直觉 💡

希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。

License:  CC BY 4.0