第6题:306. Additive Number
题目大意:给定一串字符串,判断该字符串是否能够切分成多个个子字符串,使得前两个子串对应数字之和等于后一个子串对应数字之和,类似斐波拉契数列。
题目分析:题目的意思很明显了,就是要看清楚题目的要求(又是因为要求没看清楚,所以提交了4 5次才提交上去,菜是原罪)。主要要求总结如下:
1. 基本要求,后一个数字是前两个数字之和,第1 2个数字除外(也就是说第1 2个数字决定了这个字符串)
1. 字符串长度至少是3,至少是3个个位数数字
2. 字符只会出现0-9,不会出现其他字符
3. 第三点就是他题目的note指出来的,也是很重要的一点,子串所表示的数字不能是0开头,也就是01、003等不能作为一个子串。这一点需要仔细考虑一下的,我就是这点没有理解清楚,不能以0开头,但是可以是0!!!比如1,0,1这个串是符合的,但是1,0,01这个是不符合的。第一个数字也是如此,不能0开头,可以是0.
4. 大整数溢出问题(说明要采用字符串加法)
要求归结好了之后,来看解决方法。就是字符串切割之后做的一个加法,对于一个满足要求的字符串,字符串由第1 2个数字子串得到,所以初步想法就是确定第一个数和第二个数。这里是一个二重循环,然后第一 二个数字确定好了之后,利用加法累加,总是前两个数相加得到后一个数(内部循环得到,终止条件:累加得到字符串长度大于或等于待判定字符串)。最终将得到的字符串和待判定字符串进行比较,如果一致,则表示该字符串满足要求。否则,不满足。最终AC代码如下:
class Solution {
public:
string stringAdd(string str1, string str2) {//字符串大整数加法
int len1 = str1.size();
int len2 = str2.size();
string op1, op2;
int cnt = len1>len2 ?(len1 - len2):(len2-len1);
string tem = "";
for(int i=0;i<cnt;i++){
tem = tem + "0";
}
if(len1 > len2){
str2 = tem + str2;
} else str1 = tem + str1;
// cout <<str1 <<"\n" <<str2 <<endl;
int len = str1.size();
string res = "";
int flag = 0;
int sum = 0;
for(int i=len-1;i>=0;i--){
sum = (str1[i] - '0') + (str2[i]-'0') +flag;
res = char((sum%10 + '0')) + res;
flag = sum/10;
}
if(flag==1) res = "1" + res;
// cout <<res <<endl;
return res;
}
bool isEqual(string str1, string str2){ //判断最终字符串是否相等
int len1 = str1.size();
int len2 = str2.size();
if(len1 != len2) return false;
for(int i=0;i<len1;i++){
if(str1[i] != str2[i]) return false;
}
return true;
}
bool isAdditiveNumber(string num) {
int len = num.size();
if(len <3) return false; //长度小于3,不满足
int index1 , index2 = 0;
for(index1 = 0;index1<=len/2;index1++){ //第一个字符串长度最多为len/2
string s1 = num.substr(0, index1+1);
// cout <<"s1 = " <<s1 <<endl;
if(s1[0]=='0' && s1.size() !=1) break; //开头是0,但不是0,则不满足
for(index2 = 1;index2<=len/2;index2++){ //第一个字符串长度最多为len/2
string s2 = num.substr(index1+1, index2);
if(s2[0]=='0' && s2.size()!=1) break; // 第一个字符串开头是0,但不是0
int cnt = index1 + 1 + index2; //记录当前长度
if(cnt >= len) break;
string res = s1 + s2;
string op1, op2;
op1 = s1; op2 = s2;
while(cnt<len){ //内部循环累加
string tem = stringAdd(op1, op2);
// cout <<"tem = " <<tem <<endl;
if(tem[0] != num[cnt]) break;
/**
* 这里为了防止时间超了,做了一下剪枝,即是所求之和的第一个数字不等于
* 原字符串中当前长度的字符值,做一个初步筛选.不可能每一次加法都做一次字符
* 串的对比,这样比较次数太多
**/
cnt += tem.size();
res = res + tem;
op1 = op2;
op2 = tem;
}
// cout <<"res = " <<res <<endl;
if(isEqual(res, num)) return true; //将由第1 2个数所求字符串与原串比较
}
}
return false;
}
};