leetcode--458. 可怜的小猪

题目描述:

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

喂猪的规则如下:

选择若干活猪进行喂养
可以允许小猪同时饮用任意数量的桶中的水,并且该过程不需要时间。
小猪喝完水后,必须有 minutesToDie 分钟的冷却时间。在这段时间里,你只能观察,而不允许继续喂猪。
过了 minutesToDie 分钟后,所有喝到毒药的猪都会死去,其他所有猪都会活下来。
重复这一过程,直到时间用完。
给你桶的数目 buckets ,minutesToDie 和 minutesToTest ,返回 在规定时间内判断哪个桶有毒所需的 最小 猪数 

解题方案1:
思路:
标签:数学

这道题初看的时候,很多人会纠结:到底需要多少只小猪,而每只小猪又应该具体如何喝水才能判断出哪只水桶有***?

这道题最开始不要去关注细节,去想到底应该怎么喂水。而是应该先思考在考察哪方面的问题,数组、链表、二叉树还是数学?那么仔细思考就能得出结论,本质上在考察数学中的 进制 问题。

举例说明:

假设:总时间 minutesToTest = 60,死亡时间 minutesToDie = 15,pow(x, y) 表示 x 的 y 次方,ceil(x)表示 x 向上取整
当前有 11 只小猪,最多可以喝 times = minutesToTest / minutesToDie = 4 次水
最多可以喝 44 次水,能够携带 base = times + 1 = 5 个的信息量,也就是(便于理解从 00 开始):
(1) 喝 00 号死去,00 号桶水有毒
(2) 喝 11 号死去,11 号桶水有毒
(3) 喝 22 号死去,22 号桶水有毒
(4) 喝 33 号死去,33 号桶水有毒
(5) 喝了上述所有水依然活蹦乱跳,44 号桶水有毒
结论是 11 只小猪最多能够验证 55 桶水中哪只水桶含有***,当 buckets ≤ 5 时,answer = 1
那么 22 只小猪可以验证的范围最多到多少呢?我们把每只小猪携带的信息量看成是 base进制数,22 只小猪的信息量就是 pow(base, 2) = pow(5, 2) = 25,所以当 5 ≤ buckets ≤ 25时,anwser = 2
那么可以得到公式关系:pow(base, ans) ≥ buckets,取对数后即为:ans ≥ log(buckets) / log(base),因为 ans 为整数,所以 ans = ceil(log(buckets) / log(base))


链接:https://leetcode-cn.com/problems/poor-pigs/solution/hua-jie-suan-fa-458-ke-lian-de-xiao-zhu-by-guanpen/
 

class Solution {
public:
    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        //1.假设含有***的水是随机事件 X
        //2.随机小猪死亡的时间段是随机时间Y
        float infoX = log(buckets);// 寻找毒水总的信息量
        int time = minutesToTest / minutesToDie +1;//在规定时间内猪的状态数(假设minutesToDie=15,minutesToTest=60,猪可以喝四次水,可以在四个时间段死去,以及不死,总共5种状态)
        float infoY = log(time); //一只猪提供的信息量

        int ans = ceil(infoX / infoY);//
        return ans;
    }
};

c++代码2:

用猪猪的生死状态:

  1. 一只猪在一次观察中,他的状态只有两种,活着或者死了。此时可以判断两桶水中哪一桶有毒。
  2. n只猪在一次观察中,他们的状态有2^n种。此时可以判断2^n桶中哪一桶有毒。具体方式为:将各个桶用2进制编码,第i只猪喝去喝所有[二进制编码中第i位为1的]桶,如果第1、3、4猪死了,说明二进制为0000001101的水桶有毒。
  3. 一只猪在k次观察中,他的状态有k+1种:第一次就死了、第二次就死了...第k次才死、最后还活着。此时可以判断k+1桶水中哪个有毒。具体地,用k+1进制将水桶编码,第一次喝第0桶,第k次喝第k-1桶,如果最后没死就是第k桶有毒。
  4. n只猪在k次观察中,他们的状态共有(k+1)^n种,则最多可以判断这么多桶水中哪个有毒。

class Solution {
public:
    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        
        if (buckets == 1) return 0;

        int runs = minutesToTest / minutesToDie;   // 多少次观察
        int status = runs + 1;                   // 一只猪有多少种状态
        int pigs = 1;
        int covered = status;                  // 可以判断多少桶水

        while (covered < buckets) {      
            // 如果猪不够用,则增加一只猪,同时能够判断的水桶变成加猪之前的status倍
            covered *= status;
            pigs++;
        }

        return pigs;
    }
};

代码3:本质其实就是一个数字进制表示的问题.

先来考虑一种最简单的情况,buckets = 1000, minutesToDie = 15, minutesToTest = 15,此时每只小猪都只能喝1次液体(再喝时间就不够了),每个小猪喝完若干瓶液体后只能出现两种状态,要么死亡,要么存活.

我们给这 1000 瓶液体分别标上一个唯一编号 0-999,由于 2^10 > 1000 >2^9
 ,所以每瓶液体都对应着唯一的一个长度为10的二进制串. 我们只需要10只小猪,让每个小猪负责一个二进制位即可. 例如第一只小猪负责二进制串的最低位,那么它就需要喝掉所有二进制最低位为1的液体,如果这只小猪最后死亡,说明有毒液体的编号二进制最低位为1;否则小猪存活,有毒液体的编号二进制最低位为0. 这样一来,一只小猪就可以确定一个二进制位的取值,使用10只小猪就能完全确定有毒液体的编号.

来考虑更一般的情况,buckets = 1000, minutesToDie = 15, minutesToTest = 60,此时每只小猪可以喝4次液体,在时间限制范围内,小猪可能出现的状态共有5种,分别为:喝完第1次后死亡、喝完第2次后死亡、喝完第3次后死亡、喝完第4次后死亡、喝完4次后依然存活. 现在每只小猪可以表示5种状态了,而不是之前的2种,那么我们就可以将瓶子的编号转换成五进制数考虑.

我们依然给这 1000 瓶液体分别标上一个唯一编号 0-999,由于 5^5>1000>5^4 

 ,所以每瓶液体都对应着唯一的一个长度为5的五进制串. 我们只需要5只小猪,让每个小猪负责一个五进制位即可. 例如第一只小猪负责五进制串的最低位,那么它第一次先喝掉五进制最低位为1的液体,第二次喝掉五进制最低位为2的液体,第三次喝掉五进制最低位为3的液体,第四次喝掉五进制最低位为4的液体. 在这一过程中,如果这只小猪某次喝完后死亡,就可以立马确定有毒液体五进制的最低位取值,如果喝完四次后仍存活,说明有毒液体五进制的最低位为0. 这样一来,一只小猪就可以确定一个五进制位的取值,使用5只小猪就能完全确定有毒液体的编号.

将问题的解抽象成更一般的数学公式如下:

                                         base =( minutesToTest/minutesToDie )+1

                                           base^ans >=buckets

base 表示对应的是几进制数,将第二个式子左右两端同时取对数,即可得到答案:

class Solution {
public:
    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        int base=minutesToTest/minutesToDie+1;
        return ceil(log(buckets)/log(base));
    }
};


链接:https://leetcode-cn.com/problems/poor-pigs/solution/leetcode-458-njin-zhi-si-xiang-by-xiaok0-819a/

python代码:

class Solution:
    def poorPigs(self, buckets: int, minutesToDie: int, minutesToTest: int) -> int:
        return ceil(log(buckets, minutesToTest//minutesToDie + 1))

解决方法2:动态规划
参考官网链接:


链接:https://leetcode-cn.com/problems/poor-pigs/solution/ke-lian-de-xiao-zhu-by-leetcode-solution-z0h7/

 

该题核心代码:

return ceil(log(buckets)/log(minutesToTest/minutesToDie+1));
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自动驾驶--小学生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值