leetcode458. Poor Pigs/319. Bulb Switcher -Medium
題目描述
有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
題目描述
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 的約數個數就是 。
如果 n有奇數個約數,說明 都是奇數,從而 均是偶數。所以所以 n 是平方數。
共有 n 個燈泡,則從 1 到 n 中共有 ⌊√n⌋個平方數。
class Solution(object):
def bulbSwitch(self, n):
"""
:type n: int
:rtype: int
"""
return int(n**0.5)