数学专题2 - leetcode458. Poor Pigs/319. Bulb Switcher -Medium

458. Poor Pigs

题目描述

有1000个水桶,有且仅有一个中有毒,其余都装满水。它们看起来一样。如果一头猪喝了有毒的水将在15min死亡。
问在一小时内找出毒水,需要的最少猪的数量。

【推广】有n个水桶,猪喝毒水后将在m分钟内死亡。问在p分钟内找到毒水桶所需的最少猪的数量?

例子

思想
(以例子为例)
1) 一只猪在一小时内最多能验多少桶?
0min喝1号桶,15min后没挂再喝2号桶,60min内可以喝 60/15 = 4 次。如果有5桶水,那个只要喝前4桶就只能第5桶是否有毒。
因此一只猪在一小时可以验5桶水。
2)一只猪在一小时内最多能验多少桶?
既然一只猪能验5桶,那么用二维思路,2只猪应该可以验5*5桶:

猪A负责行,猪B负责列,每15分钟试喝一行/一列的所有5桶水,通过2只猪上天的时间能推断出毒水在几行几列。

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
3)推到N只猪,则5^N >= 1000,最小的N即为所求。

解法

class Solution(object):
    def poorPigs(self, buckets, minutesToDie, minutesToTest):
        """
        :type buckets: int
        :type minutesToDie: int
        :type minutesToTest: int
        :rtype: int
        """
        import math
        
        times = minutesToTest//minutesToDie + 1
        return int(math.ceil(math.log(buckets, times)))

(不调包)

class Solution(object):
    def poorPigs(self, buckets, minutesToDie, minutesToTest):
        """
        :type buckets: int
        :type minutesToDie: int
        :type minutesToTest: int
        :rtype: int
        """        
        nbatch  = minutesToTest//minutesToDie + 1
        pigs = 0
        while nbatch ** pigs < buckets:
            pigs += 1
        return pigs

319. Bulb Switcher

题目描述

n个灯泡初始化时是关着的。
首先,你点亮所有的灯泡;然后,关掉每第二个灯泡(关掉2,4…);第三轮,每第三个灯泡进行切换(如果它是关闭的则开启它,如果它是开启的则关闭它);第i轮,每第i个灯泡进行切换;第n轮,仅切换最后一个灯泡。
问在第n回后还有多少个灯泡是亮着的?

例子

Input: 3
Output: 1
Explanation:
At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off].

So you should return 1, because there is only one bulb is on.

思想
题意比较难懂。
第二轮,把每第二个灯泡关掉(关掉2,4…);
第三轮,每第三个灯泡进行切换(如果它是关闭的则开启它,如果它是开启的则关闭它,切换3,6…);
第i轮,每第i个灯泡进行切换;第n回,仅切换最后一个灯泡。

暴力解法 - TLE

class Solution(object):
    def bulbSwitch(self, n):
        """
        :type n: int
        :rtype: int
        """
        bulbs = [0] * n
        for i in range(1, n+1):
            if i == 1:
                bulbs = [1] * n
            elif i == n:
                bulbs[-1] = bulbs[-1] ^ 1
            else:
                j = i
                while j <= n:
                    bulbs[j-1] = bulbs[j-1] ^ 1
                    j += i

        return sum(bulbs)

观察规律
n = 5时,最后一行 - [1, 0, 0, 1, 0]

[1, 1, 1, 1, 1]
[1, 0, 1, 0, 1]
[1, 0, 0, 0, 1]
[1, 0, 0, 1, 1]
[1, 0, 0, 1, 0]

n = 10时,最后一行 - [1, 0, 0, 1, 0, 0, 0, 0, 1, 0]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 0, 0, 1, 0, 0, 0, 0, 1, 1]
[1, 0, 0, 1, 0, 0, 0, 0, 1, 0]

n = 15时,最后一行 - [1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]


[1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1]
[1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

n = 20时,最后一行 - [1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
n = 30时,最后一行 - [1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]

即1+2+1+4+1+6+1+8+1+…,其中1+1+1+1+…的和即为所求。

(解法1 - 优化)
设置标志位attach表明当前应该on了。

class Solution(object):
    def bulbSwitch(self, n):
        """
        :type n: int
        :rtype: int
        """
        bulbs = on = off = 0
        attach = True    # on
        while bulbs < n:
            if attach:
                attach = False
                bulbs += 1
                on += 1
            else:
                attach = True
                off += 2
                bulbs += off 
        return on

(解法2 - 数论)
时间复杂度 - O(1)
每个灯泡开关被按的次数等于它的编号的约数个数。
最终灯泡是亮的,说明编号有奇数个约数

下面我们证明:一个数有奇数个约数,等价于它是平方数
证明:
1)对于每个平方数,除了平方根之外,其余所有约数都是成对出现,所以平方数有奇数个约数。

2)由算数基本定理,一个整数 n 可以唯一表示成: n = p 1 k 1 × p 2 k 2 × . . . × p m k m n = {p_1}^{{k_1}} \times {p_2}^{{k_2}} \times ... \times {p_m}^{{k_m}} n=p1k1×p2k2×...×pmkm其中 p 1 , p 2 . . . p m {p_1},{p_2}...{p_m} p1,p2...pm 均是质数, k 1 , k 2 . . . k m {k_1},{k_2}...{k_m} k1,k2...km 均是正整数。

则 n 的约数个数就是 ∏ i = 1 m ( k i + 1 ) \prod\limits_{i = 1}^m {\left( {{k_i} + 1} \right)} i=1m(ki+1)

如果 n有奇数个约数,说明 k 1 + 1 , k 2 + 1... , k m + 1 {k_1} + 1,{k_2} + 1...,{k_m} + 1 k1+1,k2+1...,km+1 都是奇数,从而 k 1 , k 2 , . . . k m {k_1},{k_2},...{k_m} k1,k2,...km 均是偶数。所以 n = ( p 1 k 1 / 2 × p 2 k 2 / 2 × . . . × p m k m / 2 ) 2 n = {\left( {{p_1}^{{k_1}/2} \times {p_2}^{{k_2}/2} \times ... \times {p_m}^{{k_m}/2}} \right)^2} n=(p1k1/2×p2k2/2×...×pmkm/2)2所以 n 是平方数。

共有 n 个灯泡,则从 1 到 n 中共有 ⌊√n⌋个平方数。

class Solution(object):
    def bulbSwitch(self, n):
        """
        :type n: int
        :rtype: int
        """
        return int(n**0.5)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值