今日心情:你绝对想不到现在我在哪?在机场✈️ ,我到成都啦。现在时间 1 : 52。我可以的。
题目描述:
一条包含字母 A-Z 的消息通过以下映射进行了 编码 :
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"
要 解码 已编码的消息,所有数字必须基于上述映射的方法,反向映射回字母(可能有多种方法)。例如,"11106" 可以映射为:"AAJF" ,将消息分组为 (1 1 10 6) , "KJF" ,将消息分组为 (11 10 6)。注意,消息不能分组为 (1 11 06) ,因为 "06" 不能映射为 "F" ,这是由于 "6" 和 "06" 在映射中并不等价。给你一个只含数字的 非空 字符串 s ,请计算并返回 解码 方法的总数 。题目数据保证答案肯定是一个 32 位 的整数。
解题代码:
class Solution {
public int numDecodings(String s) {
//特殊条件判断
int len = s.length();
//dynamic programming
int dp_1 = 0;
int dp_2 = 1;
int res = 0;
for(int i = 1; i <= len; i++){
// 当前的dp之和之前的dp_1和dp_2有关,所以res在进入新的loop的时候要进行清0
res = 0;
if(s.charAt(i-1) != '0'){
res += dp_2;
}
if(i > 1 && s.charAt(i-2) != '0'){
int comb = (s.charAt(i-2)-'0')*10 + (s.charAt(i-1)-'0');
if(comb <= 26){
res += dp_1;
}
}
//dynamic change
dp_1 = dp_2;
dp_2 = res;
}
return res;
}
}
解题思路:
自己一开始想的时候确实往动态规划思想上面靠了,也想到将前后两个数组组合进行界限判断是否满足decode的条件,但是考虑的边界条件太多了,弄到最后自己也没有实现出来。so 还是看的题解然后进行实现的。
(1)首先确定动态转换的条件最后一个可以解析的个数和之前的可以解析的个数有关:单个数字可以进行解析+两个数字组合(组合的数值小于等于26才可以被解析否则不满足要求)
(2)初始情况dp_1 为 0 : 0个数字可以解析的为0;dp_2 为 1 :1个数字可以解析的只有一种情况,但是当这一个数字为0的时候没有对应的encodor所以能解析的方案为0。
(3)对整个字符串进行遍历:for(int i = 1; i <= len; i++) 从1开始然后到len
(4)创建一个变量res用于记录第 i 个数字所有的编码方案:
- 单个数字编码:s.charAt(i-1) != '0' 判断 i 之前的数只要不为0,就可以构成有效数,此时res变量从0 加上dp_2 当前第i之前的方案;否则无效。
- 两个数字组合编码解析:i > 1 && s.charAt(i-2) != '0' : 首先保证 i > 1,至少有2个数字存在于字符串中,然后保证2个数的组成有效,即第一位数不能为0,否则为无效,不对res变量进行改变。将两个数的组成 int comb = (s.charAt(i-2)-'0')*10 + (s.charAt(i-1)-'0'); 转换为int类型。然后与数字26进行比较,如果小于等于26则组成的2个数编码有效,res 加上 dp_1 构成两个数之前的编码方案; 否则不做res 的更新
(5)对 dp_1 和 dp_2 进行动态转换:
dp_1 = dp_2;
dp_2 = res;
(6)返回 res 。注意 这里返回dp_2 还是 res 都可以
⚠️ 注意:
1. 每次进入一个新loop之前,res 要清零,因为当前 i 的编码方案 只与 最后一个数构成的编码方案 和 最后两个数构成的编码方案 组成,所以 res 相当于一个缓存器,记录当前当前数字满足编码要求的方案。
2. 遍历 loop 的范围从 1 到 字符串的长度s.length(),范围为左闭右闭。因为如果为左闭右开的话,s.charAt(i-1) 只能取到 s.length()-1-1,剩下的s.length()-1 没有进行判断计算。