Decode Ways
A message containing letters from A-Z can be encoded into numbers using the following mapping:
‘A’ -> “1”
‘B’ -> “2”
…
‘Z’ -> “26”
To decode the encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example, “11106” can be mapped into:
- “AAJF” with the grouping (1, 1, 10, 6)
- “KJF” with the grouping (11, 10, 6)
Note that the grouping (1, 11, 06) is invalid because “06” cannot be mapped into ‘F’ since “6” is different from “06”.
Given a string s containing only digits, return the number of ways to decode it.
The answer is guaranteed to fit in a 32-bit integer.
Example 1:
Input: s = “12”
Output: 2
Explanation: “12” could be decoded as “AB”(1, 2) or “L”(12).
Example 2:
Input: s = “226”
Output: 3
Explanation: “226” could be decoded as “BZ”(2, 26), “VF”(22, 6), or “BBF”(2, 2, 6).
Example 3:
Input: s = “0”
Output: 0
Explanation: There is no character that is mapped to a number starting with 0.
The only valid mappings with 0 are ‘J’ -> “10” and ‘T’ -> “20”, neither of which start with 0.
Hance, there are no valid ways to decode this since all digits need to be mapped.
Example 4:
Input: s = “06”
Output: 0
Explanation: “06” cannot be mapped to “F” because of the leading zero (“6” is different from “06”).
Constraints:
- 1 <= s.length <= 100
- s contains only digits and may contain leading zero(s).
今天的每日一题是这样的:一个由大写字母组成的字符串可以编码为一个纯数字串,编码规则是这样的:A编码为1,B编码为2,……Z编码为26.但是编码后的串里每个字符之间是没有分隔符的,也就是说26我们可以解码为Z也可以解码为B(2)F(6)。这样的话一个编码串就可能会有多种解码方式。题目要求是给我们输入一个编码串,让我们计算这个串可以用几种不同的方式解码,输出解码方法数。
这道题可以使用动态规划算法来实现。
用f(n)表示s的前n个字符组成的串的解码方法数,设len为s的长度,那么显然,f(len)即是我们所要求的结果。
而考虑下面的情况:
当串的长度为n时,设字符串里的字符分别为i1,i2,… in
此时,我们可能会用到的解码方法有两种:
- 如果i n不为0,那么我们可以认为i n是一个字符,把它解码为一个字母,这种情况下f(n) 就等于f(n-1)
- 如果i n-1 不为0,并且i n-1与i n组成的数字小于等于26,那么就可以认为i n-1,i n组合起来为一个字符,把它们两个解码为一个字母,这种情况下f(n)等于f(n-2)
这两种情况的和即为f(n)的值。
并且,我们可以很容易得到,在字符串没有前导0的情况下,f(1) =1,f(0)=1(因为空串可以解码为空串,也是一种解码方式,所以空串的结果不是0而是1)。
我再举一个例子,深入理解一下这个思想:
如输入串为:“112”
- f(1): 即“1”的解码方法数,显然它只能解码为“A”,结果为1
-
f(2): 此时的编码串为"11",用刚才的两种情况来判断:
-
字符串的最后一位是‘1’ != ‘0’,所以把1解码为A,这种情况下,f(2) = f(1) = 1
-
字符串的最后两位是“11”,满足上述的第二个条件,所以可以把11解码为K,这种情况下,f(2) += f(0) = 1+1 = 2
-
所以f(2) = 2
-
f(3):此时的编码串为“112”
- 最后一位’2’ != ‘0’,所以将2编码为B,而在’2’之前的“11”,就是上面的f(2),所以f(3) += f(2)
- 最后两位“12”,满足条件,可以解码为L,所以将12解码为L,前面的”1“则按照f(1)来计算,那么f(3) += f(1)
综上,f(3) = f(1) + f(2) = 3
所以,“112”的解码方式有3种
长度为4、5或者更长的串也是根据这个思想来计算,思路是一样的,这里就不再赘述,按照这个思想,写出的代码如下:
/**
* @author: LittleWang
* @date: 2021/4/21
* @description:
*/
public class Solution {
public int numDecodings(String s) {
if(s.charAt(0) == '0') { //如果编码串有前导0,那么是一定没有办法解码的,直接返回0
return 0;
}
int len = s.length();
int[] f = new int[len+1]; //用f[n]来存放字符串的前n个字符组成的串可以解码的个数,因为数组下标是从0开始的,为了直观,我们让数组的长度为len+1
f[0] = 1; //当长度为0,即s为空串时,可以解码为一个空串,所以解码方法有1种,不是0.
for (int i = 1; i <= len; i++) {
if(s.charAt(i-1) != '0') {
f[i] += f[i-1];
}
if(i > 1 && 10*(s.charAt(i-2)-'0')+(s.charAt(i-1)-'0') <= 26 && s.charAt(i-2) != '0') {
f[i] += f[i-2];
}
}
return f[len];
}
}
提交结果: