一、题目描述
给定一个数字字符串 S,比如 S = “123456579”,我们可以将它分成斐波那契式的序列 [123, 456, 579]。
形式上,斐波那契式序列是一个非负整数列表 F,且满足:
- 0 <= F[i] <= 2^31 - 1,(也就是说,每个整数都符合 32 位有符号整数类型);
F.length >= 3; - 对于所有的0 <= i < F.length - 2,都有 F[i] + F[i+1] = F[i+2] 成立。
- 另外,请注意,将字符串拆分成小块时,每个块的数字一定不要以零开头,除非这个块是数字 0 本身。
返回从 S 拆分出来的任意一组斐波那契式的序列块,如果不能拆分则返回 []。
示例 1:
输入:"123456579"
输出:[123,456,579]
示例 2:
输入: "11235813"
输出: [1,1,2,3,5,8,13]
示例 3:
输入: "112358130"
输出: []
解释: 这项任务无法完成。
示例 4:
输入:"0123"
输出:[]
解释:每个块的数字不能以零开头,因此 "01","2","3" 不是有效答案。
示例 5:
输入: "1101111"
输出: [110, 1, 111]
解释: 输出 [11,0,11,11] 也同样被接受。
提示:
1 <= S.length <= 200
字符串 S 中只含有数字。
二、解题思路 & 代码
2.1 暴力法
想法
数组的前两个元素唯一决定了后面的数组元素。
算法
对于每种可能的前两个元素,假设没有前导零,遍历剩余的字符串。对于每个情况,我们希望得到小于等于 2^31 - 1 的数,且是前两个数字之和。
class Solution(object):
def splitIntoFibonacci(self, S):
for i in xrange(min(10, len(S))):
x = S[:i+1]
if x != '0' and x.startswith('0'): break
a = int(x)
for j in xrange(i+1, min(i+10, len(S))):
y = S[i+1: j+1]
if y != '0' and y.startswith('0'): break
b = int(y)
fib = [a, b]
k = j + 1
while k < len(S):
nxt = fib[-1] + fib[-2]
nxtS = str(nxt)
if nxt <= 2**31 - 1 and S[k:].startswith(nxtS):
k += len(nxtS)
fib.append(nxt)
else:
break
else:
if len(fib) >= 3:
return fib
return []
复杂度分析
- 时间复杂度: O ( N 2 ) O(N^2) O(N2),其中 N 是 S 的长度,按照要求结果的长度都是 O(1) 的。
- 空间复杂度:O(N)。
2.2 回溯 + 剪枝
主要是回溯过程中的剪枝优化,减去了值大于2 ** 31 - 1和不符合F[i] + F[i + 1] = F[i + 2]的部分。还有就是new_value以’0’开头并且长度大于1的部分,需要注意’0’是符合条件的数字。
class Solution:
def splitIntoFibonacci(self, S: str) -> List[int]:
n = len(S)
res = []
def backtrack(index, temp):
if index == n:
if self._is_fibonacci(temp):
res.append(temp)
return
for i in range(index, n):
new_value = S[index:i + 1]
if int(new_value) > 2 ** 31 - 1:
break
if not (new_value.startswith('0') and len(new_value) > 1):
if len(temp) >= 2 and int(new_value) == (temp[-1] + temp[-2]):
backtrack(i + 1, temp + [int(new_value)])
elif len(temp) < 2:
backtrack(i + 1, temp + [int(new_value)])
backtrack(0, [])
return res[0] if res else []
def _is_fibonacci(self, temp):
if len(temp) < 3:
return False
for i in range(2, len(temp)):
if temp[i] != (temp[i - 1] + temp[i - 2]):
return False
return True