跳至主要內容

458. 可怜的小猪


458. 可怜的小猪

🔴   🔖  数学 动态规划 组合数学  🔗 力扣open in new window LeetCodeopen in new window

题目

There are buckets buckets of liquid, where exactly one of the buckets is poisonous. To figure out which one is poisonous, you feed some number of (poor) pigs the liquid to see whether they will die or not. Unfortunately, you only have minutesToTest minutes to determine which bucket is poisonous.

You can feed the pigs according to these steps:

  1. Choose some live pigs to feed.
  2. For each pig, choose which buckets to feed it. The pig will consume all the chosen buckets simultaneously and will take no time. Each pig can feed from any number of buckets, and each bucket can be fed from by any number of pigs.
  3. Wait for minutesToDie minutes. You may not feed any other pigs during this time.
  4. After minutesToDie minutes have passed, any pigs that have been fed the poisonous bucket will die, and all others will survive.
  5. Repeat this process until you run out of time.

Given buckets, minutesToDie, and minutesToTest, return theminimum number of pigs needed to figure out which bucket is poisonous within the allotted time.

Example 1:

Input: buckets = 4, minutesToDie = 15, minutesToTest = 15

Output: 2

Explanation: We can determine the poisonous bucket as follows:

At time 0, feed the first pig buckets 1 and 2, and feed the second pig buckets 2 and 3.

At time 15, there are 4 possible outcomes:

  • If only the first pig dies, then bucket 1 must be poisonous.
  • If only the second pig dies, then bucket 3 must be poisonous.
  • If both pigs die, then bucket 2 must be poisonous.
  • If neither pig dies, then bucket 4 must be poisonous.

Example 2:

Input: buckets = 4, minutesToDie = 15, minutesToTest = 30

Output: 2

Explanation: We can determine the poisonous bucket as follows:

At time 0, feed the first pig bucket 1, and feed the second pig bucket 2.

At time 15, there are 2 possible outcomes:

  • If either pig dies, then the poisonous bucket is the one it was fed.
  • If neither pig dies, then feed the first pig bucket 3, and feed the second pig bucket 4.

At time 30, one of the two pigs must die, and the poisonous bucket is the one it was fed.

Constraints:

  • 1 <= buckets <= 1000
  • 1 <= minutesToDie <= minutesToTest <= 100

题目大意

buckets 桶液体,其中 正好有一桶 含有毒药,其余装的都是水。它们从外观看起来都一样。为了弄清楚哪只水桶含有毒药,你可以喂一些猪喝,通过观察猪是否会死进行判断。不幸的是,你只有 minutesToTest 分钟时间来确定哪桶液体是有毒的。

喂猪的规则如下:

  1. 选择若干活猪进行喂养
  2. 可以允许小猪同时饮用任意数量的桶中的水,并且该过程不需要时间。
  3. 小猪喝完水后,必须有 minutesToDie 分钟的冷却时间。在这段时间里,你只能观察,而不允许继续喂猪。
  4. 过了 minutesToDie 分钟后,所有喝到毒药的猪都会死去,其他所有猪都会活下来。
  5. 重复这一过程,直到时间用完。

给你桶的数目 bucketsminutesToDieminutesToTest ,返回 在规定时间内判断哪个桶有毒所需的最小 猪数

示例 1:

输入: buckets = 1000, minutesToDie = 15, minutesToTest = 60

输出: 5

示例 2:

输入: buckets = 4, minutesToDie = 15, minutesToTest = 15

输出: 2

示例 3:

输入: buckets = 4, minutesToDie = 15, minutesToTest = 30

输出: 2

提示:

  • 1 <= buckets <= 1000
  • 1 <= minutesToDie <= minutesToTest <= 100

解题思路

假设我们用 2 头猪、毒药会在 15 分钟内致死、且有 60 分钟的测试时间,可以通过以下方法在最多 25 桶中找到有毒的一桶。

将桶排列成一个 5×5 的正方形:

 1   2   3   4   5
 6   7   8   9  10
11  12  13  14  15
16  17  18  19  20
21  22  23  24  25

因为有 60 分钟的时间,而测试一次需要 15 分钟,所以我们最多可以运行 4 次测试。

现在,用一头猪来确定(让它依次喝第 1、2、3、4、5 号桶的水,等 15 分钟;然后喝第 6、7、8、9、10 号桶的水,再等 15 分钟;以此类推)。用另一头猪来确定(让它依次喝第 1、6、11、16、21 号桶的水,等 15 分钟;然后喝第 2、7、12、17、22 号桶的水,以此类推)。

如果行的那头猪在第三轮测试中死亡,说明毒药在第三行。如果测试列的那头猪没有死亡,说明毒药在第五列(这也是为什么尽管我们只能运行 4 轮测试,却可以覆盖 5 行或 5 列)。

以此类推,对于 3 头猪,我们可以用一个 5×5×5 的立方体代替 5×5 的平面,依然用每头猪分别确定一个维度的坐标:一头猪喝从上到下的每层,另一头猪喝从左到右的每排,第三头猪喝从前到后的每列。通过这种方式,3 头猪可以判断最多 125 个桶。

通过这种方法,我们可以得出公式,n 只小猪可以最多判断 (Math.floor(minutesToTest / minutesToDie) + 1) ^ n 个桶。

因此,只需要找到满足条件的最小数量的猪即可。

复杂度分析

  • 时间复杂度O(pigs),循环次数取决于 pigs 的值。
  • 空间复杂度O(1),只使用了常数空间来存储变量。

代码

/**
 * @param {number} buckets
 * @param {number} minutesToDie
 * @param {number} minutesToTest
 * @return {number}
 */
var poorPigs = function (buckets, minutesToDie, minutesToTest) {
	let pigs = 0;
	while (
		Math.pow(Math.floor(minutesToTest / minutesToDie) + 1, pigs) < buckets
	) {
		pigs++;
	}
	return pigs;
};