Sweaty Imposter

Decode Ways

MediumDynamic Programming (1-D & 2-D)Blind 75MidOpen on LeetCodeUpdated

You're given a string s of digits. It encodes a message of uppercase letters where A was written as "1", B as "2", and so on up to Z as "26", with all the codes joined together and no separators. Return the number of ways to split s back into letters. Every piece must be a number from 1 to 26 written without a leading zero, so neither "0" nor "06" is a valid piece. Return 0 if s can't be decoded at all.

Examples

s = "12" returns 2

Split it as 1 2 ("AB") or keep 12 together ("L").

s = "226" returns 3

The three splits are 2 2 6 ("BBF"), 22 6 ("VF") and 2 26 ("BZ").

s = "06" returns 0

The first piece would have to start with 0, and neither "0" nor "06" maps to a letter, so there is no valid decoding.

Constraints

  • 1 <= s.length <= 100
  • s contains only digits and may contain leading zero(s).
  • The answer fits in a 32-bit integer.

Hints

Hint 1

Think about the last letter of any valid decoding. It came from either the last one digit or the last two digits of s.

Hint 2
A pointer toward the approach
Hint 3
The full approach, step by step

Drill This: Your Approach First

Approach

Let ways[i] be the number of decodings of the first i characters, with ways[0] = 1 for the empty prefix. The last piece of a prefix is either one digit, valid when it isn't '0' (add ways[i-1]), or two digits, valid when they form 10 to 26 (add ways[i-2]). Each step reads only the previous two counts, so two rolling variables are enough. O(n) time, O(1) space.

Time

O(n)

Space

O(1)

Pitfall

Mishandling zeros. A "0" can only be the second digit of 10 or 20, so "30" and "100" decode 0 ways, and a two-digit piece like "06" must be rejected even though 6 is in range.

Solutions

class Solution {
    public int numDecodings(String s) {
        int prev2 = 1;                           // ways to decode the first i - 2 chars
        int prev1 = s.charAt(0) == '0' ? 0 : 1;  // ways to decode the first i - 1 chars
        for (int i = 2; i <= s.length(); i++) {
            int cur = 0;
            if (s.charAt(i - 1) != '0') cur += prev1;
            int two = (s.charAt(i - 2) - '0') * 10 + (s.charAt(i - 1) - '0');
            if (two >= 10 && two <= 26) cur += prev2;
            prev2 = prev1;
            prev1 = cur;
        }
        return prev1;
    }
}
Drill This