问题:给定一个数字字符串s,将它拆分成一个长度大于3的斐波那契式的列表。
也就是说,除第一个和第二个数字,列表中的每个数字都等于前两个数字的和。
例如:
s="1235813",输出:[1,2,3,5,8,13]
s = "1234",输出:[]
解题思路如下:
先假设第一个数字是s字符串中的第一个数字,如"12345168910"中的1。
然后再假设第二个数字是s字符串中的第二个数字,如"12345168910"中的2。
接下来检查这个假设是否成立。假设不成立,因为1+2=3,但2+3≠4。
所以退回到第二个数字,假设第二个数字是s字符串中的第二个数字和第三个数字,如"12345168910"中的23,然后再次检查这个假设是否成立。通过判断,这个假设仍然不成立。
可以发现第二个数字为2,23,234,2345,23451,234516,2345168,23451689,234516891,2345168910这些假设都不成立。
这时退回到第一个数字,使它变为字符串中的第一个和第二个数字,如"12345168910"中的12。而第二个数字则是s字符串的下一个的数字——3。
重复这个步骤直到找到成立的两个数字,或者将所有可能都尝试完得出没有解的结论。
假设第三个数字成立了,找到了一个数字是前两个数字的和。
接下来,要检查第四个数字是否成立。重复这个步骤,一旦数字不成立,就退回到第二个数字,改变它,然后再继续。
比如168=123+45。现在需要验证第四个数字。因为后三位数字不是291,所以退回到第二个数字,改变它。尝试完所有的第二个数字的可能并失败后,返回到第一个数字,改变它,然后再继续。
注意:本题有两处可以提升效率的部分。
(1)在判断两个数字的和是否在剩余的字符串中时,如果两个数字的和小于当前数字,就可以直接得到否定的结论。比如当s="42834",第一个数字是4,第二个数字是2时,因为4+2不但不等于8,还小于8,那就不需要再检查4+2是否等于83。
(2)像“01”“004”这样的数字不成立,可以直接跳过它们。
# 将s拆分成一个长度大于3的斐波那契式的列表
def splitIntoFibonacci(s):
# res是当前结果列表,index是当前数字的开始坐标
# 以res[-1], res[-2]为前两位数字,检查第三位数字是否成立
def helper(s, res, index):
if index == n and len(res) >= 3: # 如果所有数字都被遍历并且res有3个以上数字
return True
for i in range(index, n):
if s[index] == "0" and i > index: # 不成立的数字
break
num = int(s[index:i + 1]) # 动态变化的当前数字
# 第三个数字不成立
if len(res) >= 2 and num > res[-1] + res[-2]:
break
# 第三个数字暂时不存在或第三个数字成立
if len(res) <= 1 or num == res[-1] + res[-2]:
res.append(num)
if helper(s, res, i + 1): # 检查第四个数字
return True
res.pop()
return False
res = []
n = len(s)
helper(s, res, 0)
return res
输入:
输出:
输入:
输出: