Decode Ways [Medium]

28 Aug 2026, Updated: 24 Sep 2026 4 min read
1
The Decode Ways problem requires finding the number of ways a numeric string can be decoded into letters.

Problem

You are given a string s containing digits. Each digit sequence can be decoded using the following mapping:
1 → A 
2 → B 
.
.
. 
26 → Z
Return the number of possible ways to decode the entire string. A digit 0 cannot be decoded by itself. It can only appear as part of 10 or 20.

Example(s)

Consider the following example(s) to understand the expected input and output.

Input

s = "226"

Output

3
The string can be decoded in three ways:
2  2  6  →  B  B  F
22  6  →  V  F
2  26  →  B  Z

Memoization Approach

To decode the string, we start at an index and decide how many digits to use. At each position, we can try to decode one digit or two digits.

If the current digit is between 1 and 9, it can be decoded as one character, and we then move to the next index.

If the current digit together with the next digit forms a number between 10 and 26, the two digits can also be decoded as one character, and we then move two positions forward.

If we reach the end of the string, one complete decoding has been found. If the current character is '0', it cannot be decoded by itself.

The same index can be reached through different decoding choices, so we store the result for each index using memoization.
class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0)
            return 0;

        Integer[] memo = new Integer[s.length()];
        return numDecodingsHelper(s, 0, memo);
    }

    private int numDecodingsHelper(String s, int i, Integer[] memo) {
        // Reached the end, found one valid decoding
        if (i == s.length())
            return 1;

        // A valid code cannot start with '0'
        if (s.charAt(i) == '0')
            return 0;

        // Return the cached result
        if (memo[i] != null)
            return memo[i];

        // Decode the current digit
        int ways = numDecodingsHelper(s, i + 1, memo);

        // Check if the next two digits form a valid code from 10 to 26
        if (i + 1 < s.length()) {
            int ten = s.charAt(i) - '0';
            int one = s.charAt(i + 1) - '0';
            int value = ten * 10 + one;

            if (value >= 10 && value <= 26)
                ways += numDecodingsHelper(s, i + 2, memo);
        }
        return memo[i] = ways;
    }
}

Complexity

There are n possible indices, and each index is calculated only once, resulting in O(n) time complexity. The memoization array requires O(n) space.

Tabulation Approach

We can also solve the problem using bottom-up Dynamic Programming.

Let dp[i] represent the number of ways to decode the substring starting at index i. If we reach the end of the string, one valid decoding has been completed.

We then process the string from right to left. If the current digit is not '0', it can be decoded by itself.

If the current digit and the next digit together form a number between 10 and 26, we can also decode both digits together.
class Solution {

    public int numDecodings(String s) {
        int n = s.length();
        int[] dp = new int[n + 1];

        // One way to decode an empty suffix.
        dp[n] = 1;

        for (int i = n - 1; i >= 0; i--) {

            // A zero cannot be decoded by itself.
            if (s.charAt(i) == '0') {
                dp[i] = 0;
                continue;
            }

            // Decode one digit.
            dp[i] = dp[i + 1];

            // Decode two digits.
            if (i + 1 < n) {
                int number = (s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0');

                if (number >= 10 && number <= 26) {
                    dp[i] += dp[i + 2];
                }
            }
        }
        return dp[0];
    }
}

Complexity

Each position is processed once, resulting in O(n) time complexity, while the DP array requires O(n) space.

Space Optimized Approach

In the tabulation approach, dp[i] only depends on dp[i + 1] and dp[i + 2].

Therefore, instead of storing the entire DP array, we only need to keep track of the previous two values.
class Solution {

    public int numDecodings(String s) {
        int n = s.length();
        int next = 1;
        int nextNext = 0;

        for (int i = n - 1; i >= 0; i--) {
            int current = 0;

            // Decode one digit.
            if (s.charAt(i) != '0') {
                current = next;

                // Decode two digits.
                if (i + 1 < n) {
                    int number = (s.charAt(i) - '0') * 10 + (s.charAt(i + 1) - '0');

                    if (number >= 10 && number <= 26) {
                        current += nextNext;
                    }
                }
            }
            nextNext = next;
            next = current;
        }
        return next;
    }
}

Complexity

Each character is processed once, resulting in O(n) time complexity, and only a constant number of variables is used, resulting in O(1) space complexity.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion