zoukankan      html  css  js  c++  java
  • LeetCode第[91]题(Java):Decode Ways(解码方法数)

    题目:解码方法数

    难度:Medium

    题目内容

    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.

    翻译

    一个包含A-Z字母的消息被编码成数字,使用以下映射:

    “A” - > 1

    “B”- > 2

    ……

    “Z”- > 26

    给定一个包含数字的非空字符串,确定解码它的总方法数。

    我的思路:一开始想用递归但是边界问题太多,就放弃了。

          single 从0开始(每个数组单独解码),count从1开始,如果s[i-1]s[i]二者组成的数字在(0,26 ] 范围内,那就count+;

          且遇见0的时候,一开始的单独编码就不存在了,且少了一次组合的机会,例如【110】 中【11】和【0】不能组合

            所以此时 single = 0;count - 1

    我的代码

     1     public int numDecodings(String s) {
     2         if (s.isEmpty() || s.charAt(0) == '0')
     3             return 0;
     4         
     5         int count = 0;
     6         int single = 1;
     7         for (int i = 1; i < s.length(); i++) {
     8             if (s.charAt(i) == '0'){
     9                 count = s.length() > 2 ? count-1 : count;
    10                 single = 0;
    11             }
    12             int x = Integer.parseInt(s.substring(i-1, i+1));
    13             if ( x<= 26 && x > 0) {
    14                 count += 1;
    15             }
    16         }
    17         return (count + single) > 0 ? (count + single) : 0;
    18     }

    结果214 / 258 test cases passed.

    Input:"1212"
    Output:4
    Expected:5

    编码过程中的问题

    1、最初 single 和 count 没有分开计算;

    2、第9行,当只有两个的时候,此时count 不需要 -1 ,例如【10】;

    3、这个思路还是有问题的,例如【1212】中少计算了【12】【12】这个组合

    答案代码

     1 public class Solution {
     2     public int numDecodings(String s) {
     3         int n = s.length();
     4         if (n == 0) return 0;
     5         
     6         int[] memo = new int[n+1];
     7         memo[n]  = 1;
     8         memo[n-1] = s.charAt(n-1) != '0' ? 1 : 0;
     9         
    10         for (int i = n - 2; i >= 0; i--)
    11             if (s.charAt(i) == '0') continue;
    12             else memo[i] = (Integer.parseInt(s.substring(i,i+2))<=26) ? memo[i+1]+memo[i+2] : memo[i+1];
    13         
    14         return memo[0];
    15     }
    16 }

    答案思路

    假设所有的数字都有效,且左右两两相邻数之间也有效(1到26),那么有如下规律

       numDecodings(s) = numDecodings(s.substring(1)) + numDecodings(s.substring(2)) --------------------------------------------------式(1)

    规律显而易见,斐波那契数列。不过是反过来的(从字符串后面往前)

    当然,那只是假设,也要考虑特殊情况:

    使用一个数组(大小为len+1)从后往前记录对应的数字“出现”后解码数的增量

    1、当前指针所指字符为0

      此时此字符无法解码,所以式(1)中的前者就只能为0,后者也为0

      例如【023】,substring(1)——【0】|【23】,截掉的【0】不能解析,所以此组合无效

             substring(2)——【02】|【3】,截掉的【02】不能解析,所以此组合无效

      所以0数字出现后,解码数的增量为0。

    2、当前字符的值是有效的(大于0),但是当前字符与右边字符组合的数字无效(大于26)

      相当于式(1)中的后者=0

      例如【3212】,substring(1)——【3】|【212】,截掉的【3】能解析,所以其值为【212】的解码数

             substring(2)——【32】|【12】,截掉的【32】不能解析,所以此组合无效

    递归实现:

     1     public int numDecodings(String s) {
     2         if (s.isEmpty()) {
     3             return 1;
     4         }
     5         
     6         if (s.charAt(0) == '0') {
     7             return 0;
     8         } 
     9         
    10         if (s.length() == 1)
    11             return 1;
    12             
    13         int sub1 = numDecodings(s.substring(1));
    14         int sub2 = 0;
    15         
    16         if (Integer.parseInt(s.substring(0,2)) <= 26) {
    17             sub2 = numDecodings(s.substring(2));
    18         }
    19         return sub1 + sub2;
    20     }

    此方法会在最后几个用例(很长)运行超时。

    所以答案采用了迭代的方式进行。

    优化:既然是斐波纳数列,那么就能使用双值迭代的方式取代用一个数组进行记录

     1     public int numDecodings(String s) {
     2         if (s.isEmpty() || s.charAt(0) == '0') {
     3             return 0;
     4         }
     5         int sub1 = 1;
     6         int sub2 = 1;
     7         for (int i = s.length() - 2; i > -1; i--) {
     8             if (s.charAt(i+1) == '0') {
     9                 sub1 = 0;
    10             }
    11             if (Integer.parseInt(s.substring(i,i+2)) <= 26) {
    12                 sub1 = sub1 + sub2;
    13                 sub2 = sub1 - sub2;
    14             } else {
    15                 sub2 = sub1;
    16             }
    17         }
    18         return sub1;
    19     }

    第11行其实还可以使用字符进行判断以降低时间和空间复杂度:

       s.charAt(i) == '1' || s.charAt(i) == '2' && s.charAt(i+1) - '0' <= 6 

  • 相关阅读:
    java通过LinkedList实现堆栈和队列数据结构
    华硕笔记本无法调节屏幕亮度
    Java8新特性
    GitLab使用记录
    Java IO流关闭问题之原理简析
    gradle build docker image
    mysql安装及使用
    前端div层级控制
    Could not get dialect instance.
    Starting a Gradle Daemon, 5 busy and 1 incompatible and 1 stopped Daemons could not be reused, use --status for details FAILURE: Build failed with an exception. * What went wrong: Could not dispatch
  • 原文地址:https://www.cnblogs.com/Xieyang-blog/p/9107432.html
Copyright © 2011-2022 走看看