Blind 75Medium

Decode Ways — DP Over Digits

Use dp[i] representing ways to decode the prefix up to i by considering one or two-digit translations.

Dynamic ProgrammingString

Problem Statement

Given a digit string, count how many ways it can be decoded using mapping 1→A, ..., 26→Z.

Why This Problem Matters

  • Teaches string DP with conditional transitions.
  • Common interview favourite requiring careful handling of zeros.
  • Builds intuition for DP on sequences with local dependencies.

Thought Process

Define dp state

dp[i] = ways to decode first i characters. Base case dp[0] = 1, dp[1] depends on leading digit.

Handle one-digit and two-digit options

If s[i-1] != 0 add dp[i-1]; if substring s[i-2..i-1] between 10 and 26 add dp[i-2].

Guard invalid zeros

Standalone zero invalidates decoding; ensure transitions skip them.

Step-by-Step Reasoning

  1. Initialise dp array length n + 1 with dp[0] = 1.
  2. Set dp[1] based on whether first char != 0.
  3. For i from 2..n compute oneDigit = s[i-1], twoDigit = s[i-2..i-1]; accumulate valid transitions.
  4. Return dp[n].

Dry Run

s = "226"

dp builds [1,1,2,3]; decodings "BZ","VF","BBF".

s = "06"

Leading zero invalid, dp[1] = 0; final answer 0.

Complexity Analysis

Time

O(n)

Space

O(1)

Why

Linear scan; can use constant space by keeping two previous values.

Annotated Solution

JAVA
public class DecodeWays {
  public int numDecodings(String s) {
    if (s == null || s.length() == 0 || s.charAt(0) == '0') {
      return 0;
    }

    int prev2 = 1;
    int prev1 = 1;

    for (int i = 1; i < s.length(); i += 1) {
      int current = 0;
      char c = s.charAt(i);
      if (c != '0') {
        current += prev1;
      }
      int twoDigit = (s.charAt(i - 1) - '0') * 10 + (c - '0');
      if (twoDigit >= 10 && twoDigit <= 26) {
        current += prev2;
      }
      if (current == 0) {
        return 0;
      }
      prev2 = prev1;
      prev1 = current;
    }

    return prev1;
  }
}

Rolling variables track dp[i-1] and dp[i-2]; zeros contribute only through valid two-digit combinations.

Common Pitfalls

  • Treating zero as decodable alone; only works with 10 or 20 pairings.
  • Failing to use integers for two-digit substring; string comparisons more error-prone.
  • Accessing s.charAt(i-2) when i < 2 causes index errors.

Follow-Up Questions

  • How would the mapping change if * wildcard digits were allowed? (See Decode Ways II.)
  • Can you output all decodings instead of counting them? (Backtracking with pruning.)

Key Takeaways

String DP often boils down to evaluating small windows of characters.
Explicitly mention how you handle zeros—interviewers listen for it.
Rolling state reduces memory and demonstrates optimisation awareness.