這是記錄CodeWars的第二篇文章
今天這題挺有意思的,借這題正好可以理解Python的靈活剥悟。
一.題目
Well met with Fibonacci bigger brother, AKA Tribonacci.
As the name may already reveal, it works basically like a Fibonacci, but summing the last 3 (instead of 2) numbers of the sequence to generate the next. And, worse part of it, regrettably I won't get to hear non-native Italian speakers trying to pronounce it :(
So, if we are to start our Tribonacci sequence with [1, 1, 1] as a starting input (AKA signature), we have this sequence:
[1, 1 ,1, 3, 5, 9, 17, 31, ...]
But what if we started with [0, 0, 1] as a signature? As starting with [0, 1] instead of [1, 1] basically shifts the common Fibonacci sequence by once place, you may be tempted to think that we would get the same sequence shifted by 2 places, but that is not the case and we would get:
[0, 0, 1, 1, 2, 4, 7, 13, 24, ...]Well, you may have guessed it by now, but to be clear: you need to create a fibonacci function that given a signature array/list, returns the first n elements - signature included of the so seeded sequence.
Signature will always contain 3 numbers; n will always be a non-negative number; if n == 0, then return an empty array and be ready for anything else which is not clearly specified ;)
一些英語(yǔ)單字:
1.Fibonacci 和 Tribonacci
Fibonacci 即 斐波那契數(shù)列,即從第三項(xiàng)開(kāi)始,每一項(xiàng)都由該項(xiàng)前兩位加起來(lái)得到,例如
[1,2,3,5,8,13]
第三項(xiàng)1+2=3
第四項(xiàng)2+3=5
第五項(xiàng)3+5=8
而Tribonacci數(shù)列則是由前三項(xiàng)加起來(lái)得到的夺溢。(本題就是在介紹Tribonacci數(shù)列)
2.AKA
又叫做,亦稱(Also Known As的縮寫)
3.That is not the case
事實(shí)并非如此
4.tempted
原型是tempt v.吸引烛谊,誘惑风响。
you may be tempted to think that...
查字典是吸引和誘惑的意思,但覺(jué)得怎樣都翻譯的不是很通順丹禀,后來(lái)想起來(lái)一個(gè)詞——誘導(dǎo)状勤。
你也許被(Fibonacci的例子)誘導(dǎo),認(rèn)為...blahblah
??
上面這段英文翻譯起來(lái)就是
好的双泪,我們現(xiàn)在遇到了Fibonacci(斐波那契數(shù)列)的哥哥持搜,Tribonacci。
也許從它的名字你就能想到焙矛,它和Fibonacci的計(jì)算機(jī)制很像葫盼,但是!它通過(guò)累加序列的最后三個(gè)數(shù)字(而不是兩個(gè))而去形成下一個(gè)數(shù)字村斟。而且贫导,更糟的部分是,我不想聽(tīng)母語(yǔ)不是意大利語(yǔ)的人發(fā)這個(gè)單詞的音蟆盹。
(??這么傲嬌的嘛)所以如果我們以序列[1,1,1]作為起始序列輸入(這個(gè)序列又稱signature)孩灯,我們可以得到下面這個(gè)序列
[1, 1 ,1, 3, 5, 9, 17, 31, ...]
但是,如果我們以[0,0,1]作為signature呢逾滥?在Fibonacci序列中以[0,1]開(kāi)頭而不是[1峰档,1]開(kāi)頭的話,僅僅只是整個(gè)序列右移了一位寨昙,你也許被誘導(dǎo)就覺(jué)得我們會(huì)得到同樣的序列只是整個(gè)序列向右移了兩位面哥。圖樣圖森破!我們會(huì)得到
[0, 0, 1, 1, 2, 4, 7, 13, 24, ...]
( ??真的是跟[1,1,1]作為輸入的完全不一樣耙愦)好的,你也許已經(jīng)猜到了我們要做什么归榕,但需要申明的是:你需要?jiǎng)?chuàng)造一個(gè)fibonacci function尸红,這個(gè)函數(shù)輸入序列,返回前n個(gè)元素。
Signature總是包含3個(gè)數(shù)字外里;n一定是非數(shù)整數(shù)怎爵。如果n等于0,就返回一個(gè)空列表盅蝗。
初始代碼
舉個(gè)栗子
Test.describe("Basic tests")
Test.assert_equals(tribonacci([1, 1, 1], 10), [1, 1, 1, 3, 5, 9, 17, 31, 57, 105])
Test.assert_equals(tribonacci([0, 0, 1], 10), [0, 0, 1, 1, 2, 4, 7, 13, 24, 44])
Test.assert_equals(tribonacci([0, 1, 1], 10), [0, 1, 1, 2, 4, 7, 13, 24, 44, 81])
Test.assert_equals(tribonacci([1, 0, 0], 10), [1, 0, 0, 1, 1, 2, 4, 7, 13, 24])
Test.assert_equals(tribonacci([0, 0, 0], 10), [0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
Test.assert_equals(tribonacci([1, 2, 3], 10), [1, 2, 3, 6, 11, 20, 37, 68, 125, 230])
Test.assert_equals(tribonacci([3, 2, 1], 10), [3, 2, 1, 6, 9, 16, 31, 56, 103, 190])
Test.assert_equals(tribonacci([1, 1, 1], 1), [1])
Test.assert_equals(tribonacci([300, 200, 100], 0), [])
Test.assert_equals(tribonacci([0.5, 0.5, 0.5], 30), [0.5, 0.5, 0.5, 1.5, 2.5, 4.5, 8.5, 15.5, 28.5, 52.5, 96.5, 177.5, 326.5, 600.5, 1104.5, 2031.5, 3736.5, 6872.5, 12640.5, 23249.5, 42762.5, 78652.5, 144664.5, 266079.5, 489396.5, 900140.5, 1655616.5, 3045153.5, 5600910.5, 10301680.5])
二.思路和代碼
思路:
剛弄懂題目大意的時(shí)候鳖链,首先想到啊。
傳入?yún)?shù):一個(gè)列表(signature)墩莫,一個(gè)非負(fù)整數(shù)(n)芙委。
返回:列表
n=0 不用操作返回空列表
n=1 不用操作返回列表第一個(gè)
n=2 不用操作返回列表前兩個(gè)
n=3 不用操作返回列表前三個(gè)
n>3開(kāi)始 進(jìn)行加法操作 返回n個(gè)
開(kāi)始覺(jué)得用一個(gè)新的列表記錄數(shù)值,然后用if判斷分別分成這五部分操作狂秦,
但是灌侣!
在寫最后一個(gè)情況n>3的時(shí)候,計(jì)算新一項(xiàng)的時(shí)候發(fā)現(xiàn)如果用下面這個(gè)覺(jué)得好麻煩裂问。
signature[-1]+signature[-2]+signature[-3]
我們有sum()這個(gè)內(nèi)置函數(shù)啊
把一個(gè)數(shù)值列表用sum()我們可以直接得到列表和侧啼,但這里我們只需要后三項(xiàng)啊,
沒(méi)錯(cuò)堪簿,就在這時(shí)想起了一個(gè)概念——分片(Slicing)痊乾。
像signature[-1]
這種稱為索引,用-1找到對(duì)應(yīng)位置的值
而像signature[2:5]
這種被稱為分片椭更,代表一個(gè)列表哪审,該列表第一個(gè)元素是signature列表中索引2的元素,第二個(gè)元素是signature列表中索引3的元素甜孤,但不包括索引5的元素协饲。
例如列表
L=[4,5,6,7,8,9,10,11,12]
L[2:5]代表了一個(gè)列表,即[6,7,8] 沒(méi)有9是因?yàn)長(zhǎng)[5]=9,但我們不包括索引5.
除此之外缴川,還有L[2:5:-1]茉稠,即[8,7,6],在原有基礎(chǔ)上翻轉(zhuǎn)。
L[2:5:2]把夸,即[6,8],找到索引2后+2而线,找索引4。
非常的靈活恋日,不是嗎膀篮。
那我們就不用新的列表來(lái)記錄數(shù)值也不用if判斷不同情況
最后返回直接使用這句
return signature[:n]
一句話解決了n=0到n=3的所有情況??????
代碼:
def tribonacci(signature,n):
while len(signature) < n:
signature.append(sum(signature[-3:]))
return signature[:n]
代碼解析:
當(dāng)列表和n傳進(jìn)來(lái)時(shí),
如果n是0~3 那么len(signature) < n則為False岂膳。不會(huì)進(jìn)入while循環(huán)誓竿,直接返回分片后的列表
如果n>3,例如n=5谈截,那么len(signature) < n (即3<5) 為真
用append方法添加新元素筷屡。新元素為sum(signature[-3:])即signature列表后三位求和涧偷,然后不斷循環(huán)直到打破條件。
三.最優(yōu)解代碼
可以看到毙死,排序第一名的想法和我們差不多燎潮。也是利用Python中分片的思想。
但是更多的人和我想的一樣用while循環(huán) len(signature) < n來(lái)做判斷條件扼倘。我覺(jué)得我們第二組的可讀性更好确封,你覺(jué)得哪個(gè)好呢?
四.總結(jié)
Python是非常靈活再菊,列表的分片就是其中能體現(xiàn)靈活的機(jī)制爪喘。
你可以從一個(gè)列表中截一部分出來(lái)
L[2:5]
也可以間隔一個(gè)截取
L[2:5:2]
還可以截取后翻轉(zhuǎn)過(guò)來(lái)
L[2:5:-1]
當(dāng)然還有其他的玩法,等等你去發(fā)現(xiàn)啦袄简,學(xué)Python吧少年腥放。。 ??