题目地址:
https://www.lintcode.com/problem/split-array-into-fibonacci-sequence/description
给定一个由数字构成的长 n n n的字符串 s s s,要求将其截取成若干部分,使得这些部分看成数字时就成为了斐波那契数列。返回这个数列。要求数列长度不小于 3 3 3,并且每个截取的部分除非自己是 0 0 0,否则不能含开头 0 0 0。并且,每个数小于等于 2 31 − 1 2^{31}-1 231−1。
容易看出,只需要前两个数定下来了,整个数列也就定下来了,所以我们只需要枚举前两个数是多少,然后向后推即可。推的同时注意开头零的问题。由于可能会截取出超过 2 31 − 1 2^{31}-1 231−1的数,我们用long来做。代码如下:
import java.util.ArrayList;
import java.util.List;
public class Solution {
/**
* @param S: a string S of digits
* @return: Return any Fibonacci-like sequence split from S
*/
public List<Integer> splitIntoFibonacci(String S) {
// write your code here
List<Integer> res = new ArrayList<>();
// i和j枚举的是前两个数的最后一位的位置
for (int i = 0; i + 1 < S.length(); i++) {
for (int j = i + 1; j < S.length(); j++) {
// start1是当前枚举的两个数的第一个数的开头位置,end1是其结尾位置,end2是枚举的两个数第二个数的结尾位置
int start1 = 0, end1 = i, end2 = j;
while (true) {
// 如果有开头0则直接退出循环,进行下一次枚举
if (end1 - start1 + 1 >= 2 && S.charAt(start1) == '0') {
break;
}
if (end2 - end1 >= 2 && S.charAt(end1 + 1) == '0') {
break;
}
// 解析出两个数
long a = Long.parseLong(S.substring(start1, end1 + 1)), b = Long.parseLong(S.substring(end1 + 1, end2 + 1));
// 如果大于了最大int,则也退出循环,进行下一次枚举
if (a > Integer.MAX_VALUE || b > Integer.MAX_VALUE) {
break;
}
// 算出第三个数c
long c = a + b;
String str = String.valueOf(c);
// 如果后面截不出c,退出循环,进行下一次枚举
if (S.indexOf(str, end2 + 1) != end2 + 1) {
break;
}
// 我们计划每次while循环都加入第二个数,只有进行第一次while的时候,我们需要把第一个数加进去
if (start1 == 0) {
res.add((int) a);
}
res.add((int) b);
// 把指针都重新调整
start1 = end1 + 1;
end1 = end2;
end2 += str.length();
// 如果第二个数已经到了最后一个字符,并且列表里的数已经不少于2个了,
// 那加上最后一个恰好不少于3个,就说明找到了,返回之
if (end2 == S.length() - 1 && res.size() >= 2) {
res.add((int) c);
return res;
}
}
// 退出了while循环,说明没找到答案,则清空列表
res.clear();
}
}
return res;
}
}
时间复杂度 O ( n 2 ) O(n^2) O(n2),空间 O ( n ) O(n) O(n)。