题目描述
前言
在处理字符串解码问题时,我们通常会遇到需要将数字序列映射到字母的情况。本问题要求计算给定字符串 s
的解码方式的总数,其中字符串仅包含数字,每个数字或数字对可以解码为对应的字母。本文将详细讲解如何通过动态规划来高效解决这一问题。
基本思路
1. 定义
我们定义一个动态规划数组 dp
,其中 dp[i]
表示字符串 s
的前 i
个字符的解码方式数量。
2. 理解问题和递推关系
- 有效的解码方式包括:
- 单个字符(‘1’ 到 ‘9’)可以解码为对应的字母(‘A’ 到 ‘I’)。
- 双字符(‘10’ 到 ‘26’)可以解码为对应的字母(‘J’ 到 ‘Z’)。
- 特殊情况:
- 如果字符串以 ‘0’ 开头,返回 0,因为没有有效的解码。
3. 解决方法
-
初始化:
dp[0] = 1
(空字符串有一种解码方式)。dp[1] = 1
(如果s[0]
有效)。
-
状态转移:
- 对于每个字符
s[i]
(从1
到n-1
):- 如果
s[i]
不为 ‘0’,则可以通过dp[i-1]
解码(即单字符解码)。 - 如果
s[i-1:i+1]
(即两个字符)在10
到26
之间,则可以通过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[i−1]+dp[i−2]if s[i]=′0′if 10≤int(s[i−1: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;
}
};
代码解释总结
在以上代码中,我们通过动态规划实现了解码方式的计算。使用两个状态变量 dp1
和 dp2
进行状态更新,确保时间复杂度为
O
(
n
)
O(n)
O(n) 且空间复杂度为
O
(
1
)
O(1)
O(1)。最终,我们返回 dp2
作为字符串 s
的解码方式数量。
总结
通过本问题的解决,我们掌握了如何使用动态规划来处理字符串解码问题。通过定义状态、构建状态转移方程,并考虑边界条件,我们能有效地计算出结果。这种方法在处理类似问题时将非常有用。