豬生豬,兔生兔

2022-07-20 08:36:11 字數 4246 閱讀 7759

tags:演算法

其實這個出自面試題,當時沒做出來,哭喪臉...

我們先來看個比較常見的問題:

有一對兔子,從出生後第3個月起每個月每只兔子都生一對兔子,小兔子長到第三個月後每個月每只又生一對兔子,假如兔子都不死,問第n個月的兔子總數為多少?

由題目意思可看出第n個月的總數取決於第n-1個月的兔子的總數加上第n-2個月出生的兔子生出來新兔子的數目,簡單粗暴點用公式來表示:

f(1) = 2                    // 第乙個月有2只兔子

f(2) = 2 // 第二個月有2之兔子

f(3) = f(2) + f(1) * 2 // 現在第乙個月的兔子可以生小兔子了,第三個月的總數為第二個月的兔子總數加上第乙個月兔子生下來的兔子

f(4) = f(3) + f(2) * 2 //現在第二個月的兔子可以生小兔子了,第四個月的總數為第三個月的總數加上第二個月

......

f(n) = f(n-1) + f(n-2) * 2 // 現在第n-2個月的兔子可以生小兔子了,不管是在第n-2個月之前就出生的還是在第n-2個月才出生的,在相對的第三個月後即第n個月都會生小兔子,然而在第n-1個月出生的兔子不能生小兔子,這部分作為基數直接計算進第n個月的總數中,所以第n個月的總數由兩部分組成,一是上個月的兔子總數,二是這個月新出生的兔子。

思路有了,那我們就直接來**吧~

def getsum(num):

if num == 1 or num == 2:

return 2

return getsum(num-1) + getsum(num-2) * 2

這種遞迴的**還是有點慢啊,那可不可以給力點,讓**更快一點呢~那我們就不用遞迴來試試迭代呢~

def getsum(num):

a, b = 2, 2 # 第乙個月,第二個月

if sum == 1 or sum == 2:

return 2

for i in range(3, sum+1):

a, b = b, a*2+b # a做為第n-2個月,b做為第n-1個月,計算後a與b的指向位置均向後移動了一位,此時a為n-1,b為n

return b

ok,這種不會死的兔子真是厲害啊,在**可以買,我也要~

哎,買不到不死的兔子哎,兔子都會死,就像這樣:

有4只兔子,從出生後第3個月(經過兩個月)起每個月每只兔子都生一對兔子,小兔子長到第三個月後每個月每只又生一對兔子,假如兔子只能活四個月也就是第乙個月出生的兔子第五個月就死掉了,問第n個月的兔子總數為多少?

這個好眼熟,和上面的差不多耶~哎,不對啊,這個兔子有壽命的啊,那是不是有個公式像上面的那種遞推公式呢,來推一下吧:

f(1) = 4                             // 第乙個月4只

f(2) = 4 // 第二個月4只

f(3) = 4 + 4*2 = f(2) + f(1) * 2 // 第乙個月的兔子生小兔子啦

f(4) = f(3) + f(2) * 2 // 第二個月的兔子也生啦

f(5) = f(4) - f(1) + (f(3) - f(2)) * 2 // 第乙個月的兔子死掉了,第三個月的兔子出生了

f(6) = 第五個月的總數加上第三個月兔子生的小兔子再加上第四個月的兔子生的小兔子...這個公式有點複雜啊,下面的會不會更可怕,害怕ing

好了好了,我放棄了,不用這個方法了,快快快想想其他的:

按著剛剛的思路,我們可不可以計算每個月的新出生的兔子數量,然後把還活著者的相加起來呢~但這樣的話不就和上面的一樣了嗎,重點都是要計算新兔子的數量,那可不可以給力點~我們幹嘛要自己維護這種計算過程的狀態呢,為啥不讓計算機自己維護呢,ok,讓計算機自己維護要怎麼讓他自己能維護呢~這個時候面試官提點了一下:物件導向

對哇,來來來,讓我們拋棄過程化的思路:

當有新兔子出生的時候就是new物件的時候,有多少個出生就new多少個,每個物件擁有自己的出生月份,這樣就可以判斷是否可以生兔子,是否還活著了

每次對月份進行遞迴迭代的時候就是判斷物件的屬性,不需要手動維護

還是先用遞迴來一遍:

# -*- coding:utf-8 -*-  

class rabbit:

def __init__(self, year):

self.year = year

def isdead(self, year):

"""死了為true,沒死為false"""

return self.year + 3 < year

def isbirth(self, year):

return self.year + 1 < year

def __str__(self):

return '(pig: year-%s)' % str(self.year)

__repr__ = __str__

def getsum(num):

if num == 1 or num == 2:

return [rabbit(1)] * 4

piglist = getsum(num-1)

templist =

# 過濾掉死掉的兔子,新增新出生的兔子

for pig in piglist:

# 還活著的加入當月列表中

if not pig.isdead(num):

# 新出生的加入當月列表中

if not pig.isdead(num) and pig.isbirth(num):

templist.extend([rabbit(num)] * 2)

# 返回當月的兔子情況

return templist

if __name__ == '__main__':

pigcharm = getsum(5)

print pigcharm

print len(pigcharm)

ok,下面就是迭代的版本了:

# -*- coding:utf-8 -*-  

class pig:

def __init__(self, year):

self.year = year

def isdead(self, year):

"""死了為true,沒死為false"""

return self.year + 3 < year

def isbirth(self, year):

return self.year + 1 < year

def __str__(self):

return '(pig: year-%s)' % str(self.year)

__repr__ = __str__

def getsum(num):

pigcharm = [pig(1)] * 4

if num == 1:

return pigcharm

# 利用for迴圈進行迭代

for year in range(2, num+1):

templist =

for pig in pigcharm:

# 過濾掉死掉的兔子

if not pig.isdead(year):

# 加入新出生的兔子

if not pig.isdead(year) and pig.isbirth(year):

templist.extend([pig(year)] * 2)

pigcharm = templist

return pigcharm

if __name__ == '__main__':

pigcharm = getsum(5)

print pigcharm

print len(pigcharm)

看來,以後解決問題的時候還需要多想想,換個思路會更好啊~

(剛面試完,等回覆好心急...)

你這裡滿篇的兔子嘛,豬呢?對哇,豬呢?!豬可能是被兔子吃掉了吧~(原面試題就是豬,到了我這豬就被兔子吃了,慘啊)

兔兔 的 題解 Teamwork

區間最值 題目背景 在 f ar me rfarmer farmer j oh njohn john 最喜歡的節日裡,他想要給他的朋友們贈送一些禮物。由於他並不擅長包裝禮物,他想要獲得他的奶牛們的幫助。你可能能夠想到,奶牛們也不是很擅長包裝禮物,而 far me rfarmer farmer j o...

兔兔與老闆的對話

第一家公司 老闆 兔兔,今天工作忙不忙?兔兔 不忙。下班時老闆對兔兔說 你明天不用來了。兔兔 為什麼?老闆 因為你不能多為公司幹事,所以才會不忙,公司要你何用?第二家公司 老闆 兔兔,今天工作忙不忙?兔兔 很忙。下班時老闆對兔兔說 你明天不用來了。兔兔 為什麼?老闆 因為你做事沒有條理性,所以才會整...

兔兔 的 題解 噴水裝置

題目描述 在乙個長 l ll 公尺,寬 w ww 公尺的草坪裡裝有 n nn 個澆灌噴頭。每個噴頭都裝在草坪中心線上 離兩邊各 w 2 frac w 2 2w 公尺 我們知道每個噴頭的位置 c cc 離草坪中心線左端的距離 以及它能覆蓋到的澆灌範圍 rrr。請問 最少需要開啟多少個噴頭才能澆灌整塊草...