Consider a coding system where the letters a to z are represented by the numbers 1 to 26 (a = 1, b = 2, ..., z = 26). Given an array arr[] of digits, find every valid way to decode it into a string by grouping consecutive digits into chunks of one or two digits, where each chunk's value lies between 1 and 26. Return all such decoded strings, in any order.
Note: We can not change order of array. That means [1, 2, 1] cannot become [2, 1, 1]
Examples:
Input: arr[] = [1, 1]
Output: ["aa", "k"]
Explanation: The digits can be grouped two different ways:
Reading each digit separately gives 1, 1, which is 'a' + 'a' = "aa".
Grouping both digits together gives 11, which is 'k'.
Both groupings are valid, so there are 2 interpretations.Input: arr[] = [1, 2, 1]
Output: ["aba", "au", "la"]
Explanation: The digits can be grouped three different ways:
Reading each digit separately gives 1, 2, 1, which is 'a' + 'b' + 'a' = "aba".
Grouping the last two digits as 21 gives 1, 21, which is 'a' + 'u' = "au".
Grouping the first two digits as 12 gives 12, 1, which is 'l' + 'a' = "la".
All three groupings are valid, so there are 3 interpretations.
Table of Content
Using Binary Tree Construction - O(2^n) Time and O(2^n) Space
The order of the digits cannot be changed, so at each position there are only two choices: decode the current digit as a single character or decode the current and next digits together if they form a valid number (10 to 26). These choices form a binary tree, where the left child represents a single-digit decoding and the right child represents a two-digit decoding. Each root-to-leaf path gives one valid interpretation, so collecting all leaf nodes produces all possible decoded strings.
Consider arr[] = {1, 2, 1}.
- Start with an empty string "".
- Decode 1 as 'a' and move to the next digit.
- From "a":
- Decode 2 as 'b', then decode 1 as 'a' to get "aba".
- Decode 21 as 'u' to get "au".
- From the root, decode 12 as 'l', then decode 1 as 'a' to get "la".
The binary tree formed is:

The leaf nodes contain all valid interpretations: ["aba", "au", "la"]
#include <bits/stdc++.h>
using namespace std;
// Tree node
class Node {
public:
string str;
Node *left, *right;
Node(string s) {
str = s;
left = right = nullptr;
}
};
vector<string> ans;
// Builds the binary tree
Node* createTree(int idx, string curr, vector<int> &arr) {
int n = arr.size();
if (idx == n)
return new Node(curr);
Node *root = new Node(curr);
// Decode one digit
if (arr[idx] >= 1 && arr[idx] <= 9)
root->left = createTree(idx + 1,
curr + char('a' + arr[idx] - 1),
arr);
// Decode two digits
if (idx + 1 < n) {
int num = arr[idx] * 10 + arr[idx + 1];
if (num >= 10 && num <= 26)
root->right = createTree(idx + 2,
curr + char('a' + num - 1),
arr);
}
return root;
}
// Collect all leaf nodes
void collectLeaf(Node *root) {
if (!root)
return;
if (!root->left && !root->right) {
ans.push_back(root->str);
return;
}
collectLeaf(root->left);
collectLeaf(root->right);
}
vector<string> findAllInterpretations(vector<int> &arr) {
ans.clear();
Node *root = createTree(0, "", arr);
collectLeaf(root);
return ans;
}
int main() {
vector<int> arr = {1, 2, 1};
vector<string> res = findAllInterpretations(arr);
cout << "[";
for (int i = 0; i < res.size(); i++) {
cout << "\"" << res[i] << "\"";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.ArrayList;
// Tree node
class Node {
String str;
Node left, right;
Node(String s) {
str = s;
left = right = null;
}
}
class GFG {
static ArrayList<String> ans = new ArrayList<>();
// Builds the binary tree
public static Node createTree(int idx, String curr, int[] arr) {
int n = arr.length;
if (idx == n)
return new Node(curr);
Node root = new Node(curr);
// Decode one digit
if (arr[idx] >= 1 && arr[idx] <= 9)
root.left = createTree(idx + 1,
curr + (char) ('a' + arr[idx] - 1),
arr);
// Decode two digits
if (idx + 1 < n) {
int num = arr[idx] * 10 + arr[idx + 1];
if (num >= 10 && num <= 26)
root.right = createTree(idx + 2,
curr + (char) ('a' + num - 1),
arr);
}
return root;
}
// Collect all leaf nodes
public static void collectLeaf(Node root) {
if (root == null)
return;
if (root.left == null && root.right == null) {
ans.add(root.str);
return;
}
collectLeaf(root.left);
collectLeaf(root.right);
}
public static ArrayList<String> findAllInterpretations(int[] arr) {
ans.clear();
Node root = createTree(0, "", arr);
collectLeaf(root);
return ans;
}
public static void main(String[] args) {
int[] arr = {1, 2, 1};
ArrayList<String> res = findAllInterpretations(arr);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print("\"" + res.get(i) + "\"");
if (i + 1 < res.size())
System.out.print(", ");
}
System.out.println("]");
}
}
# Tree node
class Node:
def __init__(self, s):
self.str = s
self.left = None
self.right = None
# Builds the binary tree
def createTree(idx, curr, arr):
n = len(arr)
if idx == n:
return Node(curr)
root = Node(curr)
# Decode one digit
if 1 <= arr[idx] <= 9:
root.left = createTree(
idx + 1,
curr + chr(ord('a') + arr[idx] - 1),
arr
)
# Decode two digits
if idx + 1 < n:
num = arr[idx] * 10 + arr[idx + 1]
if 10 <= num <= 26:
root.right = createTree(
idx + 2,
curr + chr(ord('a') + num - 1),
arr
)
return root
# Collect all leaf nodes
def collectLeaf(root, ans):
if not root:
return
if root.left is None and root.right is None:
ans.append(root.str)
return
collectLeaf(root.left, ans)
collectLeaf(root.right, ans)
def findAllInterpretations(arr):
ans = []
root = createTree(0, "", arr)
collectLeaf(root, ans)
return ans
def main():
arr = [1, 2, 1]
res = findAllInterpretations(arr)
print("[", end="")
for i in range(len(res)):
print(f'"{res[i]}"', end="")
if i + 1 < len(res):
print(", ", end="")
print("]")
if __name__ == "__main__":
main()
using System;
using System.Collections.Generic;
// Tree node
class Node
{
public string str;
public Node left, right;
public Node(string s)
{
str = s;
left = right = null;
}
}
class Program
{
static List<string> ans = new List<string>();
// Builds the binary tree
static Node createTree(int idx, string curr, int[] arr)
{
int n = arr.Length;
if (idx == n)
return new Node(curr);
Node root = new Node(curr);
// Decode one digit
if (arr[idx] >= 1 && arr[idx] <= 9)
root.left = createTree(
idx + 1,
curr + (char)('a' + arr[idx] - 1),
arr);
// Decode two digits
if (idx + 1 < n)
{
int num = arr[idx] * 10 + arr[idx + 1];
if (num >= 10 && num <= 26)
root.right = createTree(
idx + 2,
curr + (char)('a' + num - 1),
arr);
}
return root;
}
// Collect all leaf nodes
static void collectLeaf(Node root)
{
if (root == null)
return;
if (root.left == null && root.right == null)
{
ans.Add(root.str);
return;
}
collectLeaf(root.left);
collectLeaf(root.right);
}
static List<string> findAllInterpretations(int[] arr)
{
ans.Clear();
Node root = createTree(0, "", arr);
collectLeaf(root);
return ans;
}
static void Main()
{
int[] arr = { 1, 2, 1 };
List<string> res = findAllInterpretations(arr);
Console.Write("[");
for (int i = 0; i < res.Count; i++)
{
Console.Write($"\"{res[i]}\"");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.WriteLine("]");
}
}
// Tree node
class Node {
constructor(s) {
this.str = s;
this.left = null;
this.right = null;
}
}
// Builds the binary tree
function createTree(idx, curr, arr) {
let n = arr.length;
if (idx === n)
return new Node(curr);
let root = new Node(curr);
// Decode one digit
if (arr[idx] >= 1 && arr[idx] <= 9)
root.left = createTree(
idx + 1,
curr + String.fromCharCode('a'.charCodeAt(0) + arr[idx] - 1),
arr
);
// Decode two digits
if (idx + 1 < n) {
let num = arr[idx] * 10 + arr[idx + 1];
if (num >= 10 && num <= 26)
root.right = createTree(
idx + 2,
curr + String.fromCharCode('a'.charCodeAt(0) + num - 1),
arr
);
}
return root;
}
// Collect all leaf nodes
function collectLeaf(root, ans) {
if (root === null)
return;
if (root.left === null && root.right === null) {
ans.push(root.str);
return;
}
collectLeaf(root.left, ans);
collectLeaf(root.right, ans);
}
function findAllInterpretations(arr) {
let ans = [];
let root = createTree(0, "", arr);
collectLeaf(root, ans);
return ans;
}
// Driver code
let arr = [1, 2, 1];
let res = findAllInterpretations(arr);
process.stdout.write("[");
for (let i = 0; i < res.length; i++) {
process.stdout.write(`"${res[i]}"`);
if (i + 1 < res.length)
process.stdout.write(", ");
}
console.log("]");
Output
["aba", "au", "la"]
Using Backtracking - O((2^n)*n) Time and O(n) Space
Instead of constructing a binary tree, we directly generate all valid interpretations using backtracking. At each position, there are two possible choices: decode the current digit as a single character or decode the current and next digits together if they form a valid number (10 to 26). We append the corresponding character to the current string, recursively process the remaining digits, and then backtrack by removing the last character. This explores all possible interpretations while using only the recursion stack.
- Start decoding from the first digit with an empty string.
- Decode the current digit, append its character, recurse, and then remove it.
- If the current and next digits form a valid letter (10 to 26), append that character, recurse, and then remove it.
- When all digits have been processed, store the current string as one valid interpretation.
- Continue until all possible interpretations have been generated.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void dfs(vector<int>& arr, int index, string& curr,
vector<string>& res) {
int n = arr.size();
// One complete interpretation is formed
if (index == n) {
res.push_back(curr);
return;
}
// Take the current digit alone
if (arr[index] >= 1 && arr[index] <= 9) {
curr.push_back('a' + arr[index] - 1);
dfs(arr, index + 1, curr, res);
curr.pop_back();
}
// Combine current and next digit if they form a valid letter
if (index + 1 < n) {
int val = arr[index] * 10 + arr[index + 1];
if (val >= 10 && val <= 26) {
curr.push_back('a' + val - 1);
dfs(arr, index + 2, curr, res);
curr.pop_back();
}
}
}
vector<string> findAllInterpretations(vector<int>& arr) {
vector<string> res;
string curr;
dfs(arr, 0, curr, res);
return res;
}
int main() {
vector<int> arr = {1, 2, 1};
vector<string> res = findAllInterpretations(arr);
cout << "[";
for (int i = 0; i < res.size(); i++) {
cout << "\"" << res[i] << "\"";
if (i + 1 < res.size())
cout << ", ";
}
cout << "]";
return 0;
}
import java.util.ArrayList;
import java.util.List;
class GFG {
static void dfs(int[] arr, int index, StringBuilder curr,
ArrayList<String> res) {
int n = arr.length;
// One complete interpretation is formed
if (index == n) {
res.add(curr.toString());
return;
}
// Take the current digit alone
if (arr[index] >= 1 && arr[index] <= 9) {
curr.append((char) ('a' + arr[index] - 1));
dfs(arr, index + 1, curr, res);
curr.deleteCharAt(curr.length() - 1);
}
// Combine current and next digit if they form a valid letter
if (index + 1 < n) {
int val = arr[index] * 10 + arr[index + 1];
if (val >= 10 && val <= 26) {
curr.append((char) ('a' + val - 1));
dfs(arr, index + 2, curr, res);
curr.deleteCharAt(curr.length() - 1);
}
}
}
static ArrayList<String> findAllInterpretations(int[] arr) {
ArrayList<String> res = new ArrayList<>();
StringBuilder curr = new StringBuilder();
dfs(arr, 0, curr, res);
return res;
}
public static void main(String[] args) {
int[] arr = {1, 2, 1};
ArrayList<String> res = findAllInterpretations(arr);
System.out.print("[");
for (int i = 0; i < res.size(); i++) {
System.out.print("\"" + res.get(i) + "\"");
if (i + 1 < res.size())
System.out.print(", ");
}
System.out.println("]");
}
}
def dfs(arr, index, curr, res):
n = len(arr)
# One complete interpretation is formed
if index == n:
res.append("".join(curr))
return
# Take the current digit alone
if 1 <= arr[index] <= 9:
curr.append(chr(ord('a') + arr[index] - 1))
dfs(arr, index + 1, curr, res)
curr.pop()
# Combine current and next digit if they form a valid letter
if index + 1 < n:
val = arr[index] * 10 + arr[index + 1]
if 10 <= val <= 26:
curr.append(chr(ord('a') + val - 1))
dfs(arr, index + 2, curr, res)
curr.pop()
def findAllInterpretations(arr):
res = []
curr = []
dfs(arr, 0, curr, res)
return res
if __name__ == "__main__":
arr = [1, 2, 1]
res = findAllInterpretations(arr)
print("[", end="")
for i in range(len(res)):
print(f'"{res[i]}"', end="")
if i + 1 < len(res):
print(", ", end="")
print("]")
using System;
using System.Collections.Generic;
using System.Text;
class GFG
{
static void dfs(int[] arr, int index, StringBuilder curr,
List<string> res)
{
int n = arr.Length;
// One complete interpretation is formed
if (index == n)
{
res.Add(curr.ToString());
return;
}
// Take the current digit alone
if (arr[index] >= 1 && arr[index] <= 9)
{
curr.Append((char)('a' + arr[index] - 1));
dfs(arr, index + 1, curr, res);
curr.Length--;
}
// Combine current and next digit if they form a valid letter
if (index + 1 < n)
{
int val = arr[index] * 10 + arr[index + 1];
if (val >= 10 && val <= 26)
{
curr.Append((char)('a' + val - 1));
dfs(arr, index + 2, curr, res);
curr.Length--;
}
}
}
static List<string> findAllInterpretations(int[] arr)
{
List<string> res = new List<string>();
StringBuilder curr = new StringBuilder();
dfs(arr, 0, curr, res);
return res;
}
static void Main()
{
int[] arr = { 1, 2, 1 };
List<string> res = findAllInterpretations(arr);
Console.Write("[");
for (int i = 0; i < res.Count; i++)
{
Console.Write($"\"{res[i]}\"");
if (i + 1 < res.Count)
Console.Write(", ");
}
Console.WriteLine("]");
}
}
function dfs(arr, index, curr, res) {
let n = arr.length;
// One complete interpretation is formed
if (index === n) {
res.push(curr.join(""));
return;
}
// Take the current digit alone
if (arr[index] >= 1 && arr[index] <= 9) {
curr.push(String.fromCharCode('a'.charCodeAt(0) + arr[index] - 1));
dfs(arr, index + 1, curr, res);
curr.pop();
}
// Combine current and next digit if they form a valid letter
if (index + 1 < n) {
let val = arr[index] * 10 + arr[index + 1];
if (val >= 10 && val <= 26) {
curr.push(String.fromCharCode('a'.charCodeAt(0) + val - 1));
dfs(arr, index + 2, curr, res);
curr.pop();
}
}
}
function findAllInterpretations(arr) {
let res = [];
let curr = [];
dfs(arr, 0, curr, res);
return res;
}
// Driver Code
let arr = [1, 2, 1];
let res = findAllInterpretations(arr);
process.stdout.write("[");
for (let i = 0; i < res.length; i++) {
process.stdout.write(`"${res[i]}"`);
if (i + 1 < res.length)
process.stdout.write(", ");
}
console.log("]");
Output
["aba", "au", "la"]