91.力扣解码方式详细讲解

44b07e04800b48a08f142fa0ef3ba196.png

b0edc837c36a4201a569d8b927b5436a.png

力扣(LeetCode)上的第91题“解码方法”要求我们找出一个数字字符串可以被解码成字母的方法数量。这个问题可以使用动态规划(Dynamic Programming,DP)来解决。动态规划是一种将复杂问题分解为更小子问题来解决的方法,通过解决所有相关的子问题,我们可以解决整个问题。

这个问题的关键在于确定状态转移方程。状态转移方程描述了如何从一个状态(或步骤)转移到下一个状态。

对于这个问题,我们可以定义一个DP数组 `dp`,其中 `dp[i]` 表示字符串的前 `i` 个字符有多少种解码方法。我们要做的就是填充这个 `dp` 数组,并最终返回 `dp[n]`,其中 `n` 是输入字符串的长度。让我们来看一个具体的C++代码实现:

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        if (n == 0 || s[0] == '0') return 0; // 如果字符串为空或者以0开头,则无法解码

        vector<int> dp(n + 1, 0);
        dp[0] = 1; // 空字符串有一种解码方式
        dp[1] = 1; // 第一个字符不为'0'时有一种解码方式

        for (int i = 2; i <= n; i++) {
            int oneDigit = s[i - 1] - '0'; // 取单个数字
            int twoDigits = (s[i - 2] - '0') * 10 + oneDigit; // 取两个数字组成的数字

            if (oneDigit >= 1) {
                dp[i] += dp[i - 1]; // 如果当前数字不为0,它可以单独解码
            }
            if (twoDigits >= 10 && twoDigits <= 26) {
                dp[i] += dp[i - 2]; // 如果两个数字组成的数字在10到26之间,它可以和前一个数字一起解码
            }
        }

        return dp[n];
    }
};

总括:这段代码运用循环for不断的遍历,为了方便理解你可以先把n当成2这样你看看这段代码就好理解,s的字符串中i是不断的增加,首先前提条件1判断是否是0,2判断组成两为啥是否小于26大于10这样才能是两位数组合(因为是26个字母变成的数字嘛)这样不断递归增加组合的次数就可以了

可能产生的问题   d[i]=d[i-2]是什么意思?

d[i]=d[i-2]` 表示的是一种特定的解码过程,其中 `d[i]` 代表解码后数据序列中的第 `i` 个元素,而 `d[i-2]` 则是指该序列中第 `i-2` 个元素。这种方法说明当前位置 `i` 的解码值是由同一序列中 `i` 位置之前的第二个元素决定的。

换句话说,这个解码过程是基于一个规则,即每个元素的值是由其前面第二个元素的值直接确定的。这可能是在处理某种特定的数据结构或算法时使用的一种规则,比如在处理差分数据、时间序列预测或某种形式的数据压缩时。

例如,如果你有一个序列:
d[0], d[1], d[2], d[3], d[4], ..., d[i-2], d[i-1], d[i], ...
 

根据 `d[i]=d[i-2]` 这个规则,`d[2]` 的值将会是 `d[0]` 的值,`d[3]` 的值将会是 `d[1]` 的值,依此类推。

这种模式可能是为了解码通过特定方式编码的数据。例如,如果原始数据通过某种算法被转换或压缩,其中每个元素都被替换为与它前面第二个元素的差值,那么在解码时,你可能会使用这种 `d[i]=d[i-2]` 的规则来恢复原始数据

2.核心的状态转移逻辑:

1. 如果当前字符是 `'0'`,那么如果前一个字符是 `'1'` 或 `'2'`,这个 `'0'` 只能和前一个字符一起解码,因此 `dp[i] = dp[i-2]`。如果前一个字符不是 `'1'` 或 `'2'`,则无法解码,返回 0。

2. 如果当前字符和前一个字符组合起来的数字在 10 到 26 的范围内(包括10和26),那么这个数字可以一起解码,也可以分开解码,所以 `dp[i] += dp[i-2]`。

3. 如果当前字符不是 `'0'`,它可以单独解码,所以 `dp[i] += dp[i-1]`。

问题 3.将数字编码成字母的代码的解释:
for (int i = 2; i <= n; i++) {
    int oneDigit = s[i - 1] - '0'; // 取单个数字
    int twoDigits = (s[i - 2] - '0') * 10 + oneDigit; // 取两个数字组成的数字
}

`for (int i = 2; i <= n; i++) { ... }`:这是一个for循环,它从2开始,一直增加到`n`(包括`n`)。这里的`n`应该是字符串`s`的长度。通常在解码问题中,我们从字符串的第二个字符开始处理,因为我们可能需要检查当前字符和前一个字符。

- `int oneDigit = s[i - 1] - '0';`:这行代码取出字符串`s`中位置`i - 1`的字符,然后通过减去字符`'0'`,将其转换为对应的整数值。在ASCII码表中,数字字符`'0'`到`'9'`是连续排列的,所以`'0'`到`'9'`的字符值减去`'0'`的字符值,就会得到0到9的整数值。例如,如果`s[i - 1]`是字符`'3'`,那么`'3' - '0'`的结果就是整数3。

- `int twoDigits = (s[i - 2] - '0') * 10 + oneDigit;`:这行代码先取出字符串`s`中位置`i - 2`的字符,同样将其转换为整数值,然后乘以10。接着,将这个结果与`oneDigit`相加,得到一个两位数的整数值。这个操作相当于组合了`s`中的两个连续字符来形成一个两位数。例如,如果`s[i - 2]`是`'1'`,并且`oneDigit`是3,那么`(s[i - 2] - '0') * 10`的结果是10,加上`oneDigit`的3,总共是13。

这段代码的目的是为了在解码过程中,能够根据字符串中的单个数字或者两个连续数字来进行相应的操作。这个解码可能是基于某个特定的规则,比如在某些编码方案中,数字`1`到`26`可能分别对应英文字母`A`到`Z`。在这种情况下,这段代码就是在检查每一个字符或者字符对,看它们是否可以表示为一个有效的字母。

没了感谢观看!~

7428d874a9b84e838c4018ba371bfd06.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值