leetcode题集: 306. Additive Number

24 篇文章 0 订阅
2 篇文章 0 订阅

第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;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值