Decode Ways

Leetcode的第91题,也是一个比较经常出现的面试题。题目很考察面试者对动态规划的理解程度。

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -
>
 1
'B' -
>
 2
...
'Z' -
>
 26

Given an encoded message containing digits, determine the total number of ways to decode it.

For example,
Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12).

The number of ways decoding "12" is 2.

看到题目很容易想到,首先我们可以用递归来写, 思路直接参照代码,但是由于递归效率比较低,对于大数据来说会超时。因为如果数据很长的话,递归栈会特别大,而且有很多不必要的重复计算。递归是不推荐的做法,但是为了引出后面的Followup,这里还是放上了最原始的递归的代码。虽然有很多优化能做,但是这里不详细讨论了。

Followup1: 优化递归

我们看到,实际上递归 比如 1234 , 1的时候解码了234,然后34,然后 4,继续走到2,在这里 又重新解码了 34, 4,导致多次重复。所以我们可以用动态规划来存之前解码过的结果,这样就不用反复计算。状态转移方程如下:

f[i] = number of decode ways from 0 to i-1;

f[0] = f[1] = 1 ,

*num= s[i-1]*10+s[i]

f(i) = f(i-2) + f(i-1), 10 <=num<= 26

 = f\(i-1\),             num&lt; 10 ornum&gt;26

这样做的时间复杂度是 O(n), 空间复杂度是 O(n)

Followup 2:能不能用O(1) 的空间来解决问题

我们看到,对于当前位置i,他的数值只和 i-1, i-2的数值有关,所以其实我们根本不需要用一个数组来存。只需要两个数字存之前两位的结果,不断更新他们就好了。所以代码如下。

Followup 3:请给出所有的解

由于需要给出所有的解,动态规划就不适用了,这时候我们只能通过深度优先搜索来找所有的解法。代码和本文最前面使用递归计算多少个解差不多,唯一区别就是现在需要另外开一个空间来记录当前搜索的路径。

Followup 4:如果A 不是对应 1, 我给你一个自定义的Map,可以 A->9, B->10... 或者 A -> 20, B-> 50... 题目保证字母对应的数字 < 100

之前的解法,我们在判断数字是不是有效的时候,都是直接写 '0' < c <= '9' 和 10 <= number <= 26. 其实这一部分逻辑我们可以放到一个 isValid(String str) 的方法里面。

privatebooleanisValid(Stringstr){

if\(str.charAt\(0\) =='0'\) {

    returnfalse;

}

intnum= Integer.valueOf\(str\);

returnnum&gt; 0 &&num&lt;= 26;

}

那么我们把这个方法稍微做一个修改,其实变得更简单了。

privatebooleanisValid(intnum, Map<Integer, Character>map){

returnmap.containsKey\(Integer.valueOf\(num\)\);

}

最后整体代码大致如下(未经大数据测试)

总结

总的来说,Followup4 给出的是一个通用解法。无论怎么变化, 只要掌握动态规划的转移方程,理清楚当前结果和前面结果的关系,这题就变得很容易了。

results matching ""

    No results matching ""