【LeetCode】动态规划—91. 解码方法(附完整Python/C++代码)

题目描述

在这里插入图片描述

前言

在处理字符串解码问题时,我们通常会遇到需要将数字序列映射到字母的情况。本问题要求计算给定字符串 s 的解码方式的总数,其中字符串仅包含数字,每个数字或数字对可以解码为对应的字母。本文将详细讲解如何通过动态规划来高效解决这一问题。

基本思路

1. 定义

我们定义一个动态规划数组 dp,其中 dp[i] 表示字符串 s 的前 i 个字符的解码方式数量。

2. 理解问题和递推关系

  1. 有效的解码方式包括:
    • 单个字符(‘1’ 到 ‘9’)可以解码为对应的字母(‘A’ 到 ‘I’)。
    • 双字符(‘10’ 到 ‘26’)可以解码为对应的字母(‘J’ 到 ‘Z’)。
  2. 特殊情况:
    • 如果字符串以 ‘0’ 开头,返回 0,因为没有有效的解码。

3. 解决方法

  1. 初始化

    • dp[0] = 1(空字符串有一种解码方式)。
    • dp[1] = 1(如果 s[0] 有效)。
  2. 状态转移

    • 对于每个字符 s[i](从 1n-1):
      • 如果 s[i] 不为 ‘0’,则可以通过 dp[i-1] 解码(即单字符解码)。
      • 如果 s[i-1:i+1](即两个字符)在 1026 之间,则可以通过 dp[i-2] 解码(即双字符解码)。
    • 状态转移方程如下:
      d p [ i ] = { d p [ i − 1 ] if  s [ i ] ≠ ′ 0 ′ + d p [ i − 2 ] if  10 ≤ int ( s [ i − 1 : i + 1 ] ) ≤ 26 dp[i] = \begin{cases} dp[i-1] & \text{if } s[i] \neq '0' \\+ dp[i-2] & \text{if } 10 \leq \text{int}(s[i-1:i+1]) \leq 26 \end{cases} dp[i]={dp[i1]+dp[i2]if s[i]=0if 10int(s[i1:i+1])26

4. 进一步优化

  • 由于 dp[i] 只依赖于 dp[i-1]dp[i-2],可以使用两个变量来代替整个数组,进一步降低空间复杂度。

5. 小总结

通过动态规划方法,我们能有效地计算出字符串的解码方式数量。时间复杂度为 O ( n ) O(n) O(n),空间复杂度可优化至 O ( 1 ) O(1) O(1)

以上就是解码方法问题的基本思路。


代码实现

Python 代码

class Solution:
    def numDecodings(self, s: str) -> int:
        if not s or s[0] == '0':
            return 0  # 如果字符串为空或以'0'开头,返回0
        
        dp1, dp2 = 1, 1  # dp1 = dp[i-2], dp2 = dp[i-1]
        
        for i in range(1, len(s)):
            current = 0
            
            # 检查单字符解码
            if s[i] != '0':
                current += dp2
            
            # 检查双字符解码
            two_digit = int(s[i - 1:i + 1])
            if 10 <= two_digit <= 26:
                current += dp1
            
            dp1, dp2 = dp2, current  # 更新状态
        
        return dp2  # 返回最终解码方式数量

C++ 代码

class Solution {
public:
    int numDecodings(string s) {
        if (s.empty() || s[0] == '0') return 0;

        int dp1 = 1, dp2 = 1;  // dp[i-2], dp[i-1]
        
        for (int i = 1; i < s.size(); ++i) {
            int current = 0;

            // 检查单字符解码
            if (s[i] != '0') {
                current += dp2;
            }

            // 检查双字符解码
            int two_digit = stoi(s.substr(i - 1, 2));
            if (two_digit >= 10 && two_digit <= 26) {
                current += dp1;
            }

            dp1 = dp2;  // 更新 dp[i-2]
            dp2 = current;  // 更新 dp[i-1]
        }

        return dp2;
    }
};

代码解释总结

在以上代码中,我们通过动态规划实现了解码方式的计算。使用两个状态变量 dp1dp2 进行状态更新,确保时间复杂度为 O ( n ) O(n) O(n) 且空间复杂度为 O ( 1 ) O(1) O(1)。最终,我们返回 dp2 作为字符串 s 的解码方式数量。

总结

通过本问题的解决,我们掌握了如何使用动态规划来处理字符串解码问题。通过定义状态、构建状态转移方程,并考虑边界条件,我们能有效地计算出结果。这种方法在处理类似问题时将非常有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Albert_Lsk

今天又能喝柠檬茶啦

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

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

打赏作者

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

抵扣说明:

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

余额充值