[LeetCode] 91. 解码方法
题目链接 : https://leetcode-cn.com/problems/decode-ways/
题目描述:
一条包含字母 A-Z 的消息通过以下方式进行了编码:
'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。
示例:
示例 1:
输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。
示例2:
输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6)
思路:
动态规划
dp[i]
到字符串第i
位置最多解码的个数
动态方程: dp[i] = dp[i-1] + dp[i - 2]
注意:这里有很多要考虑的情况
例如:101
,100
,所以要考虑有0
的情况,直接看代码,注释写在里面了!
再附上自顶向下的动态规划, 大家可以提供 Java
版本吗?
代码:
自底向上
class Solution:
def numDecodings(self, s: str) -> int:
dp = [0] * len(s)
# 考虑第一个字母
if s[0] == "0":
return 0
else:
dp[0] = 1
if len(s) == 1: return dp[-1]
# 考虑第二个字母
if s[1] != "0":
dp[1] += 1
if 10 <= int(s[:2]) <= 26:
dp[1] += 1
for i in range(2, len(s)):
# 当出现连续两个0
if s[i - 1] + s[i] == "00": return 0
# 考虑单个字母
if s[i] != "0":
dp[i] += dp[i - 1]
# 考虑两个字母
if 10 <= int(s[i - 1] + s[i]) <= 26:
dp[i] += dp[i - 2]
return dp[-1]
java
class Solution {
public int numDecodings(String s) {
int[] dp = new int[s.length()];
// 考虑第一个字母
if (s.charAt(0) == '0') return 0;
else dp[0] = 1;
if (s.length() == 1) return dp[dp.length - 1];
// 考虑第二字母
if (s.charAt(1) != '0') dp[1] += 1;
if (10 <= Integer.parseInt(s.substring(0, 2)) && Integer.parseInt(s.substring(0, 2)) <= 26) dp[1] += 1;
for (int i = 2; i < s.length(); i++) {
if (s.charAt(i - 1) == '0' && s.charAt(i) == '0') return 0;
if (s.charAt(i) != '0') dp[i] += dp[i - 1];
if (10 <= Integer.parseInt(s.substring(i - 1, i + 1)) && Integer.parseInt(s.substring(i - 1, i + 1)) <= 26)
dp[i] += dp[i - 2];
}
return dp[dp.length - 1];
}
}
自顶向下
import functools
class Solution:
@functools.lru_cache(None)
def numDecodings(self, s: str) -> int:
if not s:
return 1
ans = 0
if len(s) >= 1 and s[0] != '0':
ans += self.numDecodings(s[1:])
if len(s) >= 2 and s[0] != '0' and int(s[:2]) <= 26:
ans += self.numDecodings(s[2:])
return ans