zoukankan      html  css  js  c++  java
  • (Java) LeetCode 91. Decode Ways —— 解码方法

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

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

    Given a non-empty string containing only digits, determine the total number of ways to decode it.

    Example 1:

    Input: "12"
    Output: 2
    Explanation: It could be decoded as "AB" (1 2) or "L" (12).  

    Example 2:

    Input: "226"
    Output: 3
    Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

    这个题想了好久,觉得真的是比较难想,好多case一遍一遍测试才通过。试着总结一下思路吧。

    首先,假如我们分析到了中间,比较通用的情况。

    现在在已有字符串的基础上,新来一位字符,就要开始分情况。如果来的是'0',就只有唯一的组成情况,就是和前面的一个数字组成编码,且前面的这个数字还必须是'1'或'2',否则就是无效的编码。所以如果来的是'0',相当于要么和前面的数字组合,要么就无效。如果用动态规划的思想,那就先写上伪代码:

    if (s[i] == '0') { 
        if (s[i-1] == '1' || '2') 
            dp[i] = dp[i-2]; 
        else 
            return 0;
    }     

    这里为什么是dp[i] = dp[i-2]呢?因为'0'只能作为和前面的一位字符组合存在,所以前面的字符出现的时候相当于并没有出现,因为它要等着后面的'0'来和它组合,所以编码种类和dp[i-2]一样多。

    接下来看如果来的是'1'~'9',不仅自己要再细分情况,也要再考虑前面一位的情况。如果前面一位是'1',或前一位是'2'且这一位是'1'~'6',那么可以产生新的编码,因为它既可以独立存在成一个字母,又可以和前面的数字组合形成一个字母。作为独立存在的情况相当于就是取dp[i-1],因为添加一位独立存在的字符并没有增加任何可能性,所以保持和前状态一样;作为组合存在的情况同上,还要再往前想一位。因为如果组合存在的话,前面的一位其实也是和后面的一位作为组合存在而不是独立存在,即当dp[i-1]那位字符来的时候,装作它没来,因为它要等着和后面的字符结合,所以编码种类和dp[i-2]是一样多的。所以最后dp[i] = dp[i-1] + dp[i-2]。

    如果前面一位字符不是'1'或者'2',那么新来的字符位只能作为独立存在,无法结合。所以并没有产生新的编码可能,即dp[i] = dp[i-1]。

    总结起来伪代码如下:

    if (s[i-1] == '1' || (s[i-1] == '2' && '1' <= s[i] <= '6')) 
      dp[i] = dp[i-1] + dp[i-2];
    else
      dp[i] = dp[i-1];

    这样所有的情况就分析完了。现在看为了解决通用情况需要些什么,很明显从上面来看,需要知道每一位字符前两位,即dp[0]和dp[1]要首先知道。dp[0]很简单,如果不是'0'那就是1,是'0'就直接返回0了,第一位是'0'无法解码。dp[1]也并不复杂,其实和通用情况一样,如果第二位是'0',dp[1]就是1或return 0,取决于能否和前面结合,即第一位是否是'1'或'2';如果第一位是'1',或第一位是'2'且第二位是'1'~'6',那dp[1]就是2,因为可以结合或独立存在。其他情况就都是1了,因为只能独立存在,不增加解码可能性。

    写完了思路发现这道题就写完了,把思路实现即为代码。应该是有很多可以优化的地方,或者是思绪上,或者是代码上,留作以后复习的时候优化吧。现在这么写思路特别清楚,很容易理解,姑且先这样吧!


    Java

    class Solution {
        public int numDecodings(String s) {
            if (s == "") return 0;
            char[] digit = s.toCharArray();
            int[] dp = new int[digit.length];
            //get dp[0]
            dp[0] = digit[0] == '0' ? 0 : 1;
            if (dp[0] == 0 || digit.length == 1) return dp[0];
            //get dp[1]
            dp[1] = 1;
            if (digit[1] == '0') {
                if (digit[0] >= '3')
                    return 0;
            }
            else if (digit[0] == '1' || (digit[0] == '2' && '1' <= digit[1] && digit[1] <= '6'))
                    dp[1] = 2;
            //get dp[i]
            for (int i = 2; i < digit.length; i++) {
                if (digit[i] == '0') {
                    if (digit[i-1] == '1' || digit[i-1] == '2')
                        dp[i] = dp[i-2];
                    else return 0;
                }
                else if (digit[i-1] == '1' || (digit[i-1] == '2' && '1' <= digit[i] && digit[i] <= '6')) 
                    dp[i] = dp[i-1] + dp[i-2];
                else dp[i] = dp[i-1];
            }
            return dp[digit.length-1];
        }
    }
  • 相关阅读:
    10.2 处理大集合
    观察者模式——出版者与订阅者
    phonegap(cordova) 自己定义插件代码篇(五)----android ,iOS 集成微信登陆
    另一鲜为人知的单例写法-ThreadLocal
    Spring MVC中Controller如何将数据返回给页面
    IntelliJ IDEA安装主题详细步骤
    oracle导出dmp文件的2种方法
    Oracle导出表(即DMP文件)的两种方法
    Spring MVC 实现文件的上传和下载
    压力测试 JMeter3.3
  • 原文地址:https://www.cnblogs.com/tengdai/p/9245714.html
Copyright © 2011-2022 走看看