You have intercepted a secret message encoded as a string of numbers. The message is decoded via the following mapping:
"1" -> 'A'
"2" -> 'B'
...
"25" -> 'Y'
"26" -> 'Z'
However, while decoding the message, you realize that there are many different ways you can decode the message because some codes are contained in other codes ("2" and "5" vs "25").
For example, "11106" can be decoded into:
"AAJF" with the grouping (1, 1, 10, 6)"KJF" with the grouping (11, 10, 6)(1, 11, 06) is invalid because "06" is not a valid code (only "6" is valid).Note: there may be strings that are impossible to decode.
Given a string s containing only digits, return the number of ways to decode it. If the entire string cannot be decoded in any valid way, return 0.
The test cases are generated so that the answer fits in a 32-bit integer.
Example 1:
Input: s = "12"
Output: 2
Explanation:
"12" could be decoded as "AB" (1 2) or "L" (12).
Example 2:
Input: s = "226"
Output: 3
Explanation:
"226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
Example 3:
Input: s = "06"
Output: 0
Explanation:
"06" cannot be mapped to "F" because of the leading zero ("6" is different from "06"). In this case, the string is not a valid encoding, so return 0.
Constraints:
1 <= s.length <= 100s contains only digits and may contain leading zero(s).Problem Overview: You receive a string of digits where 1 -> A, 2 -> B, ..., 26 -> Z. The task is to count how many different ways the string can be decoded into letters. A single digit can represent one letter, while two digits can represent a letter only if the value is between 10 and 26. Handling 0 correctly is the main challenge because it cannot be decoded alone.
Approach 1: Dynamic Programming (O(n) time, O(n) space)
This problem fits classic Dynamic Programming. Each position depends on the number of ways the previous characters could be decoded. Define dp[i] as the number of ways to decode the substring ending at index i. Iterate through the string and evaluate two possibilities at each step.
First, check the single-digit decode. If s[i] is not '0', it can be decoded as a letter, so add dp[i-1]. Second, check the two-digit decode using s[i-1:i+1]. If the value falls between 10 and 26, add dp[i-2]. This builds the solution incrementally while skipping invalid combinations like "06". The base case starts with dp[0] = 1 when the first digit is valid.
This approach clearly models the decision process at every index and is easy to reason about during interviews. Time complexity is O(n) because you scan the string once, and space complexity is O(n) due to the DP array storing results for each position.
Approach 2: Optimized Space Dynamic Programming (O(n) time, O(1) space)
The DP relation only depends on the previous two states: dp[i-1] and dp[i-2]. Instead of storing the entire array, keep two variables representing those values. During iteration, compute the current number of decodings using the same rules as the full DP approach.
Check whether the current digit forms a valid single-digit decode and whether the current and previous digits form a valid two-digit number. Update the running values as you move forward through the string. This rolling-state technique removes the need for the DP array while keeping the exact same recurrence.
The algorithm still runs in O(n) time because every character is processed once, but space drops to O(1). This version is typically preferred in production-quality code or memory-constrained environments since it keeps the logic simple while minimizing memory usage.
Recommended for interviews: Start with the standard Dynamic Programming formulation because it clearly shows the recurrence relation and reasoning about valid decodings. Once the interviewer is comfortable with the logic, mention that only two previous states are needed and optimize it to constant space. Demonstrating both approaches shows strong understanding of dynamic programming transitions and optimization techniques.
The dynamic programming approach leverages the fact that a problem can be broken into subproblems. Here, we use an array dp where dp[i] represents the number of ways to decode the substring s[0..i-1].
We iterate through the string and update the dp array based on the valid single and two-digit mappings.
In this C solution, we use an integer array dp to store the number of ways to decode the string up to each character.
We initialize dp[0] = 1 as there's one way to decode an empty string, and dp[1] = 1 because there's one way to decode a valid single character (assuming it's not '0'). We then loop through the string starting from the second character, calculating the number of ways to decode it based on one-digit and two-digit combinations.
C++
Java
Python
C#
JavaScript
Time Complexity: O(n), where n is the length of the input string. This is because we iterate over each character once.
Space Complexity: O(n), as we use an additional array of size n for storing our results for subproblems.
Instead of using an entire array to store all previous results, this approach keeps track of only the last two computations (since we only ever need the last two values for our dp computations).
Thus, we use two variables to hold these values and update them as needed to keep our space usage minimal.
This C solution reduces space complexity by using two variables - prev1 and prev2 to keep track of decodings without maintaining a full dp array.
These variables capture prior computations needed for the current index advance.
C++
Java
Python
C#
JavaScript
Time Complexity: O(n), since each character in the string is touched once.
Space Complexity: O(1), because only two variables are used to maintain state.
| Approach | Complexity |
|---|---|
| Dynamic Programming Approach | Time Complexity: Space Complexity: |
| Optimized Space Dynamic Programming Approach | Time Complexity: Space Complexity: |
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Dynamic Programming (DP array) | O(n) | O(n) | Best for understanding the recurrence and explaining the logic clearly during interviews |
| Optimized Space Dynamic Programming | O(n) | O(1) | Preferred when memory efficiency matters since only two previous states are required |
Decode Ways - Dynamic Programming - Leetcode 91 - Python • NeetCode • 229,191 views views
Watch 9 more video solutions →Practice Decode Ways with our built-in code editor and test cases.
Practice on FleetCodePractice this problem
Open in Editor