【回溯】B022_LC_累加数(暴搜 / 空间压缩 / 进阶)

一、Problem

累加数是一个字符串,组成它的数字可以形成累加序列

一个有效的累加序列必须至少包含 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

进阶: 你如何处理一个溢出的过大的整数输入?

二、Solution

方法一:回溯

思考

获取到当前数 cur 时,如何能检查到前两个数?我选择用一个列表 fab 来存,下面就看看这个原创解法吧…

注:当字符串较长的时候,两个数相加的时候可能会溢出,故用 long 代替 int

class Solution {
public:
    vector<long> fab;
    bool dfs(int i, string& num) {
        if (i==num.size())
            return fab.size() > 2;

        for (int j=i; j<num.size(); j++) {
            string now_s = num.substr(i, j-i+1);
            if (now_s .size() > 1 && now_s.find("0") == 0)
                continue;
            long now = atol(now_s.c_str()), sz = fab.size();
            if (fab.size() >= 2 && now != fab[sz-1] + fab[sz-2])
                continue;
            fab.emplace_back(now);
            if (dfs(j+1, num))
                return true;
            fab.pop_back();
        }
        return false;
    }
    bool isAdditiveNumber(string& num) {
        return dfs(0, num);
    }
};

空间上可优化的地方就是:

  • 用一个 last 变量来存储上一个数字,以及用一个 cnt 来代替 fab.size() 的工作
  • 还有我们还差一个数 last_last,通过做差法来得到,详细看代码…
class Solution {
public:
    bool dfs(int i, long last, long s, int c, string& num) {
        if (i==num.size())
            return c > 2;

        for (int j=i; j<num.size(); j++) {
            string next = num.substr(i, j-i+1);
            if (next.size() > 1 && next.find("0") == 0)
                continue;
            long now = atol(next.c_str());
            if (c>=2 && now != s)
                continue;
            if (dfs(j+1, now, last+now, c+1, num))
                return true;
        }
        return false;
    }
    bool isAdditiveNumber(string& num) {
        return dfs(0, 0, 0, 0, num);
    }
};

复杂度分析

  • 时间复杂度: O ( . . . ) O(...) O(...)
  • 空间复杂度: O ( . . . ) O(...) O(...)

方法二:进阶

思考

进阶:当输入的字符串非常长时,写过代码的人都能想到不能强转整形来进行加减,所以很快就能想到用字符串加法以及字符串的比较来实现

所以,进阶问题的破解的核心就变成了字符串 num 的子串的获取(也就是子串下标的选择)

思路

  • 我们设三个子串的下标分别为 i、j、k
  • 首先,我们从小问题出发,选取的第一个子串的开始下标 i 肯定是 0,且 j > i,k > j
  • 有了 i、j、k 我们可以得到三个子串
  • 具体的合法判断逻辑 参考代码…
class Solution {
public:
    string sum(string& A, string& B) {
        int n=A.size(), m=B.size(), i=n-1, j=m-1, ca=0;
        string ans;
        while (i>=0 || j>=0) {
            int a = i<0 ? 0 : A[i--]-'0';
            int b = j<0 ? 0 : B[j--]-'0';
            int s = a+b+ca, t=0;
            if (s >= 10) {
                t=s%10;
                ca=s/10;
            } else {
                t=s;
                ca=0;
            };
            ans = to_string(t) + ans;
        }
        if (ca) ans = to_string(ca) + ans;
        return ans;
    }
    int n;
    bool dfs(int i, int j, int k, string& s) {
        if (s[i]=='0' && j-i>1 || (s[j]=='0' && k-j>1)) return false;
        string a=s.substr(i, j-i), b=s.substr(j, k-j), c=sum(a, b);
        int sz=c.size();
        if (c != s.substr(k, sz)) return false;
        if (sz == n-k) return true;
        return dfs(j, k, k+sz, s);
    }
    bool isAdditiveNumber(string& num) {
        n=num.size(); int i=0;
        for (int j=i+1; j<=n/2; j++)
        for (int k=j+1; k<n; k++) if (dfs(i, j, k, num))
            return true;
        return false;
    }
};

复杂度分析

  • 时间复杂度: O ( . . . ) O(...) O(...)
  • 空间复杂度: O ( . . . ) O(...) O(...)
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、 1资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READmE.文件(md如有),本项目仅用作交流学习参考,请切勿用于商业用途。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值