回溯题目:累加数

题目

标题和出处

标题:累加数

出处:306. 累加数

难度

5 级

题目描述

要求

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

一个有效的累加序列必须至少包含 3 \texttt{3} 3 个数。除了最开始的两个数以外,序列中的每个后续数字必须是它之前两个数字之和。

给定一个只包含数字的字符串,如果字符串是累加数则返回 true \texttt{true} true,否则返回 false \texttt{false} false

累加序列里的数不能有前导零,所以 1,   2,   03 \texttt{1, 2, 03} 1, 2, 03 1,   02,   3 \texttt{1, 02, 3} 1, 02, 3 都是无效的。

示例

示例 1:

输入: num   =   "112358" \texttt{num = "112358"} num = "112358"
输出: true \texttt{true} true
解释:
累加序列为: 1,   1,   2,   3,   5,   8 \texttt{1, 1, 2, 3, 5, 8} 1, 1, 2, 3, 5, 8 1 + 1 = 2 \texttt{1} + \texttt{1} = \texttt{2} 1+1=2 1 + 2 = 3 \texttt{1} + \texttt{2} = \texttt{3} 1+2=3 2 + 3 = 5 \texttt{2} + \texttt{3} = \texttt{5} 2+3=5 3 + 5 = 8 \texttt{3} + \texttt{5} = \texttt{8} 3+5=8

示例 2:

输入: num   =   "199100199" \texttt{num = "199100199"} num = "199100199"
输出: true \texttt{true} true
解释:
累加序列为: 1,   99,   100,   199 \texttt{1, 99, 100, 199} 1, 99, 100, 199 1 + 99 = 100 \texttt{1} + \texttt{99} = \texttt{100} 1+99=100 99 + 100 = 199 \texttt{99} + \texttt{100} = \texttt{199} 99+100=199

数据范围

  • 1 ≤ num.length ≤ 35 \texttt{1} \le \texttt{num.length} \le \texttt{35} 1num.length35
  • num \texttt{num} num 仅由数字组成

进阶

你如何处理过大的整数输入导致的溢出?

解法

思路和算法

根据累加序列的定义,只要确定前两个数,即可确定累加序列。由于累加序列至少包含 3 3 3 个数,因此需要枚举前 3 3 3 个数的开始下标,然后判断给定的字符串 num \textit{num} num 是否为累加数。

整个累加序列的第一个数的开始下标是 0 0 0,需要枚举第二个数和第三个数的开始下标判断是否存在累加序列。可以使用回溯判断是否组成累加序列。

回溯过程中需要记录三个数的开始下标 start 1 \textit{start}_1 start1 start 2 \textit{start}_2 start2 start 3 \textit{start}_3 start3,则前两个数的结束下标分别是 start 2 − 1 \textit{start}_2 - 1 start21 start 3 − 1 \textit{start}_3 - 1 start31,长度分别是 start 2 − start 1 \textit{start}_2 - \textit{start}_1 start2start1 start 3 − start 2 \textit{start}_3 - \textit{start}_2 start3start2。回溯的做法如下。

  1. 如果前两个数存在长度大于 1 1 1 且最高位是 0 0 0 的情况,则存在前导零,不符合累加序列的要求。

  2. 如果 start 3 \textit{start}_3 start3 等于字符串 num \textit{num} num 的长度,则到达字符串的末尾且序列至少包含 3 3 3 个数,符合累加序列的要求。

  3. 计算前两个数的和,根据前两个数的和计算第三个数的长度,并与第三个数比较。

    • 如果第三个数的长度大于 1 1 1 且第三个数的最高位是 0 0 0,则存在前导零,不符合累加序列的要求。

    • 如果前两个数的和与第三个数不匹配,则不符合累加序列的要求。

    • 如果第三个数不存在前导零,且前两个数的和与第三个数匹配,则将第二个数和第三个数作为三个数中的前两个数,继续回溯。

如果遇到累加序列,则返回 true \text{true} true。如果回溯结束时仍没有遇到累加序列,则返回 false \text{false} false

实现方面,由于整数位数可能较多,为了避免溢出,可以使用字符串操作模拟整数加法。

代码

class Solution {
    int n;
    String num;

    public boolean isAdditiveNumber(String num) {
        this.n = num.length();
        this.num = num;
        for (int start2 = 1; start2 < n; start2++) {
            for (int start3 = start2 + 1; start3 < n; start3++) {
                if (backtrack(0, start2, start3)) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean backtrack(int start1, int start2, int start3) {
        int length1 = start2 - start1, length2 = start3 - start2;
        if (length1 > 1 && num.charAt(start1) == '0' || length2 > 1 && num.charAt(start2) == '0') {
            return false;
        }
        if (start3 == n) {
            return true;
        }
        String sum = addStrings(start1, start2 - 1, start2, start3 - 1);
        int length3 = sum.length();
        if (length3 > 1 && num.charAt(start3) == '0' || !equals(sum, start3)) {
            return false;
        }
        return backtrack(start2, start3, start3 + length3);
    }

    public String addStrings(int start1, int end1, int start2, int end2) {
        StringBuffer sb = new StringBuffer();
        int index1 = end1, index2 = end2;
        int carry = 0;
        while (index1 >= start1 || index2 >= start2 || carry != 0) {
            int digit1 = index1 >= start1 ? num.charAt(index1) - '0' : 0;
            int digit2 = index2 >= start2 ? num.charAt(index2) - '0' : 0;
            int sum = digit1 + digit2 + carry;
            sb.append(sum % 10);
            carry = sum / 10;
            index1--;
            index2--;
        }
        return sb.reverse().toString();
    }

    public boolean equals(String sum, int start) {
        int sumLength = sum.length();
        if (n - start < sumLength) {
            return false;
        }
        for (int i = 0; i < sumLength; i++) {
            if (sum.charAt(i) != num.charAt(start + i)) {
                return false;
            }
        }
        return true;
    }
}

复杂度分析

  • 时间复杂度: O ( n 3 ) O(n^3) O(n3),其中 n n n 是字符串 num \textit{num} num 的长度。需要 O ( n 2 ) O(n^2) O(n2) 的时间枚举整个累加序列的第二个数和第三个数的开始下标,对于每个可能的序列需要 O ( n ) O(n) O(n) 的时间判断是否符合累加序列的要求,因此时间复杂度是 O ( n 3 ) O(n^3) O(n3)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 num \textit{num} num 的长度。递归调用栈的层数是 O ( n ) O(n) O(n)

内容概要:本文提出了一种基于改进扩散模型的高海拔地区新能源高波动出力场景生成方法,并提供了完整的Python代码实现。该方法针对高海拔地区风能、光伏等新能源出力波动剧烈、不确定性高的特点,通过优化扩散模型的结构与训练策略,有效捕捉历史据的概率分布特征与时序相关性,从而生成高质量、多样化的出力场景。文中详细阐述了模型的学推导、网络架构设计、损失函优化及采样算法改进,并通过实验证明其在拟合精度、场景多样性与稳定性方面优于传统生成模型,为电力系统在高比例新能源接入下的规划、调度与风险评估提供了可靠的场景输入支持。; 适合人群:具备一定Python编程能力和机器学习基础,从事新能源发电预测、电力系统分析、智能优化、场景生成等方向研究的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①用于高海拔地区风电、光伏出力的不确定性建模与多场景生成;②支撑含高渗透率新能源的电力系统随机优化调度、鲁棒决策与风险评估;③为相关学术研究、论文复现与算法改进提供可运行的技术方案与代码基础; 阅读建议:建议读者结合所提供的完整资源(代码、据集、说明文档)进行实践操作,重点关注扩散模型的前向加噪与反向去噪过程的设计细节,以及如何将其适配于新能源时序据的生成任务,通过参调优与对比实验深入理解模型的生成机制与性能边界。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值