LeetCode 458. 可怜的小猪
题目描述


题意分析
buckets桶液体中恰好一桶有毒。每轮可以让活猪同时喝任意多桶液体,等待minutesToDie分钟后,喝到毒药的猪死亡。要在minutesToTest分钟内确定毒桶,求最少需要几头猪。
解法:状态计数 + 整数容量累乘
核心思路
[!blue]
可完成的完整观察轮数为
rounds = minutesToTest / minutesToDie。一头猪的结果不只有生和死,还能区分第几轮死亡:第 1 轮到第rounds轮死亡,或测试结束仍存活,共有states = rounds + 1种结果。
p头猪最多给出states^p种结果组合,每个毒桶都必须对应不同组合,因此必须满足states^p >= buckets。否则至少两桶会产生相同观察结果,无法区分。这个下界可以达到:给每桶分配一个不同的
states进制编号,使用p位,每一位对应一头猪。把数字 0 约定为一直存活,数字r约定为第r轮死亡。在第r轮,让每头活猪喝下所有“对应位等于r”的桶里的液体。若毒桶对应位为r,这头猪此前不会接触毒液,恰好在这一轮死亡;对应位为 0 则一直喝不到毒液。最后所有猪的结果就能还原毒桶编号。因此只需求让容量覆盖桶数的最小
p。从 0 头猪、容量 1 开始,每增加一头猪就把容量乘以states,首次达到或超过桶数时停止,避免使用浮点对数处理整数边界。
解题步骤
- 计算完整轮数
rounds和每头猪的状态数states = rounds + 1。- 初始化
pigs = 0、capacity = 1。- 只要
capacity < buckets,就将容量乘以states,并令pigs++。- 返回
pigs。只有一桶时无需实验,初始容量就足够,返回 0。题目保证
minutesToDie <= minutesToTest,因此至少能观察一轮,states >= 2,容量会严格增长并最终满足条件。
代码实现
class Solution {
public int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
int rounds = minutesToTest / minutesToDie;
// 每轮死亡和始终存活分别形成可区分状态。
int states = rounds + 1;
int pigs = 0;
// 零头猪只能表示一个结果,恰好覆盖单桶情形。
long capacity = 1;
while (capacity < buckets) {
capacity *= states;
pigs++;
}
return pigs;
}
}
func poorPigs(buckets int, minutesToDie int, minutesToTest int) int {
rounds := minutesToTest / minutesToDie
// 每轮死亡和始终存活分别形成可区分状态。
states := rounds + 1
pigs := 0
// 零头猪只能表示一个结果,恰好覆盖单桶情形。
capacity := int64(1)
for capacity < int64(buckets) {
capacity *= int64(states)
pigs++
}
return pigs
}
复杂度分析
- 时间复杂度:$O(1+\log_{states}buckets)$,循环次数等于所需猪数。
- 空间复杂度:$O(1)$。
关键点总结
[!green]
- 测试结束仍存活也是一个状态。
- 状态数给出必要下界,按进制位安排喂水说明下界可达。
- 不足一个完整观察周期的时间不能算新一轮。
易错点总结
[!yellow]
- 漏掉存活状态:低估每头猪可区分的结果数。
- 容量恰好相等仍继续循环:多算一头。
- 轮数向上取整:使用了无法完成观察的轮次。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 887. 鸡蛋掉落 | 困难 | 同样按实验能区分的状态数量推导所需资源,原题受鸡蛋损坏影响,本题每只猪可表示死亡轮次或存活结果。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!