Count Possible Decodings of a given Digit Sequence (original) (raw)

Last Updated : 22 Mar, 2025

Try it on GfG Practice redirect icon

Let 1 maps to 'A', 2 maps to 'B', ..., 26 to 'Z'. Given a **digit sequence, **count the number of possible decodings of the given digit sequence.

Consider the input string ****"123"**. There are three valid ways to decode it:

**Note: Groupings that contain invalid codes (e.g., "0" by itself or numbers greater than "26") are not allowed.
For instance, the string ****"230"** is **invalid because ****"0"** cannot stand alone, and ****"30" is greater than "26",** so it cannot represent any letter. The task is to find the **total number of valid ways to decode a given string.

**Examples:

**Input: digits = "121"
**Output: 3
**Explanation: The possible decodings are "ABA", "AU", "LA"

**Input: digits = "1234"
**Output: 3
**Explanation: The possible decodings are "ABCD", "LCD", "AWD"

Table of Content

[Naive Approach] Using Recursion - O(2^n) Time and O(n) Space

For the **recursive approach to count decoding ways, there will be two cases:

The recurrence relation will look like this:

**Base Case: if index >= digits.length()

C++ `

// C++ program to count decoding ways of a digit string // using recursion. #include <bits/stdc++.h> using namespace std;

// Helper function to recursively calculate decoding ways. int decodeHelper(string &digits, int index) {

int n = digits.length();

// Base case: If we reach the end of the string,
// return 1 as it signifies a valid decoding.
if (index >= n)
{
    return 1;
}

int ways = 0;

// Single-digit decoding: check if current digit is not '0'.
if (digits[index] != '0')
{
    ways = decodeHelper(digits, index + 1);
}

// Two-digit decoding: check if next two digits are valid.
if ((index + 1 < n) && ((digits[index] == '1' && digits[index + 1] <= '9') ||
                        (digits[index] == '2' && digits[index + 1] <= '6')))
{

    ways += decodeHelper(digits, index + 2);
}

return ways;

}

// Function to count decoding ways for the // entire string. int countWays(string &digits) {

return decodeHelper(digits, 0);

}

int main() {

string digits = "121";

cout << countWays(digits) << endl;

return 0;

}

Java

// Java program to count decoding ways of a digit string // using recursion. import java.util.*;

class GfG {

// Helper function to recursively calculate decoding
// ways.
static int decodeHelper(String digits, int index)
{

    int n = digits.length();

    // Base case: If we reach the end of the string,
    // return 1 as it signifies a valid decoding.
    if (index >= n) {
        return 1;
    }

    int ways = 0;

    // Single-digit decoding: check if current digit is
    // not '0'.
    if (digits.charAt(index) != '0') {
        ways = decodeHelper(digits, index + 1);
    }

    // Two-digit decoding: check if next two digits are
    // valid.
    if ((index + 1 < n)
        && ((digits.charAt(index) == '1'
             && digits.charAt(index + 1) <= '9')
            || (digits.charAt(index) == '2'
                && digits.charAt(index + 1) <= '6'))) {

        ways += decodeHelper(digits, index + 2);
    }

    return ways;
}

// Function to count decoding ways for the
// entire string.
static int countWays(String digits)
{
    return decodeHelper(digits, 0);
}

public static void main(String[] args)
{

    String digits = "121";

    System.out.println(countWays(digits));
}

}

Python

Python program to count decoding ways of a digit string

using recursion.

Helper function to recursively calculate decoding ways

def decodeHelper(digits, index): n = len(digits)

# Base case: If we reach the end of the string,
# return 1 as it signifies a valid decoding.
if index >= n:
    return 1

ways = 0

# Single-digit decoding: check if current digit is not '0'.
if digits[index] != '0':
    ways = decodeHelper(digits, index + 1)

# Two-digit decoding: check if next two digits are valid.
if (index + 1 < n and
    ((digits[index] == '1' and digits[index + 1] <= '9') or
     (digits[index] == '2' and digits[index + 1] <= '6'))):

    ways += decodeHelper(digits, index + 2)

return ways

Function to count decoding ways for the entire string

def countWays(digits): return decodeHelper(digits, 0)

if name == "main":

digits = "121"
print(countWays(digits))

C#

// C# program to count decoding ways of a digit string // using recursion. using System;

class GfG {

// Helper function to recursively calculate decoding
// ways.
static int DecodeHelper(string digits, int index)
{

    int n = digits.Length;

    // Base case: If we reach the end of the string,
    // return 1 as it signifies a valid decoding.
    if (index >= n) {
        return 1;
    }

    int ways = 0;

    // Single-digit decoding: check if current digit is
    // not '0'.
    if (digits[index] != '0') {
        ways = DecodeHelper(digits, index + 1);
    }

    // Two-digit decoding: check if next two digits are
    // valid.
    if ((index + 1 < n)
        && ((digits[index] == '1'
             && digits[index + 1] <= '9')
            || (digits[index] == '2'
                && digits[index + 1] <= '6'))) {

        ways += DecodeHelper(digits, index + 2);
    }

    return ways;
}

// Function to count decoding ways for the entire
// string.
static int countWays(string digits)
{
    return DecodeHelper(digits, 0);
}

static void Main()
{
    string digits = "121";
    Console.WriteLine(countWays(digits));
}

}

JavaScript

// JavaScript program to count decoding ways of a digit // string using recursion.

function decodeHelper(digits, index) { const n = digits.length;

// Base case: If we reach the end of the string,
// return 1 as it signifies a valid decoding.
if (index >= n) {
    return 1;
}

let ways = 0;

// Single-digit decoding: check if current digit is not
// '0'.
if (digits[index] !== "0") {
    ways = decodeHelper(digits, index + 1);
}

// Two-digit decoding: check if next two digits are
// valid.
if (index + 1 < n
    && ((digits[index] === "1"
         && digits[index + 1] <= "9")
        || (digits[index] === "2"
            && digits[index + 1] <= "6"))) {
    ways += decodeHelper(digits, index + 2);
}

return ways;

}

// Function to count decoding ways for the entire string function countWays(digits) { return decodeHelper(digits, 0); }

const digits = "121"; console.log(countWays(digits));

`

[Better Approach 1] Using Top-Down DP (Memoization****) -** O(n) **Time and O(n) Space

**1. Optimal Substructure: The solution to the problem can be broken down into smaller subproblems:

Mathematically, the recurrence relations are:

**if digits[index] != '0':
decodeHelper(digits, index) = decodeHelper(digits, index + 1)

**if digits[index] and digits[index + 1] form a valid number :
decodeHelper(digits, index) += decodeHelper(digits, index + 2)

**2. Overlapping Subproblems: The same subproblems are recalculated **multiple times, like computing the number of decodings from index i repeatedly. This overlap can be avoided using memoization to store already computed results.

memo[index] = decodeHelper(digits, index + 1) if digits[index] != '0'
memo[index] += decodeHelper(digits, index + 2) if digits[index] and digits[index + 1]

C++ `

// C++ program to count decoding ways of a digit string // using Memoization #include <bits/stdc++.h> using namespace std;

// Helper function to recursively calculate decoding ways // with memoization. int decodeHelper(string &digits, int index, vector &memo) {

int n = digits.length();

// Base case: If we reach the end of the string,
// return 1 as it signifies a valid decoding.
if (index >= n)
{
    return 1;
}

// If the value is already calculated for this
// index, return it.
if (memo[index] != -1)
{
    return memo[index];
}

int ways = 0;

// Single-digit decoding: check if current digit is not '0'.
if (digits[index] != '0')
{
    ways = decodeHelper(digits, index + 1, memo);
}

// Two-digit decoding: check if next two digits are valid.
if ((index + 1 < n) && ((digits[index] == '1' && digits[index + 1] <= '9') ||
                        (digits[index] == '2' && digits[index + 1] <= '6')))
{

    ways += decodeHelper(digits, index + 2, memo);
}

// Memoize the result for the current index.
memo[index] = ways;
return ways;

}

// Function to count decoding ways for the entire string. int countWays(string &digits) { int n = digits.length();

// Create a memoization vector initialized to -1.
vector<int> memo(n, -1);

return decodeHelper(digits, 0, memo);

}

int main() {

string digits = "121";

cout << countWays(digits) << endl;

return 0;

}

Java

// Java program to count decoding ways of a digit string // using recursion with memoization. import java.util.*;

class GfG {

// Helper function to recursively calculate decoding
// ways with memoization.
static int decodeHelper(String digits, int index,
                        int[] memo)
{

    int n = digits.length();

    // Base case: If we reach the end of the string,
    // return 1 as it signifies a valid decoding.
    if (index >= n) {
        return 1;
    }

    // If the value is already calculated for this
    // index, return it.
    if (memo[index] != -1) {
        return memo[index];
    }

    int ways = 0;

    // Single-digit decoding: check if current digit is
    // not '0'.
    if (digits.charAt(index) != '0') {
        ways = decodeHelper(digits, index + 1, memo);
    }

    // Two-digit decoding: check if next two digits are
    // valid.
    if ((index + 1 < n)
        && ((digits.charAt(index) == '1'
             && digits.charAt(index + 1) <= '9')
            || (digits.charAt(index) == '2'
                && digits.charAt(index + 1) <= '6'))) {

        ways += decodeHelper(digits, index + 2, memo);
    }

    // Memoize the result for the current index.
    memo[index] = ways;
    return ways;
}

// Function to count decoding ways for the entire
// string.
static int countWays(String digits)
{

    int n = digits.length();

    // Create a memoization array initialized to -1.
    int[] memo = new int[n];
    Arrays.fill(memo, -1);

    return decodeHelper(digits, 0, memo);
}

public static void main(String[] args)
{

    String digits = "121";

    System.out.println(countWays(digits));
}

}

Python

Python program to count decoding ways of a digit string

using recursion with memoization.

Helper function to recursively calculate decoding ways

def decodeHelper(digits, index, memo): n = len(digits)

# Base case: If we reach the end of the string,
# return 1 as it signifies a valid decoding.
if index >= n:
    return 1

# If the result for this index is already
# calculated, return it.
if memo[index] != -1:
    return memo[index]

ways = 0

# Single-digit decoding: check if current digit is not '0'.
if digits[index] != '0':
    ways = decodeHelper(digits, index + 1, memo)

# Two-digit decoding: check if next two digits are valid.
if (index + 1 < n and
    ((digits[index] == '1' and digits[index + 1] <= '9') or
     (digits[index] == '2' and digits[index + 1] <= '6'))):

    ways += decodeHelper(digits, index + 2, memo)

# Memoize the result for the current index.
memo[index] = ways
return ways

Function to count decoding ways for the entire string

def countWays(digits): n = len(digits)

# Create a memoization list initialized to -1.
memo = [-1] * n
return decodeHelper(digits, 0, memo)

if name == "main":

digits = "121"
print(countWays(digits))

C#

// C# program to count decoding ways of a digit string // using recursion with memoization. using System;

class GfG {

// Helper function to recursively calculate
// decoding ways.
static int DecodeHelper(string digits, int index,
                        int[] memo)
{

    int n = digits.Length;

    // Base case: If we reach the end of the string,
    // return 1 as it signifies a valid decoding.
    if (index >= n) {
        return 1;
    }

    // If result for this index is already computed,
    // return it.
    if (memo[index] != -1) {
        return memo[index];
    }

    int ways = 0;

    // Single-digit decoding: check if current
    // digit is not '0'.
    if (digits[index] != '0') {
        ways = DecodeHelper(digits, index + 1, memo);
    }

    // Two-digit decoding: check if next two
    // digits are valid.
    if ((index + 1 < n)
        && ((digits[index] == '1'
             && digits[index + 1] <= '9')
            || (digits[index] == '2'
                && digits[index + 1] <= '6'))) {

        ways += DecodeHelper(digits, index + 2, memo);
    }

    // Store the result in memo and return it.
    memo[index] = ways;
    return ways;
}

// Function to count decoding ways for the entire
// string.
static int countWays(string digits)
{
    int n = digits.Length;

    // Memoization array initialized to -1.
    int[] memo = new int[n];
    Array.Fill(memo, -1);

    return DecodeHelper(digits, 0, memo);
}

static void Main()
{

    string digits = "121";

    Console.WriteLine(countWays(digits));
}

}

JavaScript

// JavaScript program to count decoding ways of a digit // string using recursion with memoization.

function decodeHelper(digits, index, memo) { const n = digits.length;

// Base case: If we reach the end of the string,
// return 1 as it signifies a valid decoding.
if (index >= n) {
    return 1;
}

// If result for this index is already computed, return
// it.
if (memo[index] !== -1) {
    return memo[index];
}

let ways = 0;

// Single-digit decoding: check if current digit is not
// '0'.
if (digits[index] !== "0") {
    ways = decodeHelper(digits, index + 1, memo);
}

// Two-digit decoding: check if next two digits are
// valid.
if (index + 1 < n
    && ((digits[index] === "1"
         && digits[index + 1] <= "9")
        || (digits[index] === "2"
            && digits[index + 1] <= "6"))) {
    ways += decodeHelper(digits, index + 2, memo);
}

// Store the result in memo and return it.
memo[index] = ways;
return ways;

}

// Function to count decoding ways for the entire string. function countWays(digits) { const n = digits.length;

// Memoization array initialized to -1.
const memo = new Array(n).fill(-1);

return decodeHelper(digits, 0, memo);

}

const digits = "121"; console.log(countWays(digits));

`

[Better Approach 2] Using Bottom-Up DP (Tabulation) -O(n) **Time and O(n) Space

The approach here is similar to the **recursive method, but instead of breaking down the problem recursively, we solve it iteratively in a bottom-up manner using dynamic programming. We will create a 1D array dp of size (n + 1), where dp[i], represents the number of ways to decode the **substring starting from **index i of the string **digits[].

**Dynamic Programming Relation:

If the current digit is not '0', it can be **decoded as a single digit, so we update the dp[i] as:

If the next two digits form a valid number between **10 and 26, then we also consider decoding the current and next digit together:

**Base Case: dp[n] = 1, where an **empty string has one valid decoding.

C++ `

// C++ program to count decoding ways of a digit string // using Tabulation #include <bits/stdc++.h> using namespace std;

// Function to count decoding ways for the entire string. int countWays(string &digits) { int n = digits.length();

// Create a dp array initialized to 0, with size n + 1.
vector<int> dp(n + 1, 0);

// Base case: An empty string has one valid decoding.
dp[n] = 1;

// Iterate from the end of the string to the beginning.
for (int i = n - 1; i >= 0; i--)
{

    // Single-digit decoding: check if current
    // digit is not '0'.
    if (digits[i] != '0')
    {
        dp[i] = dp[i + 1];
    }

    // Two-digit decoding: check if next two digits are valid.
    if ((i + 1 < n) &&
        ((digits[i] == '1' && digits[i + 1] <= '9') || (digits[i] == '2' && digits[i + 1] <= '6')))
    {
        dp[i] += dp[i + 2];
    }
}

return dp[0];

}

int main() {

string digits = "121";
cout << countWays(digits) << endl;

return 0;

}

Java

// Java program to count decoding ways of a digit string // using Tabulation import java.util.ArrayList;

class GfG {

// Function to count decoding ways for the entire
// string.
public static int countWays(String digits)
{
    int n = digits.length();

    // Create a dp list initialized to 0, with size n
    // + 1.
    ArrayList<Integer> dp = new ArrayList<>();
    for (int i = 0; i <= n; i++) {
        dp.add(0);
    }

    // Base case: An empty string has one valid
    // decoding.
    dp.set(n, 1);

    // Iterate from the end of the string to the
    // beginning.
    for (int i = n - 1; i >= 0; i--) {

        // Single-digit decoding: check if current
        // digit is not '0'.
        if (digits.charAt(i) != '0') {
            dp.set(i, dp.get(i + 1));
        }

        // Two-digit decoding: check if next two digits
        // are valid.
        if ((i + 1 < n)
            && ((digits.charAt(i) == '1'
                 && digits.charAt(i + 1) <= '9')
                || (digits.charAt(i) == '2'
                    && digits.charAt(i + 1) <= '6'))) {

            dp.set(i, dp.get(i) + dp.get(i + 2));
        }
    }

    return dp.get(0);
}

public static void main(String[] args)
{

    String digits = "121";

    System.out.println(countWays(digits));
}

}

Python

Python program to count decoding ways of a digit string

using Tabulation

Function to count decoding ways for the entire string.

def countWays(digits): n = len(digits)

# Create a dp list initialized to 0, with size n + 1.
dp = [0] * (n + 1)

# Base case: An empty string has one valid decoding.
dp[n] = 1

# Iterate from the end of the string to the beginning.
for i in range(n - 1, -1, -1):

    # Single-digit decoding: check if current
    # digit is not '0'.
    if digits[i] != '0':
        dp[i] = dp[i + 1]

    # Two-digit decoding: check if next two digits are valid.
    if (i + 1 < n and
        ((digits[i] == '1' and digits[i + 1] <= '9') or
         (digits[i] == '2' and digits[i + 1] <= '6'))):
        dp[i] += dp[i + 2]

return dp[0]

if name == "main":

digits = "121"

print(countWays(digits))

C#

// C# program to count decoding ways of a digit string // using Tabulation using System; using System.Collections.Generic;

class GfG {

// Function to count decoding ways for the entire
// string.
static int countWays(string digits)
{
    int n = digits.Length;

    // Create a dp list initialized to 0, with size n
    // + 1.
    List<int> dp = new List<int>(new int[n + 1]);

    // Base case: An empty string has one valid
    // decoding.
    dp[n] = 1;

    // Iterate from the end of the string to the
    // beginning.
    for (int i = n - 1; i >= 0; i--) {

        // Single-digit decoding: check if current
        // digit is not '0'.
        if (digits[i] != '0') {
            dp[i] = dp[i + 1];
        }

        // Two-digit decoding: check if next two digits
        // are valid.
        if ((i + 1 < n)
            && ((digits[i] == '1'
                 && digits[i + 1] <= '9')
                || (digits[i] == '2'
                    && digits[i + 1] <= '6'))) {

            dp[i] += dp[i + 2];
        }
    }

    return dp[0];
}

static void Main()
{

    string digits = "121";

    Console.WriteLine(countWays(digits));
}

}

JavaScript

// Javascript program to count decoding ways of // a digit string using Tabulation

// Function to count decoding ways for the entire string. function countWays(digits) { const n = digits.length;

// Create a dp array initialized to 0, with size n + 1.
const dp = Array(n + 1).fill(0);

// Base case: An empty string has one valid decoding.
dp[n] = 1;

// Iterate from the end of the string to the beginning.
for (let i = n - 1; i >= 0; i--) {

    // Single-digit decoding: check if current
    // digit is not '0'.
    if (digits[i] !== "0") {
        dp[i] = dp[i + 1];
    }

    // Two-digit decoding: check if next two digits are
    // valid.
    if (i + 1 < n
        && ((digits[i] === "1" && digits[i + 1] <= "9")
            || (digits[i] === "2"
                && digits[i + 1] <= "6"))) {
        dp[i] += dp[i + 2];
    }
}

return dp[0];

}

const digits = "121";

console.log(countWays(digits));

`

[Expected Approach] Using Space Optimised DP -O(n) **Time and O(1) Space

In **previous approach of dynamic programming we have derive the relation between states as given below:

If we observe that for calculating **current dp[i] state we only need previous two values dp[i+1] and dp[i]+dp[i+2]. There is no need to store all the **previous states.

C++ `

#include <bits/stdc++.h> using namespace std;

// Function to count decoding ways for the // entire string with optimized space. int countWays(string digits) { int n = digits.length();

// If the string is empty or starts with '0',
// there are no valid decodings.
if (n == 0 || digits[0] == '0')
{
    return 0;
}

// two variables to store the previous two results.
int prev1 = 1, prev2 = 0;

for (int i = 1; i <= n; ++i)
{
    int current = 0;

    // Check for valid single-digit decoding
    if (digits[i - 1] != '0')
    {
        current += prev1;
    }

    // Check for valid two-digit decoding
    // (previous digit and current digit form a
    // valid number between 10 and 26)
    if (i > 1)
    {
        int twoDigit = (digits[i - 2] - '0') * 10 + (digits[i - 1] - '0');
        if (twoDigit >= 10 && twoDigit <= 26)
        {
            current += prev2;
        }
    }

    // Update prev1 and prev2 for the next iteration.
    prev2 = prev1;
    prev1 = current;
}
return prev1;

}

int main() { string digits = "121"; cout << countWays(digits) << endl; return 0; }

Java

// Function to count decoding ways for the entire string // with optimized space. class GfG { static int countWays(String digits) { int n = digits.length();

    // If the string is empty or starts with '0',
    // there are no valid decodings.
    if (n == 0 || digits.charAt(0) == '0') {
        return 0;
    }

    // two variables to store the previous two results.
    int prev1 = 1, prev2 = 0;

    for (int i = 1; i <= n; ++i) {

        int current = 0;

        // Check for valid single-digit decoding
        if (digits.charAt(i - 1) != '0') {
            current += prev1;
        }

        // Check for valid two-digit decoding
        // (previous digit and current digit form
        // a valid number between 10 and 26)
        if (i > 1) {
            int twoDigit
                = (digits.charAt(i - 2) - '0') * 10
                  + (digits.charAt(i - 1) - '0');
            if (twoDigit >= 10 && twoDigit <= 26) {
                current += prev2;
            }
        }

        // Update prev1 and prev2 for the next
        // iteration.
        prev2 = prev1;
        prev1 = current;
    }
    return prev1;
}

public static void main(String[] args)
{
    String digits = "121";
    System.out.println(countWays(digits));
}

}

Python

def countWays(digits): n = len(digits)

# If the string is empty or starts with '0',
# there are no valid decodings.
if n == 0 or digits[0] == '0':
    return 0

# two variables to store the previous two results.
prev1, prev2 = 1, 0

for i in range(1, n + 1):
    current = 0
    # Check for valid single-digit decoding
    if digits[i - 1] != '0':
        current += prev1
    # Check for valid two-digit decoding
    # (previous digit and current digit form a valid number between 10 and 26)
    if i > 1:
        two_digit = (int(digits[i - 2]) * 10 + int(digits[i - 1]))
        if 10 <= two_digit <= 26:
            current += prev2

    # Update prev1 and prev2 for the next iteration.
    prev2 = prev1
    prev1 = current
return prev1

if name == 'main': digits = '121' print(countWays(digits))

C#

using System;

class GfG { static int countWays(string digits) { int n = digits.Length;

    // If the string is empty or starts with '0',
    // there are no valid decodings.
    if (n == 0 || digits[0] == '0') {
        return 0;
    }

    // two variables to store the previous two results.
    int prev1 = 1, prev2 = 0;

    for (int i = 1; i <= n; ++i) {
        int current = 0;
        // Check for valid single-digit decoding
        if (digits[i - 1] != '0') {
            current += prev1;
        }
        // Check for valid two-digit decoding
        // (previous digit and current digit form a
        // valid number between 10 and 26)
        if (i > 1) {
            int twoDigit = (digits[i - 2] - '0') * 10
                           + (digits[i - 1] - '0');
            if (twoDigit >= 10 && twoDigit <= 26) {
                current += prev2;
            }
        }

        // Update prev1 and prev2 for the next
        // iteration.
        prev2 = prev1;
        prev1 = current;
    }
    return prev1;
}

public static void Main()
{
    string digits = "121";
    Console.WriteLine(countWays(digits));
}

}

JavaScript

function countWays(digits) { const n = digits.length;

// If the string is empty or starts with '0',
// there are no valid decodings.
if (n === 0 || digits[0] === "0") {
    return 0;
}

// two variables to store the previous two results.
let prev1 = 1, prev2 = 0;

for (let i = 1; i <= n; ++i) {
    let current = 0;
    // Check for valid single-digit decoding
    if (digits[i - 1] !== "0") {
        current += prev1;
    }
    // Check for valid two-digit decoding
    // (previous digit and current digit form a valid
    // number between 10 and 26)
    if (i > 1) {
        const twoDigit = (parseInt(digits[i - 2]) * 10
                          + parseInt(digits[i - 1]));
        if (twoDigit >= 10 && twoDigit <= 26) {
            current += prev2;
        }
    }

    // Update prev1 and prev2 for the next iteration.
    prev2 = prev1;
    prev1 = current;
}
return prev1;

}

const digits = "121"; console.log(countWays(digits));

`