题目:
给定一个数字字符串 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]
来源:
解题思路:回溯
定义一个变量n,记录字符串[start, i]的数值。第一次递归(start=0)中for循环情况如下:
- 递归终止条件:数字字符串处理完成
- 结果满足条件:数字字符串处理完成,并且结果至少3个数
- 剪枝条件:找到一个后,或数字超int最大值,或不满足斐波那契公式(也可以增加判断:当前2个数字之和小于当前数字n时,退出for循环,因为后面的数字n更大)
class Solution {
public:
vector<int> result;
vector<int> path;
bool finish;
vector<int> splitIntoFibonacci(string S) {
finish = false;
// 处理开头的0
int start = 0;
while (start < S.size() && S[start] == '0') {
path.push_back(0);
start++;
}
back(S, start);
return result;
}
void back(const string& s, int start) {
if (path.size() > 2 && start == s.size()) {
finish = true;
result = path;
return;
}
long n = 0;
for (int i = start; i < s.size(); i++) {
if (finish) break;
n = n * 10 + s[i] - '0'; // n:[start,i]内的数字
if (n > 0x7fffffff) break;
int sz = path.size();
if (sz < 2 || (long)path[sz-1] + (long)path[sz-2] == n) {
path.push_back(n);
back(s, i + 1);
path.pop_back();
}
}
}
};
每个块的数字一定不要以零开头,这种情况没有处理,居然也能通过。例如:11203应当返回[],而本代码却返回了[1,1,2,3]。
补救的方法是在int sz = path.size();后面增加一行:if (sz > 1 && s[start] == '0') break;表示,当序列至少2个数的前提下,start所指向的数字不能是0,若是0则跳过。