給定一個只包含數字 ‘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;
}
};