【六十九】【算法分析与设计】509. 斐波那契数,983. 最低票价,91. 解码方法,从暴力递归开始改写记忆化递归+动态规划

509. 斐波那契数

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1

F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n)

示例 1:

输入:n = 2 输出:1 解释:F(2) = F(1) + F(0) = 1 + 0 = 1

示例 2:

输入:n = 3 输出:2 解释:F(3) = F(2) + F(1) = 1 + 1 = 2

示例 3:

输入:n = 4 输出:3 解释:F(4) = F(3) + F(2) = 2 + 1 = 3

提示:

  • 0 <= n <= 30

暴力递归

 
#if 1  // 如果条件为真,则编译以下代码
class Solution {  // 定义一个名为Solution的类
public:

    int dfs(int n){  // 定义一个名为dfs的递归函数,用于计算斐波那契数列的第n项
        if(n==0) return 0;  // 如果n为0,直接返回0(斐波那契数列的第0项是0)
        if(n==1||n==2) return 1;  // 如果n为1或2,直接返回1(斐波那契数列的第1项和第2项都是1)

        return dfs(n-1)+dfs(n-2);  // 递归调用自身,计算第n项的值,即前两项的和
    }
    void solveinit(){  // 定义一个名为solveinit的函数,目前是空的,可能用于初始化操作

    }
    int fib(int n) {  // 定义一个名为fib的函数,用于接口调用,返回斐波那契数列的第n项
        solveinit();  // 调用solveinit函数(尽管它目前没有实际操作)
        return dfs(n);  // 调用dfs函数计算并返回斐波那契数列的第n项
    }

};
#endif  // 结束#if预处理指令

记忆化递归

 
#if 1  // 如果条件为真,则编译以下代码
class Solution {  // 定义一个名为Solution的类
public:
    vector<int> memory;  // 定义一个vector,用于存储已计算的斐波那契数,以避免重复计算
    int n;  // 定义一个整型变量n,用于存储斐波那契数列的需求项数

    int dfs(int n){  // 定义一个名为dfs的递归函数,用于计算斐波那契数列的第n项
        if(n==0) return 0;  // 如果n为0,直接返回0(斐波那契数列的第0项是0)
        if(n==1||n==2) return 1;  // 如果n为1或2,直接返回1(斐波那契数列的第1项和第2项都是1)
        if(memory[n]!=-1) return memory[n];  // 如果这一项已经计算过,直接返回之前计算的结果

        memory[n]=dfs(n-1)+dfs(n-2);  // 递归调用自身,计算第n项的值,即前两项的和,并存储结果
        return memory[n];  // 返回存储的结果
    }
    void solveinit(){  // 定义一个名为solveinit的函数,用于初始化内存数组
        memory.clear();  // 清空memory数组
        memory.resize(n+1,-1);  // 将memory数组大小调整为n+1,并初始化所有值为-1
    }
    int fib(int _n) {  // 定义一个名为fib的函数,用于接口调用,返回斐波那契数列的第n项
        n=_n;  // 将传入的参数_n赋值给成员变量n
        solveinit();  // 调用solveinit函数进行初始化
        return dfs(n);  // 调用dfs函数计算并返回斐波那契数列的第n项
    }

};
#endif  // 结束#if预处理指令

动态规划

 
class Solution {  // 定义一个名为Solution的类
public:
    int n;  // 定义一个整型变量n,用于存储斐波那契数列的需求项数
    vector<int> dp;  // 定义一个名为dp的vector数组,用于动态规划中存储斐波那契数列的各项值

    void solveinit(){  // 定义一个名为solveinit的函数,用于初始化dp数组
        dp.clear();  // 清空dp数组
        dp.resize(n+1);  // 将dp数组的大小调整为n+1(因为需要从0到n的位置)
        dp[0]=0;  // 初始化斐波那契数列的第0项为0
        dp[1]=1;  // 初始化斐波那契数列的第1项为1
        dp[2]=1;  // 初始化斐波那契数列的第2项也为1
    }
    int fib(int _n) {  // 定义一个名为fib的函数,用于计算并返回斐波那契数列的第n项
        n=_n;  // 将传入的参数_n赋值给成员变量n

        if(n==0) return 0;  // 如果n为0,直接返回0(斐波那契数列的第0项是0)
        if(n==1||n==2) return 1;  // 如果n为1或2,直接返回1(斐波那契数列的第1项和第2项都是1)
        solveinit();  // 调用solveinit函数进行dp数组的初始化

        for(int i=3;i<=n;i++){  // 从第3项开始,遍历到第n项
            dp[i]=dp[i-1]+dp[i-2];  // 动态规划公式,当前项等于前两项的和
        }

        return dp[n];  // 返回dp数组中的第n项,即斐波那契数列的第n项
        
    }
};

动态规划+空间压缩

 
class Solution {  // 定义一个名为Solution的类
public:
    int n;  // 定义一个整型变量n,用于存储斐波那契数列的需求项数
    int a, b, c;  // 定义三个整型变量a, b, c,用于计算斐波那契数列

    void solveinit(){  // 定义一个名为solveinit的函数,用于初始化变量a, b, c
        a=1;  // 初始化a为1,表示斐波那契数列的第二项
        b=1;  // 初始化b为1,表示斐波那契数列的第二项
        c=2;  // 初始化c为2,起初设置为第三项的预设值,虽然它将被计算覆盖
    }
    int fib(int _n) {  // 定义一个名为fib的函数,用于计算并返回斐波那契数列的第n项
        n=_n;  // 将传入的参数_n赋值给成员变量n

        if(n==0) return 0;  // 如果n为0,直接返回0(斐波那契数列的第0项是0)
        if(n==1||n==2) return 1;  // 如果n为1或2,直接返回1(斐波那契数列的第1项和第2项都是1)
        solveinit();  // 调用solveinit函数进行变量初始化

        for(int i=3;i<=n;i++){  // 从第3项开始,遍历到第n项
            c=a+b;  // 当前项c计算为前两项a和b的和
            a=b;  // 将b的值赋给a,为下一次计算做准备
            b=c;  // 将当前计算出的c的值赋给b,为下一次计算做准备
        }

        return c;  // 返回变量c的值,即斐波那契数列的第n项
        
    }
};

983. 最低票价

在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行。在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出。每一项是一个从 1365 的整数。

火车票有 三种不同的销售方式

  • 一张 为期一天 的通行证售价为 costs[0] 美元;

  • 一张 为期七天 的通行证售价为 costs[1] 美元;

  • 一张 为期三十天 的通行证售价为 costs[2] 美元。

通行证允许数天无限制的旅行。 例如,如果我们在第 2 天获得一张 为期 7 天 的通行证,那么我们可以连着旅行 7 天:第 2 天、第 3 天、第 4 天、第 5 天、第 6 天、第 7 天和第 8 天。

返回 你想要完成在给定的列表 days 中列出的每一天的旅行所需要的最低消费

示例 1:

输入:days = [1,4,6,7,8,20], costs = [2,7,15] 输出:11 解释: 例如,这里有一种购买通行证的方法,可以让你完成你的旅行计划: 在第 1 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 1 天生效。 在第 3 天,你花了 costs[1] = $7 买了一张为期 7 天的通行证,它将在第 3, 4, ..., 9 天生效。 在第 20 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 20 天生效。 你总共花了 $11,并完成了你计划的每一天旅行。

示例 2:

输入:days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15] 输出:17 解释: 例如,这里有一种购买通行证的方法,可以让你完成你的旅行计划: 在第 1 天,你花了 costs[2] = $15 买了一张为期 30 天的通行证,它将在第 1, 2, ..., 30 天生效。 在第 31 天,你花了 costs[0] = $2 买了一张为期 1 天的通行证,它将在第 31 天生效。 你总共花了 $17,并完成了你计划的每一天旅行。

提示:

  • 1 <= days.length <= 365

  • 1 <= days[i] <= 365

  • days 按顺序严格递增

  • costs.length == 3

  • 1 <= costs[i] <= 1000

暴力递归

 
class Solution {  // 定义一个名为Solution的类
public:
    vector<int> days;  // 定义一个向量days,存储预计旅行的所有天数
    vector<int> costs;  // 定义一个向量costs,存储三种不同通行证的费用
    int __n;  // 定义一个整数__n,用于记录days向量的长度
    vector<int> __jiaqi;  // 定义一个向量__jiaqi,存储三种通行证的有效天数

    int dfs(int __i) {  // 定义一个名为dfs的递归函数,用于计算从第__i天开始的最低票价
        if (__i == __n)  // 如果__i等于__n,说明已经处理完所有旅行的天数
            return 0;  // 在这种情况下,没有更多的费用,返回0

        int __curday = days[__i];  // 获取当前处理的天数
        int __ans = INT_MAX;  // 初始化__ans为最大整数,用于找到最小花费
        int __j = __i;  // 初始化索引__j为当前位置__i
        for (int k = 0; k < 3; k++) {  // 遍历三种通行证
            int __nextday = __curday + __jiaqi[k];  // 计算当前通行证有效的最后一天
            while (__j < __n && days[__j] < __nextday) {  // 找到当前通行证覆盖的最后一个旅行日
                __j++;
            }
            __ans = min(__ans, costs[k] + dfs(__j));  // 更新__ans为最小花费,包括当前通行证的费用加上后续旅行的最小费用
        }
        return __ans;  // 返回计算的最小花费
    }
    void solveinit() {  // 定义一个名为solveinit的函数,用于初始化变量和向量
        __n = days.size();  // 设置__n为days向量的长度
        __jiaqi.clear();  // 清空__jiaqi向量
        __jiaqi.resize(3);  // 设置__jiaqi向量的大小为3
        __jiaqi[0] = 1;  // 设置一天通行证的有效天数
        __jiaqi[1] = 7;  // 设置七天通行证的有效天数
        __jiaqi[2] = 30;  // 设置三十天通行证的有效天数
    }
    int mincostTickets(vector<int>& _days, vector<int>& _costs) {  // 定义一个名为mincostTickets的函数,用于计算整个旅行计划的最低票价
        days = _days;  // 将输入的_days向量赋值给days
        costs = _costs;  // 将输入的_costs向量赋值给costs
        solveinit();  // 调用solveinit函数进行初始化
        return dfs(0);  // 从第0天开始调用dfs函数,计算并返回最低票价
    }
};

记忆化递归

 
class Solution { // 定义一个名为Solution的类
public:
    vector<int> days; // 定义一个向量days,存储计划旅行的所有天数
    vector<int> costs; // 定义一个向量costs,存储三种不同通行证的费用
    int __n; // 定义一个整数__n,用于记录days向量的长度
    vector<int> __jiaqi; // 定义一个向量__jiaqi,存储三种通行证的有效天数
    vector<int>
        __memory; // 定义一个向量__memory,用于记忆化搜索,存储已计算的结果,避免重复计算
    vector<int>
        __dp; // 定义一个向量__dp,用于动态规划,存储从每一天起的最小花费

    void solveinit() { // 定义一个名为solveinit的函数,用于初始化变量和向量
        __n = days.size(); // 设置__n为days向量的长度
        __jiaqi.clear();   // 清空__jiaqi向量
        __jiaqi.resize(3); // 设置__jiaqi向量的大小为3
        __jiaqi[0] = 1;    // 设置一天通行证的有效天数为1
        __jiaqi[1] = 7;    // 设置七天通行证的有效天数为7
        __jiaqi[2] = 30;   // 设置三十天通行证的有效天数为30
        __memory.clear();  // 清空__memory向量
        __memory.resize(__n + 1,
                        -1); // 设置__memory向量的大小为__n+1,并初始化为-1
        __dp.clear();             // 清空__dp向量
        __dp.resize(__n + 1, -1); // 设置__dp向量的大小为__n+1,并初始化为-1
        __dp[__n] = 0; // 设置动态规划基准情况:最后一天之后的花费为0
    }
    int mincostTickets(
        vector<int>& _days,
        vector<int>&
            _costs) { // 定义一个名为mincostTickets的函数,用于计算整个旅行计划的最低票价
        days = _days; // 将输入的_days向量赋值给days
        costs = _costs; // 将输入的_costs向量赋值给costs
        solveinit();    // 调用solveinit函数进行初始化

        for (int __i = __n - 1; __i >= 0;
             __i--) { // 从最后一个旅行日向前计算每一天的最低票价
            int __curday = days[__i]; // 获取当前处理的天数
            int __ans = INT_MAX; // 初始化__ans为最大整数,用于找到最小花费
            int __j = __i; // 初始化索引__j为当前位置__i
            for (int k = 0; k < 3; k++) { // 遍历三种通行证
                int __nextday =
                    __curday + __jiaqi[k]; // 计算当前通行证允许的最后一天
                while (__j < __n &&
                       days[__j] <
                           __nextday) { // 找到当前通行证覆盖的最后一个旅行日
                    __j++;
                }
                __ans = min(
                    __ans,
                    costs[k] +
                        __dp[__j]); // 更新__ans为最小花费,包括当前通行证的费用加上后续旅行的最小费用
            }

            __dp[__i] =
                __ans; // 将计算出的最小费用存储在动态规划数组__dp中,对应于当前天数__i的位置。
        }
        return __dp[0]; // 最终返回从第一天开始的最低总花费
    }
};

动态规划

 
class Solution { // 定义一个名为Solution的类
public:
        vector<int> days; // 定义一个向量days,存储计划旅行的所有天数
        vector<int> costs; // 定义一个向量costs,存储三种不同通行证的费用
        int __n; // 定义一个整数__n,用于记录days向量的长度
        vector<int> __jiaqi; // 定义一个向量__jiaqi,存储三种通行证的有效天数
        vector<int>                __memory; // 定义一个向量__memory,用于记忆化搜索,存储已计算的结果,避免重复计算
        vector<int>                __dp; // 定义一个向量__dp,用于动态规划,存储从每一天起的最小花费

        void solveinit() { // 定义一个名为solveinit的函数,用于初始化变量和向量
                __n = days.size(); // 设置__n为days向量的长度
                __jiaqi.clear();   // 清空__jiaqi向量
                __jiaqi.resize(3); // 设置__jiaqi向量的大小为3
                __jiaqi[0] = 1;    // 设置一天通行证的有效天数为1
                __jiaqi[1] = 7;    // 设置七天通行证的有效天数为7
                __jiaqi[2] = 30;   // 设置三十天通行证的有效天数为30
                __memory.clear();  // 清空__memory向量
                __memory.resize(__n + 1, -1); // 设置__memory向量的大小为__n+1,并初始化为-1
                __dp.clear();             // 清空__dp向量
                __dp.resize(__n + 1, -1); // 设置__dp向量的大小为__n+1,并初始化为-1
                __dp[__n] = 0; // 设置动态规划基准情况:最后一天之后的花费为0
        }
        int mincostTickets(
                vector<int>& _days,
                vector<int>&
                _costs) { // 定义一个名为mincostTickets的函数,用于计算整个旅行计划的最低票价
                days = _days; // 将输入的_days向量赋值给days
                costs = _costs; // 将输入的_costs向量赋值给costs
                solveinit();    // 调用solveinit函数进行初始化

                for (int __i = __n - 1; __i >= 0; __i--) { // 从最后一个旅行日向前计算每一天的最低票价
                        int __curday = days[__i]; // 获取当前处理的天数
                        int __ans = INT_MAX; // 初始化__ans为最大整数,用于找到最小花费
                        int __j = __i; // 初始化索引__j为当前位置__i
                        for (int k = 0; k < 3; k++) { // 遍历三种通行证
                                int __nextday = __curday + __jiaqi[k]; // 计算当前通行证允许的最后一天
                                while (__j < __n && days[__j] < __nextday) { // 找到当前通行证覆盖的最后一个旅行日
                                        __j++;
                                }
                                __ans = min(__ans, costs[k] + __dp[__j]); // 更新__ans为最小花费,包括当前通行证的费用加上后续旅行的最小费用
                        }

                        __dp[__i] = __ans; // 将计算出的最小费用存储在动态规划数组__dp中,对应于当前天数__i的位置。
                }
                return __dp[0]; // 最终返回从第一天开始的最低总花费
        }
};

91. 解码方法

一条包含字母 A-Z 的消息通过以下映射进行了 编码

'A' -> "1"

'B' -> "2"

...

'Z' -> "26"

解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:

  • "AAJF" ,将消息分组为 (1 1 10 6)

  • "KJF" ,将消息分组为 (11 10 6)

注意,消息不能分组为 (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6""06" 在映射中并不等价。

给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的 总数

题目数据保证答案肯定是一个 32 位 的整数。

示例 1:

输入:s = "12" 输出:2 解释:它可以解码为 "AB"(1 2)或者 "L"(12)。

示例 2:

输入:s = "226" 输出:3 解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

示例 3:

输入:s = "06" 输出:0 解释:"06" 无法映射到 "F" ,因为存在前导零("6" 和 "06" 并不等价)。

提示:

  • 1 <= s.length <= 100

  • s 只包含数字,并且可能包含前导零。

暴力递归

 
class Solution {  // 定义一个名为Solution的类
public:
    string __s;  // 定义一个字符串变量__s,用于存储输入的编码字符串
    int __n;  // 定义一个整数变量__n,用于存储字符串的长度

    int dfs(int __i) {  // 定义一个名为dfs的递归函数,用于计算从位置__i开始的解码方法总数
        if (__i == __n)  // 如果索引__i等于字符串长度__n,表示已经处理完所有字符
            return 1;  // 在这种情况下,找到了一种有效的解码方式,返回1

        if (__s[__i] == '0')  // 如果当前字符是'0',它不能解码为任何字母(没有单独的'0'映射)
            return 0;  // 返回0,表示从这个位置开始的字符串无法解码

        int __ans = 0;  // 初始化__ans变量为0,用于累加从当前位置开始的所有可能的解码方式
        __ans += dfs(__i + 1);  // 递归调用dfs函数处理下一个字符,并将返回值加到__ans

        if (__i + 1 < __n &&  // 如果当前位置后还有至少一个字符,并且
            ((__s[__i] - '0') * 10 + (__s[__i + 1] - '0')) <= 26)  // 当前位置和下一个位置的两个数字组成的数小于等于26
            __ans += dfs(__i + 2);  // 递归调用dfs函数处理接下来的两个字符,并将返回值加到__ans

        return __ans;  // 返回从当前位置开始的解码方法总数
    }
    void solveinit() { __n = __s.size(); }  // 定义一个名为solveinit的函数,用于初始化__n为字符串__s的长度

    int numDecodings(string s) {  // 定义一个名为numDecodings的函数,接受一个字符串s,并返回可能的解码总数
        __s = s;  // 将传入的字符串赋值给成员变量__s
        solveinit();  // 调用solveinit函数进行初始化
        return dfs(0);  // 从字符串的第一个字符开始调用dfs函数,并返回解码的总数
    }
};

记忆化递归

 
class Solution {  // 定义一个名为Solution的类
public:
    string __s;  // 定义一个字符串__s,用于存储输入的编码消息
    int __n;  // 定义一个整数__n,用于存储输入字符串的长度
    vector<int> __memory;  // 定义一个向量__memory,用于记忆化递归中存储中间结果,避免重复计算

    int dfs(int __i) {  // 定义一个递归函数dfs,用于从第__i个字符开始计算解码方法的总数
        if (__i == __n)  // 如果__i达到字符串的末尾
            return 1;  // 则表示找到了一种完整的解码方式,返回1

        if (__s[__i] == '0')  // 如果当前字符是'0'
            return 0;  // 则当前路径无法解码(因为'0'不能单独解码),返回0

        if (__memory[__i] != -1)  // 如果当前位置的解码方法数已经被计算过
            return __memory[__i];  // 直接返回存储的结果,避免重复计算

        int __ans = 0;  // 初始化当前位置的解码方法总数为0
        __ans += dfs(__i + 1);  // 尝试解码当前一个字符,然后递归计算剩余字符串的解码方法数,并累加到__ans

        if (__i + 1 < __n &&  // 如果当前位置后还有至少一个字符,并且
            ((__s[__i] - '0') * 10 + (__s[__i + 1] - '0')) <= 26)  // 如果当前字符和下一个字符组成的两位数小于等于26
            __ans += dfs(__i + 2);  // 尝试解码当前两个字符,然后递归计算剩余字符串的解码方法数,并累加到__ans

        __memory[__i] = __ans;  // 将计算结果存储在__memory中,用于记忆化
        return __ans;  // 返回从当前位置开始的解码方法总数
    }

    void solveinit() {  // 定义一个初始化函数solveinit
        __n = __s.size();  // 初始化__n为字符串__s的长度
        __memory.clear();  // 清空__memory向量
        __memory.resize(__n + 1, -1);  // 重新调整__memory大小,并初始化所有元素为-1
    }

    int numDecodings(string s) {  // 定义一个函数numDecodings,接收一个字符串s并返回解码方法的总数
        __s = s;  // 将传入的字符串赋值给成员变量__s
        solveinit();  // 调用solveinit函数进行初始化
        return dfs(0);  // 从字符串的第一个字符开始调用dfs函数,并返回解码的总数
    }
};

动态规划

 
class Solution {  // 定义一个名为Solution的类
public:
        string __s;  // 定义一个字符串变量__s,用于存储输入的编码字符串
        int __n;  // 定义一个整数变量__n,用于存储字符串的长度
        vector<int> __memory;  // 定义一个整数向量__memory,用于存储记忆化递归的中间结果
        vector<int> __dp;  // 定义一个整数向量__dp,用于存储动态规划的中间结果

        int dfs(int __i) {  // 定义一个名为dfs的递归函数,用于计算从索引__i开始的解码方法总数
                if (__i == __n)  // 如果索引__i等于字符串长度__n,表示已经达到字符串末尾
                        return 1;  // 返回1,表示找到了一种解码方法

                if (__s[__i] == '0')  // 如果当前位置的字符是'0'
                        return 0;  // 返回0,因为'0'不能解码成任何字符

                if (__memory[__i] != -1)  // 如果当前位置的解码方法已经被计算过
                        return __memory[__i];  // 直接返回记忆化的结果,避免重复计算

                int __ans = 0;  // 初始化解码方法数为0
                __ans += dfs(__i + 1);  // 递归调用dfs函数计算单个字符的解码方法,并累加到__ans

                if (__i + 1 < __n &&  // 如果当前位置后面还有至少一个字符,并且
                        ((__s[__i] - '0') * 10 + (__s[__i + 1] - '0')) <= 26)  // 当前字符与下一字符组成的数字小于等于26
                        __ans += dfs(__i + 2);  // 递归调用dfs函数计算两个字符的解码方法,并累加到__ans

                __memory[__i] = __ans;  // 将计算的结果存储在__memory中,用于记忆化
                return __ans;  // 返回从当前位置开始的解码方法总数
        }

        void solveinit() {  // 定义一个初始化函数solveinit
                __n = __s.size();  // 初始化__n为字符串__s的长度
                __memory.clear();  // 清空__memory向量
                __memory.resize(__n + 1, -1);  // 重新设置__memory大小,并初始化为-1
                __dp.clear();  // 清空__dp向量
                __dp.resize(__n + 1, -1);  // 重新设置__dp大小,并初始化为-1
                __dp[__n] = 1;  // 设置动态规划基准情况:字符串末尾之后的解码方法数为1
        }

        int numDecodings(string s) {  // 定义一个名为numDecodings的函数,用于计算字符串s的解码方法总数
                __s = s;  // 将输入的字符串s赋值给成员变量__s
                solveinit();  // 调用solveinit函数进行初始化
                for (int __i = __n - 1; __i >= 0; __i--) {  // 从字符串的最后一个字符向前遍历
                        int __ans = 0;  // 初始化当前位置的解码方法数为0
                        if (__s[__i] == '0') {  // 如果当前字符是'0'
                                __dp[__i] = 0;  // 直接设置当前位置的解码方法数为0,因为'0'不能解码
                                continue;  // 跳过当前循环
                        }
                        __ans += __dp[__i + 1];  // 累加单个字符的解码方法数到__ans

                        if (__i + 1 < __n && ((__s[__i] - '0') * 10 + (__s[__i + 1] - '0')) <= 26) {
                                __ans += __dp[__i + 2];  // 累加从当前位置开始的两个字符形成的数字后的解码方法数到__ans
                        }

                        __dp[__i] = __ans;  // 将计算得到的总解码方法数存储在__dp数组的当前索引位置
                }

                return __dp[0];  // 返回从整个字符串的开始位置解码的方法总数,即动态规划数组的第一个元素的值
        }

};

总结

1.

暴力递归改写记忆化递归和动态规划过程十分简单,记忆化递归可以说是动态规划的自顶向下版本,正常动态规划可以理解为自底向上版本.

2.

但不是所有的递归都可以改写为记忆化搜索和动态规划.定义的递归具有重复子问题,递归函数对应某一个位置dp值.

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

妖精七七_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值