题目
一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
'A' -> 1 'B' -> 2 ... 'Z' -> 26 要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"111" 可以将 "1" 中的每个 "1" 映射为 "A" ,从而得到 "AAA" ,或者可以将 "11" 和 "1"(分别为 "K" 和 "A" )映射为 "KA" 。注意,"06" 不能映射为 "F" ,因为 "6" 和 "06" 不同。
给你一个只含数字的 非空 字符串 num ,请计算并返回 解码 方法的 总数 。
题目数据保证答案肯定是一个 32 位 的整数。 输入:s = "226" 输出:3 解释:它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。 示例 3:
输入:s = "0" 输出:0 解释:没有字符映射到以 0 开头的数字。含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。由于没有字符,因此没有有效的方法对此进行解码,因为所有数字都需要映射。
动态规划
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.numDecodings("2611055971756562");
}
public int numDecodings(String s) {
if (s.startsWith("0")) {
return 0;
}
char [] codeCharArray = s.toCharArray();
int [] dpTable = new int[s.length()];
dpTable[0] = 1;
int pre_data = Integer.valueOf(String.valueOf(codeCharArray[0]));
for (int i = 1; i < codeCharArray.length; i ++) {
int data = Integer.valueOf(String.valueOf(codeCharArray[i]));
if (data == 0) {
if (pre_data <= 2 && pre_data != 0) {
// 能结合
dpTable[i] = i - 2 >= 0 ? dpTable[i - 2] : dpTable[i - 1];
} else {
return 0;
}
} else {
if (pre_data == 0) {
// 不能结合
dpTable[i] = dpTable[i - 1];
} else {
if (pre_data > 2 || (pre_data == 2 && data >=7 )) {
// 不能结合
dpTable[i] = dpTable[i - 1];
} else {
// 能结合
dpTable[i] = i - 2 >= 0 ? dpTable[i - 1] + dpTable[i - 2] : dpTable[i - 1] + 1;
}
}
}
pre_data = data;
}
return dpTable[s.length() - 1];
}
}
基本思路
- 题目可以得到最优子结构, 每次添加一个数字对于整体的解码可能的影响, 只和当前数字和前一个数字有关.
因此可以得到4中情况, 前一个数字为0, 当前数字为0或者不为0, 前一个数字不为0时, 当前数字为0或者不为0, 这四种情况中, 还需要细分出当前数字能否和前一个数字结合的问题, 即是否在(1-26之间).
-
能结合 就说明将后两位看成一个整体, 那么可能的数目就是和dp[i - 2]一直, 假设i - 2的时候可能数组为[2, 2], [22], 那如果新增一个26, 那么不就是[2, 2, 26], [22, 26]
-
不能结合的时候 新加的一位数目等于dp[i - 1], 假设假设i - 1的时候可能数组为[2, 2], [22], 新增一个0, 那么可能的数组就是[2, 2, 0], [22, 0]
-
利用dp table记录数字从1位到2位, 3位.....的可能的解码数量
-
状态转移方程与情况相关, 需要根据每一种情况, 思考列出