Leetcode - Decode Ways

My code:

public class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0)
            return 0;
        if (s.charAt(0) < '1' || s.charAt(0) > '9')
            return 0;
        else if (s.length() == 1)
            return 1;
        int[] dp = new int[s.length() + 1];
        if (s.charAt(0) >= '1' && s.charAt(0) <= '9')
            dp[1] = 1;
        else
            dp[1] = 0;
        dp[0] = 1;
        for (int i = 2; i < dp.length; i++) {
            if (s.charAt(i - 1) < '0' || s.charAt(i - 1) > '9')
                return 0;
            int v = Integer.parseInt(s.substring(i - 2, i));
            
            if (v > 9 && v <= 26)
                dp[i] += dp[i - 2];
            if (s.charAt(i - 1) > '0' && s.charAt(i - 1) <= '9')
                dp[i] += dp[i - 1];
            else if (s.charAt(i - 1) == '0' && dp[i] == 0)
                return 0;
        }
        return dp[dp.length - 1];
    }
    public static void main(String[] args) {
        Solution test = new Solution();
        System.out.println(test.numDecodings("10"));
    }
}

My test result:

Paste_Image.png

这道DP花了我接近两个小时,看了别人的代码,理解了好久才搞懂。
其实,DP的话,思路一定要清晰。比如这道题目。
求这个东西。
那么我设一个数组, dp[s.length()+1]
dp[i] 表示从s[0] - s[i - 1] 这一段区域,有多少种构造方法。
那么,有多少种呢?只有两种可能。

  1. (s[i - 2], s[i - 1])
  2. (s[i - 2]), (s[i - 1])
    那么就直接点,考虑第一种因素。
    即前面两位在 1-26之间就行了。
    于是,dp[i] += dp[i - 2], 先把第一种情况加上去
    这个很容易计算。
    此时,不需要去考虑什么0不0的。
    然后考虑第二种情况。
    那么,因为DP,我可以保证s[i - 2] 是符合的。
    于是只用判断s[i - 1]是否符合 1-9.
    如果是, dp[i] += dp[i - 1]
    然后还需要考虑一种情况, 如果 s[i - 1] == '0' 呢?
    按道理,是无法进行下去了,应该直接返回0.
    但是如果s[i - 2] 在 1-2范围内,就可以构成,10, 20,于是可以继续进行下去。
    那么该怎么区分这种情况呢?难道还要再去判断下s[i - 2]?
    不用了,如果s[i - 2] 在 1-2 范围内,就满足了第一种情况,那么dp[i] 就已经被赋值了,已经大于0了。
    所以最后只用判断下dp[i]是否为0,是否被赋值过了,如果没有。代表s[i - 2]不在1-2范围内。那么这里就无法再继续decode,得直接返回0.

一开始这道题目我是拿递归做的,思路和permutation那个类型差不多,但是超时了。的确其中有许多重复的地方。

DP还是难啊。
贴一个博客。
http://bangbingsyb.blogspot.com/2014/11/leetcode-decode-ways.html

DP,思路一定要清晰,最好能像这里一样清楚地写下来。

**
总结: String, DP
**

Good luck, Richardo!

My code:

public class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        int n = s.length();
        int[] dp = new int[n];
        dp[0] = (isDigit(s.charAt(0)) ? 1 : 0);
        for (int i = 1; i < n; i++) {
            int sum = 0;
            char curr = s.charAt(i);
            if (isDigit(curr)) {
                if (i - 1 >= 0) {
                    sum += dp[i - 1];
                }
                else {
                    sum += 1;
                }
            }
            String sub = s.substring(i - 1, i + 1);
            if (isValid(sub)) {
                if (i - 2 >= 0) {
                    sum += dp[i - 2];
                }
                else {
                    sum += 1;
                }
            }
            dp[i] = sum;
        }
        
        return dp[n - 1];
    }
    
    private boolean isValid(String s) {
        char c1 = s.charAt(0);
        char c2 = s.charAt(1);
        if (c1 == '1' && (c2 >= '0' && c2 <= '9')) {
            return true;
        }
        else if (c1 == '2' && (c2 >= '0' && c2 <= '6')) {
            return true;
        }
        else {
            return false;
        }
    }
   
    private boolean isDigit(char curr) {
        if (curr >= '1' && curr <= '9') {
            return true;
        }
        else {
            return false;
        }
    }
}

这道题目我的思路还是很清晰的。
一开始我做的方向不对。
我又想到了用 divide and conquer, burst ballon + cache
这是一定可以work的。但存在一个问题,很难解决,或者需要很多的琐碎代码去解决。
如果输入是 '111'
那么,我的算法,会重复计算很多东西。而且很难察觉。只能通过hashset 来去重。这样的话,开销会变大。

于是我转而用 iteration DP.

dp[i] 表示, [0, i] number of decode ways
那么,
如果 s.charAt(i) 本身就是digit,dp[i] += dp[i - 1]
如果 s.substring(i - 1, i + 1) 是 "11 - 26"中的一员,那么
dp[i] += dp[i - 2]

然后加上一些corner case, 就可以完成这个问题了。
思路很直接。

Anyway, Good luck, Richardo! -- 08/26/2016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容