91. Decode Ways

DFS + memo

T: O(2^n) => O(n)

S: O(n)

class Solution {
    
    public int numDecodings(String s) {

        return dfs(0, s, new Integer[s.length()+1]);
    }
    private int dfs(int i, String s, Integer[] memo) {
        // we are counting how many ways there are to decode the entire string. 
        // We only increase the count by 1 when the entire string is decoded (i.e. reached the end)
        if (i == s.length()) {  //base case => ๆˆ็ซ‹ๅฐฑ 1 way
            return 1;
        }
        if (s.charAt(i) == '0') {
            return 0;
        }
        if (memo[i] != null) {
            return memo[i];
        }
        // ้€™้กŒๅฐฑๆ˜ฏๆœ‰ๅ…ฉๅ€‹ๅˆ†ๆ”ฏ, ไธ€ไฝ or 2ไฝ, ไฝ†่ฆ็ฌฆๅˆ่ฆๅ‰‡
        int way1 = dfs(i+1, s, memo); // ้ธๅคšไธ€ไฝ็š„ๅˆ†ๆ”ฏ
        int way2 = 0;
        // 2 digits, ไธ่ถŠ็•Œ, ้ธๅคš2ไฝ็š„ๅˆ†ๆ”ฏ
        if (i < s.length() -1 && Integer.parseInt(s.substring(i, i+2)) <= 26) {
            way2 = dfs(i+2, s, memo);
        }
        memo[i] = way1 + way2;
        return memo[i];
    }
}

/*
  12
  / \
1   12 
/
2

brute force
O(2^n)


06
/
x

   121 
   /\
 1   12 \
 /\      1  => so when to the end, there 1 way 
2  21 => but if over 26, it's x
/     => so when to the end, there 1 way 
1 => so when to the end, there 1 way

 can't start with 0

first digit
1-9

first digit 1 , secodn 0~9
            2 , second 0~6
            
so subproblem, because most to 26 , ๆ˜ฏๅ…ฉไฝๆ•ธๆ‰€ไปฅไธๆ˜ฏ็”จไธ€ไฝ, ๅฐฑๆ˜ฏๅ…ฉไฝ

[1] 21 =>  dp[i+1]
or 
[12] 1 =>. dp[i+2]
dp[i] = dp[i+1] + dp[i+2]

i+1 ไฝ็š„ ways + i+2 ไฝ็š„ ways





*/

DP

top down

O(n)

O(n)

class Solution {
    
    public int numDecodings(String s) {
        int n = s.length();
        int[] dp = new int[n+1];
        
        dp[n] = 1;
        
        // ๅทฒ็ถ“ๆœ‰ n ๆ‰€ไปฅๅพž n-1 ้–‹ๅง‹ๅš
        for (int i = n-1; i >= 0; i--) {
            if (s.charAt(i) != '0') {
                dp[i] = dp[i+1];            
                if (i < n -1 && Integer.parseInt(s.substring(i, i+2)) <= 26) {
                    dp[i] += dp[i+2];
                }
            }
        }
        return dp[0];
    }
}

buttom up DP

class Solution {
  public int numDecodings(String s) {
    int n = s.length();
    int dp[] = new int[n+1];
    
    //Make it the same as 1 char condition maybe makes more sense? 
    dp[0] = s.charAt(0) == '0' ? 0 : 1;
    //dp[0] = 1; // empty string (why...??)
    dp[1] = s.charAt(0) == '0' ? 0 : 1; // one char
    
    // ๆ‰€ไปฅ็‹€ๆ…‹ไธๆ˜ฏๅพž 2ไฝ ไพ†ๅฐฑๆ˜ฏๅพž 1ไฝไพ†, ็„ถๅพŒ่ฆ่€ƒๆ…ฎไธ€ไบ›้™ๅˆถ
    for(int i = 2; i <= n; i++) {
      int twoDigit = Integer.parseInt(s.substring(i-2, i));
      if(twoDigit >= 10 && twoDigit <= 26) {
        dp[i] += dp[i-2];
      }
      
     int oneDigit = Integer.parseInt(s.substring(i-1, i));

      if(oneDigit >= 1 && oneDigit <= 9) {
        dp[i] += dp[i-1];
      }
    }
    
    return dp[n];
  }
}

dp => buttom up, so dp[i] = dp[i -xx

dfs+memo => top down, so result = dfs(i+1)....

/*

        12
        /\
       1  12 => count++
      / 
     2 =>  count++
     
     226
     /  \
     2  22
    /\    \
    2 26  6
    /
    6
    
    06
    / \
   0x  06 x
   
   so when 
   one digits => i = [1 or 2] => [i+1 => can be 0~9]
   two digits => i + 1 = [1 or 2] , i+2:  i+1~i+2 <= 26
*/

new comment

```java
class Solution {
    public int numDecodings(String s) {
        Integer[] memo = new Integer[s.length()];
        return dfs(s, 0, memo);
    }
    private int dfs(String s, int index, Integer[] memo) {
        if (s.length() == index) {
            return 1;
        }
        // base case: end with '0' (current char is 0), every time only check 1 char (current index)
        if (s.charAt(index) == '0') { // check current index(first), ex: 10 -> check to current char is 0! return 0
            return 0;
        }
        if (memo[index] != null) {
            return memo[index];
        }
        // check 1 len
        int result = dfs(s, index + 1, memo);
        // has 2 len
        if (index + 1 < s.length() && Integer.parseInt(s.substring(index, index+2)) <= 26) {
            result += dfs(s, index + 2, memo);
        }
        
        return memo[index] = result;
    }
}

/**
T: O(n)
S: O(n)
้—œ้ต: 1ๅ€‹ๅญ—ๆฏๆˆ–2ๅ€‹ๅญ—ๆฏ
case:
i+1
or i+2
how to avoid leading '0'? check ""current char"" is not '0'

226
/\ \
2 2 6
    to the end -> one way!

226
/\ 
2 26 


226
/ \
22 6 

226
/ 
226
x 


     

 */
```

use char

```java
class Solution {
    public int numDecodings(String s) {
        int n = s.length();
        int[] dp = new int[n+1];
        dp[0] = s.charAt(0) == '0' ? 0 : 1;
        dp[1] = s.charAt(0) == '0' ? 0 : 1;

        for (int i = 2; i <= n; i++) {
            if (s.charAt(i-2) != '0' && Integer.parseInt(s.substring(i-2, i)) <= 26) {
                dp[i] += dp[i-2]; 
            }
            if (s.charAt(i-1) != '0') {
                dp[i] += dp[i-1];
            }

        }
        return dp[n];
    }
}
```

Last updated