在问 · 算法题解

91. 解码方法

题目描述

字母 A 到 Z 依次编码为数字 1 到 26。一条大写字母消息编码后,就得到一个数字串。

输入非空数字串 s。解码时把 s 切成若干段,每段必须是 1 到 26 之间的数,且不能带前导零,比如 "06" 不是合法的一段。例如 "11106" 可切成 (1,1,10,6) 或 (11,10,6)。

返回把整个 s 切成合法各段的方法数。没有任何合法切法时返回 0。保证答案在 32 位整数范围内。

示例 1
输入:s = "12"
输出:2

解释:可以是 1 2(AB)或 12(L)。

示例 2
输入:s = "226"
输出:3

解释:可以是 2 26、22 6、2 2 6。

示例 3
输入:s = "06"
输出:0

解释:开头的 0 无法单独成段,06 又有前导零,所以无法解码。

数据范围

  • 1 <= s.length <= 100
  • s 只含数字,开头可能是 0。

解题思路

设 dp[i] 为前 i 个字符的解码方法数,dp[0] = 1 表示空前缀有一种解法。看最后一段:如果 s[i-1] 不是 0,它可以单独成一段,加上 dp[i-1];如果最后两位 s[i-2..i-1] 在 10–26 之间,它们可以合成一段,加上 dp[i-2]。

为什么正确

dp[i] 只依赖 dp[i-1] 和 dp[i-2],从左到右依次计算。

复杂度分析

时间 O(n),空间 O(n)(可以压缩到 O(1))。

易错点

0 不能单独解码,只能作为 10 或 20 的一部分;两位数以 0 开头(如 '06')也不合法。用字符串比较 '10' <= x <= '26' 可以自动排除前导 0。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def numDecodings(self, s: str) -> int:
        n = len(s)
        dp = [0] * (n + 1)
        dp[0] = 1
        for i in range(1, n + 1):
            if s[i - 1] != '0':
                dp[i] += dp[i - 1]
            if i >= 2 and '10' <= s[i - 2:i] <= '26':
                dp[i] += dp[i - 2]
        return dp[n]

载入编辑器,自己跑一遍 →

动态规划 专题的其他题目

查看 动态规划 全部题目 →