トピック:
累積数は文字列であり、それを構成する数は累積シーケンスを形成できます。
有効な累積シーケンスには、少なくとも3つの数値が含まれている必要があります。最初の2つの数値を除いて、文字列内の他の数値は、前の2つの数値の合計に等しくなります。
数字「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
詳細:
オーバーフローした整数入力をどのように処理しますか?
ソース:
問題解決のアイデア:バックトラック
この質問は、数値文字列をフィボナッチ数列に分割することに似ていますが、この質問はブール型を返し、数値が非常に大きい点が異なります。
分割数を記録する配列パスを定義します。
- 再帰的終了条件:文字列の分割が完了し、少なくとも3つの数値が分割されている
- 剪定条件:1つが完了したとき、または最初の数字が入力されたとき、その長さが文字列の半分を超えている場合、分割してはならない、または最初の2つの数字の合計が現在の数字nよりも小さい場合。
class Solution {
public:
vector<long> path;
bool finish;
bool isAdditiveNumber(string S) {
finish = false;
// 处理开头的0
int start = 0;
while (start < S.size() && S[start] == '0') {
path.push_back(0);
start++;
}
back(S, start);
return finish;
}
void back(const string& s, int start) {
if (path.size() > 2 && start == s.size()) {
finish = true;
return;
}
// 处理开头的0
if (s[start] == '0') {
if (path.size() < 2) {
path.push_back(0);
back(s, start + 1);
path.pop_back();
}
return;
}
long n = 0;
for (int i = start; i < s.size(); i++) {
if (finish) break;
int sz = path.size();
if ((sz == 0 && i >= s.size()/2) ||
(sz > 1 && path[sz-1] + path[sz-2] < n)) break;
n = n * 10 + s[i] - '0'; // n:[start,i]内的数字
if (sz < 2 || path[sz-1] + path[sz-2] == n) {
path.push_back(n);
back(s, i + 1);
path.pop_back();
}
}
}
};