给定一个只包含数字 ‘0’-‘9’ 的字符串,编写一个算法来判断给定输入是否是累加数。
说明: 累加序列里的数不会以 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:
输入: "199100199"
输出: true
解释: 累加序列为: 1, 99, 100, 199。1 + 99 = 100, 99 + 100 = 199
进阶:
- 你如何处理一个溢出的过大的整数输入?
一、思路
首先,想想难点是什么,有哪些部分很难处理:
- 如何划分数字?
- 大数相加问题
- 怎么样才能遍历所有的可能组合?
- 最后,该题属于哪一类型的题目?
接下来一个一个的回答上述四个问题。
1、如何划分数字?
每次验证前两个数之和时,需要先确定这两个数,可是我们事先并不知道数字有多长,也不确定第二个数字的起始位置,于是要做的是:
- 确定第一个数字的长度len1
- 如此一来,第二个数字起始位置就确定下来了
- 接着确定其长度为len2
- 于是需要验证的数字的起始位置也确定了,其长度与前两数之和的长度一致
通过上述4个步骤,可以确定一次验证结果,此时分为两种情况:
(1)验证成功
验证成功时,可以进入下一轮次验证:
- 将数字往前挪动一位,即:之前的第二个数字变为第一个数字
- 原本验证成功的数字变为第二个数字
- 此时前两位数字已经确定下来了,于是第三个数字的首位可以确定
- 又因为前两个数字已经确定,其和也能很快计算出来,第三个数字的长度也就确定了
这就像骨诺米牌一样,一旦第一轮中的某次验证匹配了,剩下的轮次就不需要划分数字,直接匹配下去直到成功或者失败
(2)验证失败
这次验证失败并不代表本轮匹配失败,可以考虑增加第一个数字或者是第二个数字的长度,再参与比较验证,准确的说,就是我们需要遍历所有可能的组合,当所有的组合都失败了,我们才能说这一轮次匹配失败,结果返回false
2、大数相加问题
采用字符串加法,从末位加起
3、怎么样才能遍历所有的可能组合?
这个问题才是本题的关键所在,我们如何遍历所有可能的组合?
根据之前的分析,我们只需要找出第一轮中的所有组合即可,因为在第一轮中出现匹配之后,可以通过递归来确定,该配对是否成功。
C++代码:
class Solution {
public:
bool isAdditiveNumber(string num) {
int i1 = 0, len = num.size();
bool flag = false;
for(int len1=1; len1 < len; len1++){
string s1 = num.substr(i1, len1);
if(s1[0] == '0' && len1 > 1)
break;
for(int len2=1; len2 < len; len2++){
int i2 = i1 + len1;
string s2 = num.substr(i2, len2);
if(s2[0] == '0' && len2 > 1)
break;
string sum = addString(s1, s2);
int len3 = sum.size(), i3 = i2 + len2;
if(i3 + len3 > num.size())
break;
string s3 = num.substr(i3, len3);
if(sum == s3){
flag = dfs(num, s2, s3, i3 + len3);
}
if(flag)
return flag;
}
}
return false;
}
bool dfs(string& num, string& s1, string& s2, int i3){
if(i3 == num.size())
return true;
string sum = addString(s1, s2);
int len3 = sum.size();
if(i3 + len3 > num.size())
return false;
string s3 = num.substr(i3, len3);
if(s3 == sum)
return dfs(num, s2, s3, i3 + len3);
else
return false;
}
string addString(string& s1, string& s2){
string ans;
int i = s1.size() - 1, j = s2.size() - 1;
int carry = 0, p;
while(i >= 0 && j >= 0){
int t1 = s1[i] - '0', t2 = s2[j] - '0';
int temp = t1 + t2 + carry;
carry = temp / 10;
p = temp % 10;
char ch = p + '0';
ans = ch + ans;
i--;
j--;
}
while(i >= 0){
int t1 = s1[i] - '0';
int temp = t1 + carry;
carry = temp / 10;
p = temp % 10;
char ch = p + '0';
ans = ch + ans;
i--;
}
while(j >= 0){
int t2 = s2[j] - '0';
int temp = t2 + carry;
carry = temp / 10;
p = temp % 10;
char ch = p + '0';
ans = ch + ans;
j--;
}
if(carry){
char ch = carry + '0';
ans = ch + ans;
}
return ans;
}
};