解题思路
这是一道字符串解码题,关键点是:
- 字母到数字的映射规则:'a'->1, 'b'->2, ..., 'z'->26
- 一个数字可能有多种解码方式,比如"12"可以解码为"ab"或"l"
- 需要考虑数字的组合是否有效(必须在1-26范围内)
解题步骤:
- 使用动态规划,
表示前
个数字的解码方式数量
- 对于每个位置
,考虑两种情况:
- 单独解码当前数字
- 将当前数字与前一个数字组合解码
- 注意处理前导零和无效组合的情况
关键点解释
表示前
个数字的解码方式数量
- 状态转移考虑两种情况:
- 单独解码:当前数字不为0时,可以继承
的方案数
- 组合解码:当前数字与前一个数字组合在10-26范围内时,可以继承
的方案数
- 单独解码:当前数字不为0时,可以继承
- 注意处理边界情况:
- 前导零无法解码
- 单个零无法单独解码
- 两位数必须在10-26范围内
代码
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string s;
cin >> s;
int n = s.length();
// dp[i]表示前i个数字的解码方式数量
vector<long long> dp(n + 1, 0);
dp[0] = 1; // 空字符串有1种解码方式
for(int i = 1; i <= n; i++) {
// 当前数字单独解码
if(s[i-1] != '0') {
dp[i] += dp[i-1];
}
// 与前一个数字组合解码
if(i > 1) {
int num = (s[i-2] - '0') * 10 + (s[i-1] - '0');
if(num >= 10 && num <= 26) {
dp[i] += dp[i-2];
}
}
}
cout << dp[n] << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int n = s.length();
// dp[i]表示前i个数字的解码方式数量
long[] dp = new long[n + 1];
dp[0] = 1; // 空字符串有1种解码方式
for(int i = 1; i <= n; i++) {
// 当前数字单独解码
if(s.charAt(i-1) != '0') {
dp[i] += dp[i-1];
}
// 与前一个数字组合解码
if(i > 1) {
int num = (s.charAt(i-2) - '0') * 10 + (s.charAt(i-1) - '0');
if(num >= 10 && num <= 26) {
dp[i] += dp[i-2];
}
}
}
System.out.println(dp[n]);
}
}
s = input()
n = len(s)
# dp[i]表示前i个数字的解码方式数量
dp = [0] * (n + 1)
dp[0] = 1 # 空字符串有1种解码方式
for i in range(1, n + 1):
# 当前数字单独解码
if s[i-1] != '0':
dp[i] += dp[i-1]
# 与前一个数字组合解码
if i > 1:
num = int(s[i-2:i])
if 10 <= num <= 26:
dp[i] += dp[i-2]
print(dp[n])
算法及复杂度
- 算法:动态规划。使用dp数组记录每个位置的解码方式数量。
- 时间复杂度:
,其中
是输入数字串的长度。
- 空间复杂度:
,需要dp数组存储中间结果。