累加数 是一个字符串,组成它的数字可以形成累加序列。
一个有效的 累加序列 必须 至少 包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给你一个只包含数字 '0'-'9' 的字符串,编写一个算法来判断给定输入是否是 累加数 。如果是,返回 true ;否则,返回 false 。
说明:累加序列里的数,除数字 0 之外,不会 以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
示例 1:
输入:"112358"
输出:true
解释:累加序列为: 1, 1, 2, 3, 5, 8 。1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8
示例 2:
输入:"11245157"
输出:true
解释:累加序列为: 112, 45, 157。112 + 45 = 157
分析:
拿"11245157"举例:
- 1 + 1 = 2 满足条件,进行下一层
- 4 + 5 ≠ 1 ≠ 15 ≠ 157 不满足,调整后面加数
- 4 + 51 ≠ 5 ≠ 57 不满足,调整后面加数
- 4 + 515 ≠ 7 不满足,后面加数调整完,调整前面加数
- 45 + 1 ≠ 5 ≠ 57 不满足,调整后面加数
- 45 + 15 ≠ 7 不满足,后面加数调整完,调整前面加数
- 451 + 5 ≠ 7 不满足,前面加数调整完,此层无结果,回到上一层
- 1 + 12 ≠ 4 ≠ 45 ≠ 451 ≠ 4515 ≠ 45157 不满足,调整后面加数
- ...... 按照上面方式遍历
- 112 + 45 ≠ 1 ≠ 15 == 157 满足条件,结束
不难看出,这种题用回溯来解比较简单,采取深度优先的遍历,满足条件进行下一层遍历,下一层若所有节点都不满足条件,则回溯到上一层,直到一个分支满足条件或都不满足条件结束。考虑要动态进行添加删除,我们可以用一个集合(List)来存储结果,满足条件时,加入集合,下一层不满足条件时移出集合。需要注意的几点是:
- 集合每三个元素为:加数,加数,和。和在与前面加数和相等时加入,然后进入下一层遍历。
- 遍历到最后一层时,若集合还是三个以上,说明没有回溯,都满足条件,返回真,否则假。
- 如果首数字为 0 ,那么此加数或和只能为 0
class Solution {
//累加序列单个数
char[] cs = null;
//序列长度
int len = 0;
//结果集合
List<Integer> res = new ArrayList<>();
public boolean isAdditiveNumber(String num) {
cs = num.toCharArray();
len = cs.length;
return dfs(0);
}
//深度优先遍历
public boolean dfs(int n){
int size = res.size();
//遍历完了,若集合还是三个以上,说明没有回溯,都满足条件
if(n == len){
return size >= 3;
}
//如果首数字为 0 ,那么此加数只能为 0
int length = cs[n] == '0'? n + 1: len;
//加数或和
int sum = 0;
//遍历
for(int i = n; i < length; ++i){
//累加
sum = sum * 10 + cs[i] - '0';
//集合长度不小于2时进行加法比较
if(size < 2 || res.get(size - 2) + res.get(size-1) == sum){
//添加加数或和
res.add(sum);
//进行下一层比较
if(dfs(i+1)){
return true;
}
//下一层节点都不满足,删除添加的数,进行回溯
res.remove(size);
}
}
return false;
}
}
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/additive-number