这是记录CodeWars的第二篇文章
今天这题挺有意思的,借这题正好可以理解Python的灵活。
一.题目
Tribonacci Sequence
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 ;)
一些英语单字:
1.Fibonacci 和 Tribonacci
Fibonacci 即 斐波那契数列,即从第三项开始,每一项都由该项前两位加起来得到,例如
[1,2,3,5,8,13]
第三项1+2=3
第四项2+3=5
第五项3+5=8
而Tribonacci数列则是由前三项加起来得到的。(本题就是在介绍Tribonacci数列)
2.AKA
又叫做,亦称(Also Known As的缩写)
3.That is not the case
事实并非如此
4.tempted
原型是tempt v.吸引,诱惑。
you may be tempted to think that...
查字典是吸引和诱惑的意思,但觉得怎样都翻译的不是很通顺,后来想起来一个词——诱导。
你也许被(Fibonacci的例子)诱导,认为...blahblah
😜
上面这段英文翻译起来就是
好的,我们现在遇到了Fibonacci(斐波那契数列)的哥哥,Tribonacci。
也许从它的名字你就能想到,它和Fibonacci的计算机制很像,但是!它通过累加序列的最后三个数字(而不是两个)而去形成下一个数字。而且,更糟的部分是,我不想听母语不是意大利语的人发这个单词的音。
(😒这么傲娇的嘛)所以如果我们以序列[1,1,1]作为起始序列输入(这个序列又称signature),我们可以得到下面这个序列
[1, 1 ,1, 3, 5, 9, 17, 31, ...]
但是,如果我们以[0,0,1]作为signature呢?在Fibonacci序列中以[0,1]开头而不是[1,1]开头的话,仅仅只是整个序列右移了一位,你也许被诱导就觉得我们会得到同样的序列只是整个序列向右移了两位。图样图森破!我们会得到
[0, 0, 1, 1, 2, 4, 7, 13, 24, ...]
( 😶真的是跟[1,1,1]作为输入的完全不一样啊)好的,你也许已经猜到了我们要做什么,但需要申明的是:你需要创造一个fibonacci function,这个函数输入序列,返回前n个元素。
Signature总是包含3个数字;n一定是非数整数。如果n等于0,就返回一个空列表。
初始代码
def tribonacci(signature, n)
举个栗子
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])
二.思路和代码
思路:
刚弄懂题目大意的时候,首先想到啊。
传入参数:一个列表(signature),一个非负整数(n)。
返回:列表
n=0 不用操作返回空列表
n=1 不用操作返回列表第一个
n=2 不用操作返回列表前两个
n=3 不用操作返回列表前三个
n>3开始 进行加法操作 返回n个
开始觉得用一个新的列表记录数值,然后用if判断分别分成这五部分操作,
但是!
在写最后一个情况n>3的时候,计算新一项的时候发现如果用下面这个觉得好麻烦。
signature[-1]+signature[-2]+signature[-3]
我们有sum()这个内置函数啊
把一个数值列表用sum()我们可以直接得到列表和,但这里我们只需要后三项啊,
没错,就在这时想起了一个概念——分片(Slicing)。
像signature[-1]
这种称为索引,用-1找到对应位置的值
而像signature[2:5]
这种被称为分片,代表一个列表,该列表第一个元素是signature列表中索引2的元素,第二个元素是signature列表中索引3的元素,但不包括索引5的元素。
例如列表
L=[4,5,6,7,8,9,10,11,12]
L[2:5]代表了一个列表,即[6,7,8] 没有9是因为L[5]=9,但我们不包括索引5.
除此之外,还有L[2:5:-1],即[8,7,6],在原有基础上翻转。
L[2:5:2],即[6,8],找到索引2后+2,找索引4。
非常的灵活,不是吗。
那我们就不用新的列表来记录数值也不用if判断不同情况
最后返回直接使用这句
return signature[:n]
一句话解决了n=0到n=3的所有情况😭😭😭
代码:
def tribonacci(signature,n):
while len(signature) < n:
signature.append(sum(signature[-3:]))
return signature[:n]
代码解析:
当列表和n传进来时,
如果n是0~3 那么len(signature) < n则为False。不会进入while循环,直接返回分片后的列表
如果n>3,例如n=5,那么len(signature) < n (即3<5) 为真
用append方法添加新元素。新元素为sum(signature[-3:])即signature列表后三位求和,然后不断循环直到打破条件。
三.最优解代码
Best Practices
可以看到,排序第一名的想法和我们差不多。也是利用Python中分片的思想。
但是更多的人和我想的一样用while循环 len(signature) < n来做判断条件。我觉得我们第二组的可读性更好,你觉得哪个好呢?
四.总结
Python是非常灵活,列表的分片就是其中能体现灵活的机制。
你可以从一个列表中截一部分出来
L[2:5]
也可以间隔一个截取
L[2:5:2]
还可以截取后翻转过来
L[2:5:-1]
当然还有其他的玩法,等等你去发现啦,学Python吧少年。。 😀
网友评论