题意: 要将整个序列, 切割成多个子序列, 让子序列成斐波那契.
for
是找不到边界的. 对于这种不定数量的枚举, 只能回溯. 除了自身回溯的边界, 题目给出了一些其他限制条件, 方便剪枝.
0
开头 pub fn split_into_fibonacci(num: String) -> Vec<i32> {
const MAX : i64 = 1 << 31;
fn backtrack(
ans: &mut Vec<i64>, num: &[u8],
length: usize, idx: usize,
sum: i64, prev: i64 // 前两个数的加和, 前一个数
) -> bool {
if idx == length {
// 返回是否已经找到结果, 如果是, 可以提前终止, 剪枝4
return ans.len() >= 3;
}
// 从 idx 开始, 枚举所有可能的数
let mut curr = 0;
for i in idx..length {
// 自身为0是可以的, 但是下一个数不能以0开头
// 因此跳过后续枚举, 剪枝1
if i > idx && num[idx] == b'0' {
break;
}
curr = curr * 10 + (num[i] - b'0') as i64;
if curr >= MAX {
// 题目要求每个数, 大于0, 小于 2**31
// 因此如果发现当前的数不符合, 则整个尝试无效, 剪枝2
break;
}
if ans.len() >= 2 {
// 斐波那契序列, 至少有3个, 因此在已经有2个数时,
// 第三个不能比前两个的加和小, 如果小, 也不用再套一层, 直接再吃一位
// 如果大, 那就必然组不成序列, 整个尝试无效, 剪枝3
if curr < sum {
continue;
} else if curr > sum {
break;
}
}
ans.push(curr);
if backtrack(ans, num, length, i+1, prev+curr, curr) {
return true;
}
ans.pop();
}
return false;
}
let mut ans = vec![];
if backtrack(&mut ans, num.as_bytes(), num.as_bytes().len(), 0, 0, 0) {
ans.into_iter().map(|n| n as i32).collect()
} else {
vec![]
}
}