一、题目描述
累加数是一个字符串,组成它的数字可以形成累加序列。
一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给定一个只包含数字 '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)情况非常多,采用回溯的方法
2)特殊情况:以0为开头的非零整数;特大数long long
3)具体解析请看代码注释
三、实现代码
1 class Solution { 2 public: 3 bool isAdditiveNumber(string num) { 4 int n = num.size(); 5 if (n < 3)return false; 6 long long ppre = 0, pre = 0; 7 //找出第一个数和第二个数 8 for (int i = 1; i <= n / 2; ++i) {//第一个数的长度不能超过n/2 9 ppre = stoi(num.substr(0, i)); 10 for (int j = 1; i + j <= (n * 2) / 3; ++j) {//第一个和第二个数总的长度不能超过2/3 11 pre = stoi(num.substr(i, j));//从位置i开始截取 12 if (dfs(i + j, max(i, j), pre, ppre, num))return true;//第二个数不一定比第一个数大 13 } 14 } 15 return false; 16 } 17 private: 18 /** 19 * 计算当前的数是不是前两个数的和 20 * pos代表当前指针达到的位置 21 * len代表要截取的长度 22 * pre代表前面的数 23 * ppre代表前一个的前一个数 24 * s代表字符串 25 */ 26 bool dfs(int pos, int len, long long pre, long long ppre, string &s) { 27 int n = s.size(); 28 if (pos == n)return true;//已经计算到最后了 29 bool flag = false; 30 long long cur = 0; 31 for (int i = len; pos + i <= n; ++i) { 32 cur = stoi(s.substr(pos, i)); 33 if (cur > pre + ppre)break;//当前的数大于两者之和,就跳出循环,不能再截取更长的长度了 34 if (cur < pre + ppre)continue;//如果当前的数小于两者之和,就截取更长的一位 35 flag = dfs(pos + i, i, cur, pre, s);//对当前来说两者相等,继续检验,下一次的开始长度至少和前面一个一样 36 if (flag)break;//只要找到一个,就可以跳出了 37 } 38 return flag; 39 } 40 /** 41 * 把字符串转换成整数 42 */ 43 long long stoi(const string &s) { 44 if (s.size() > 1 && s[0] == '0')return -1; 45 stringstream ss(s); 46 long long res; 47 ss >> res; 48 return res; 49 } 50 51 };
需要注意的地方有:第8行和第10行的等号;第43行的const