Solving Cryptarithmetic Puzzles (original) (raw)

Last Updated : 23 Jul, 2025

Newspapers and magazines often have crypt-arithmetic puzzles of the form:

SEND
+ MORE
--------
MONEY
--------

Where the goal is to assign each letter a digit from 0 to 9 so that the arithmetic works out correctly. The rules are that all occurrences of a letter must be assigned the same digit, and no digit can be assigned to more than one letter. You are given three strings a, b, and sum, representing the crypt-arithmetic puzzles, your task is to solve the puzzle and print the three strings representing its solution.

**Note: If no possible solution exists, print "-1". If multiple solutions exist, print any.

**Example:

**Input: a = "send", b = "more", sum = "money"
**Output: 7531 0825 08356
**Explanation: 7531 + 0825 = 08356, and all the unique characters are assigned unique digits. 2817, 0368, 03185, is also the possible answer.

**Input: a = "s", b = "p", sum = "f"
**Output: 2 1 3

Table of Content

[Expected Approach] - Using Backtracking - O(10 ^ n ) Time and O(n) Space

The idea is to firstly create a list of all the characters that need assigning to pass to Solve. Now use backtracking to assign all possible digits to the characters.

C++ `

// C++ program to implement // Cryptarithmetic Puzzle Solver #include <bits/stdc++.h> using namespace std;

// Function to remove preceeding zeroes void removeZeroes(string &a) { reverse(a.begin(), a.end());

while(a.size() > 1 && a.back() == '0') {
    a.pop_back();
}

reverse(a.begin(), a.end());

}

// function change character string // to digit string string charToDigit(string a, vector &digits) {

string res = "";
for(int i = 0; i<a.size(); i++) {
    res += digits[a[i]-'a'];
}
return res;

}

// function to find sum of numbers // in the form of strings string findSum(string a, string b) {

// Before proceeding further, make sure length
// of b is larger.
if (a.length() > b.length())
    swap(a, b);

// Take an empty string for storing result
string str = "";

// Calculate length of both string
int n1 = a.length(), n2 = b.length();

// Reverse both of strings
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());

int carry = 0;
for (int i=0; i<n1; i++) {

    // Do school mathematics, compute sum of
    // current digits and carry
    int sum = ((a[i]-'0')+(b[i]-'0')+carry);
    str.push_back(sum%10 + '0');

    // Calculate carry for next step
    carry = sum/10;
}

// Add remaining digits of larger number
for (int i=n1; i<n2; i++) {

    int sum = ((b[i]-'0')+carry);
    str.push_back(sum%10 + '0');
    carry = sum/10;
}

// Add remaining carry
if (carry)
    str.push_back(carry+'0');

// reverse resultant string
reverse(str.begin(), str.end());

// remove preceeding zeroes
removeZeroes(str);

return str;

}

// function to check if puzzle is solved bool isSolved(string &a, string &b, string &sum, vector &digits) {

// convert the character string to digit string
string x = charToDigit(a, digits);
string y = charToDigit(b, digits);
string z = charToDigit(sum, digits);

// sum of string x and y
string res = findSum(x, y);

removeZeroes(z);

// check if res and z is equal
if(z == res) 
    return true;
else return false;

}

// Function to solve Cryptarithmetic // Puzzle using backtracking bool cryptarithmeticSolver(int ind, vector &digits, vector &characters, string &a, string &b, string &sum) {

// if all characters are assigned
// a unique digit
if(ind == 26) {
    return isSolved(a, b, sum, digits);
}

// if current character is assigned a value
// or need not to be assigned
if(digits[ind] != '+') 
    return cryptarithmeticSolver(ind + 1, 
                digits, characters, a, b, sum);

// try to assign all possible digits
for(char i = '0'; i <= '9'; i++) {

    // if digit is not used yet
    if(characters[i-'0'] == 0) {
        characters[i-'0'] = 1;
        digits[ind] = i;
        if(cryptarithmeticSolver(ind + 1, 
            digits, characters, a, b, sum) == true)
            return true;
        digits[ind] = '+';
        characters[i-'0'] = 0;
    }
}

return false;

}

// Function to solve Cryptarithmetic Puzzle vector solvePuzzle(string &a, string &b, string &sum) {

// to map digit assigned to the character
vector<char> digits(26,'-');

// to map character assigned to the digit 
vector<int> characters(10, 0);

// mark character that need a digit to
// be assigned by a "+" sign
for(auto i:a)
    digits[i-'a'] = '+';
for(auto i:b)
    digits[i-'a'] = '+';
for(auto i:sum)
    digits[i-'a'] = '+';

// check if the assignment of digits is
// possible, and find the correct one
if(cryptarithmeticSolver(0, digits,
         characters, a, b, sum) == true) {
        
    // change the string a to digit string
    string x = charToDigit(a, digits);

    // change the string b to digit string
    string y = charToDigit(b, digits);

    // change the string sum to digit string
    string res = charToDigit(sum, digits);

    // return all three digit strings
    return {x, y, res};
}

// if no possible assignment exist
else return {"-1"};

}

int main() { string a = "s"; string b = "p"; string sum = "f"; vector ans = solvePuzzle(a, b, sum); for(auto i:ans) { cout<<i<<" "; } return 0; }

Java

import java.util.*;

class GFG {

static int time = 0;

// Function to remove preceding zeroes
static String removeZeroes(String a) {
    return a.replaceFirst("^0+(?!$)", "");
}

// function change character string to digit string
static String charToDigit(String a, char[] digits) {
    StringBuilder res = new StringBuilder();
    for (int i = 0; i < a.length(); i++) {
        res.append(digits[a.charAt(i) - 'a']);
    }
    return res.toString();
}

// function to find sum of numbers in the form of strings
static String findSum(String a, String b) {
    if (a.length() > b.length()) {
        String temp = a;
        a = b;
        b = temp;
    }

    StringBuilder str = new StringBuilder();
    int n1 = a.length(), n2 = b.length(), carry = 0;

    for (int i = 0; i < n1; i++) {
        int sum = (a.charAt(n1 - 1 - i) - '0') + (b.charAt(n2 - 1 - i) - '0') + carry;
        str.append(sum % 10);
        carry = sum / 10;
    }

    for (int i = n1; i < n2; i++) {
        int sum = (b.charAt(n2 - 1 - i) - '0') + carry;
        str.append(sum % 10);
        carry = sum / 10;
    }

    if (carry > 0) {
        str.append(carry);
    }

    str.reverse();
    return removeZeroes(str.toString());
}

// function to check if puzzle is solved
static boolean isSolved(String a, String b, String sum, char[] digits) {
    String x = charToDigit(a, digits);
    String y = charToDigit(b, digits);
    String z = charToDigit(sum, digits);

    String res = findSum(x, y);
    z = removeZeroes(z);

    return z.equals(res);
}

// Function to solve Cryptarithmetic Puzzle using backtracking
static boolean cryptarithmeticSolver(int ind, char[] digits, int[] characters, String a, String b, String sum) {
    if (ind == 26) {
        return isSolved(a, b, sum, digits);
    }

    if (digits[ind] != '+') {
        return cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum);
    }

    // Try assigning digits only for characters that haven't been assigned yet
    for (char i = '0'; i <= '9'; i++) {
        if (characters[i - '0'] == 0) {
            characters[i - '0'] = 1;
            digits[ind] = i;
            if (cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum)) {
                return true;
            }
            digits[ind] = '+';
            characters[i - '0'] = 0;
        }
    }

    return false;
}

// Function to solve Cryptarithmetic Puzzle
static List<String> solvePuzzle(String a, String b, String sum) {
    char[] digits = new char[26];
    Arrays.fill(digits, '-');

    int[] characters = new int[10];

    // Assign '+' to the characters that need digits
    for (char c : a.toCharArray()) digits[c - 'a'] = '+';
    for (char c : b.toCharArray()) digits[c - 'a'] = '+';
    for (char c : sum.toCharArray()) digits[c - 'a'] = '+';

    if (cryptarithmeticSolver(0, digits, characters, a, b, sum)) {
        String x = charToDigit(a, digits);
        String y = charToDigit(b, digits);
        String res = charToDigit(sum, digits);
        return Arrays.asList(x, y, res);
    } else {
        return Collections.singletonList("-1");
    }
}

public static void main(String[] args) {
    String a = "s";
    String b = "p";
    String sum = "f";
    List<String> ans = solvePuzzle(a, b, sum);
    ans.forEach(i -> System.out.print(i + " "));
}

}

Python

Python program to implement

Cryptarithmetic Puzzle Solver

Function to remove preceding zeroes

def removeZeroes(a): return a.lstrip('0') or '0'

function change character string

to digit string

def charToDigit(a, digits): return ''.join(digits[ord(c) - ord('a')] for c in a)

function to find sum of numbers

in the form of strings

def findSum(a, b): if len(a) > len(b): a, b = b, a

str_res = []
carry = 0

for i in range(len(a)):
    sum_digit = int(a[-1 - i]) + int(b[-1 - i]) + carry
    str_res.append(str(sum_digit % 10))
    carry = sum_digit // 10

for i in range(len(a), len(b)):
    sum_digit = int(b[-1 - i]) + carry
    str_res.append(str(sum_digit % 10))
    carry = sum_digit // 10

if carry:
    str_res.append(str(carry))

return removeZeroes(''.join(reversed(str_res)))

function to check if puzzle is solved

def isSolved(a, b, sum, digits): x = charToDigit(a, digits) y = charToDigit(b, digits) z = charToDigit(sum, digits)

res = findSum(x, y)
z = removeZeroes(z)

return z == res

Function to solve Cryptarithmetic

Puzzle using backtracking

def cryptarithmeticSolver(ind, digits, characters, a, b, sum): if ind == 26: return isSolved(a, b, sum, digits)

if digits[ind] != '+':
    return cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum)

# Try assigning digits only for characters that haven't been assigned yet
for i in range(10):
    if characters[i] == 0:
        characters[i] = 1
        digits[ind] = str(i)
        if cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum):
            return True
        digits[ind] = '+'
        characters[i] = 0

return False

Function to solve Cryptarithmetic Puzzle

def solvePuzzle(a, b, sum): digits = ['-' for _ in range(26)] characters = [0] * 10

for c in a + b + sum:
    digits[ord(c) - ord('a')] = '+'

if cryptarithmeticSolver(0, digits, characters, a, b, sum):
    x = charToDigit(a, digits)
    y = charToDigit(b, digits)
    res = charToDigit(sum, digits)
    return [x, y, res]
else:
    return ["-1"]

Driver Code

a = "s" b = "p" sum = "f" ans = solvePuzzle(a, b, sum) print(" ".join(ans))

C#

// C# program to implement // Cryptarithmetic Puzzle Solver using System; using System.Collections.Generic; using System.Text;

class GFG {

// Function to remove preceding zeroes
static string RemoveZeroes(string a) {
    return a.TrimStart('0').Length > 0 ? a.TrimStart('0') : "0";
}

// function change character string
// to digit string
static string CharToDigit(string a, char[] digits) {
    StringBuilder res = new StringBuilder();
    foreach (char c in a) {
        res.Append(digits[c - 'a']);
    }
    return res.ToString();
}

// function to find sum of numbers
// in the form of strings
static string FindSum(string a, string b) {
    if (a.Length > b.Length) {
        string temp = a;
        a = b;
        b = temp;
    }

    StringBuilder str = new StringBuilder();
    int n1 = a.Length, n2 = b.Length, carry = 0;

    for (int i = 0; i < n1; i++) {
        int sum = (a[n1 - 1 - i] - '0') + (b[n2 - 1 - i] - '0') + carry;
        str.Append(sum % 10);
        carry = sum / 10;
    }

    for (int i = n1; i < n2; i++) {
        int sum = (b[n2 - 1 - i] - '0') + carry;
        str.Append(sum % 10);
        carry = sum / 10;
    }

    if (carry > 0) {
        str.Append(carry);
    }

    char[] arr = str.ToString().ToCharArray();
    Array.Reverse(arr);
    return RemoveZeroes(new string(arr));
}

// function to check if puzzle is solved
static bool IsSolved(string a, string b, string sum, char[] digits) {
    string x = CharToDigit(a, digits);
    string y = CharToDigit(b, digits);
    string z = CharToDigit(sum, digits);

    string res = FindSum(x, y);
    z = RemoveZeroes(z);

    return z.Equals(res);
}

// Function to solve Cryptarithmetic
// Puzzle using backtracking
static bool CryptarithmeticSolver(int ind, char[] digits, int[] characters, string a, string b, string sum) {
    if (ind == 26) {
        return IsSolved(a, b, sum, digits);
    }

    if (digits[ind] != '+') {
        return CryptarithmeticSolver(ind + 1, digits, characters, a, b, sum);
    }

    for (char i = '0'; i <= '9'; i++) {
        if (characters[i - '0'] == 0) {
            characters[i - '0'] = 1;
            digits[ind] = i;
            if (CryptarithmeticSolver(ind + 1, digits, characters, a, b, sum)) {
                return true;
            }
            digits[ind] = '+';
            characters[i - '0'] = 0;
        }
    }

    return false;
}

// Function to solve Cryptarithmetic Puzzle
static List<string> SolvePuzzle(string a, string b, string sum) {
    char[] digits = new char[26];
    Array.Fill(digits, '-');

    int[] characters = new int[10];

    foreach (char i in a) digits[i - 'a'] = '+';
    foreach (char i in b) digits[i - 'a'] = '+';
    foreach (char i in sum) digits[i - 'a'] = '+';

    if (CryptarithmeticSolver(0, digits, characters, a, b, sum)) {
        string x = CharToDigit(a, digits);
        string y = CharToDigit(b, digits);
        string res = CharToDigit(sum, digits);
        return new List<string> { x, y, res };
    } else {
        return new List<string> { "-1" };
    }
}

public static void Main() {
    string a = "s";
    string b = "p";
    string sum = "f";
    List<string> ans = SolvePuzzle(a, b, sum);
    Console.WriteLine(string.Join(" ", ans));
}

}

JavaScript

// JavaScript program to implement // Cryptarithmetic Puzzle Solver

// Function to remove preceding zeroes function removeZeroes(a) { return a.replace(/^0+/, '') || '0'; }

// function change character string // to digit string function charToDigit(a, digits) { return a.split('').map(c => digits[c.charCodeAt(0) - 'a'.charCodeAt(0)]).join(''); }

// function to find sum of numbers // in the form of strings function findSum(a, b) { if (a.length > b.length) { [a, b] = [b, a]; }

let str = [];
let carry = 0;

for (let i = 0; i < a.length; i++) {
    let sum = Number(a[a.length - 1 - i]) + Number(b[b.length - 1 - i]) + carry;
    str.push(sum % 10);
    carry = Math.floor(sum / 10);
}

for (let i = a.length; i < b.length; i++) {
    let sum = Number(b[b.length - 1 - i]) + carry;
    str.push(sum % 10);
    carry = Math.floor(sum / 10);
}

if (carry) {
    str.push(carry);
}

return removeZeroes(str.reverse().join(''));

}

// function to check if puzzle is solved function isSolved(a, b, sum, digits) { let x = charToDigit(a, digits); let y = charToDigit(b, digits); let z = charToDigit(sum, digits);

let res = findSum(x, y);
z = removeZeroes(z);

return z === res;

}

// Function to solve Cryptarithmetic // Puzzle using backtracking function cryptarithmeticSolver(ind, digits, characters, a, b, sum) { if (ind === 26) { return isSolved(a, b, sum, digits); }

if (digits[ind] !== '+') {
    return cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum);
}

for (let i = 0; i <= 9; i++) {
    if (characters[i] === 0) {
        characters[i] = 1;
        digits[ind] = i.toString();
        if (cryptarithmeticSolver(ind + 1, digits, characters, a, b, sum)) {
            return true;
        }
        digits[ind] = '+';
        characters[i] = 0;
    }
}

return false;

}

// Function to solve Cryptarithmetic Puzzle function solvePuzzle(a, b, sum) { let digits = Array(26).fill('-'); let characters = Array(10).fill(0);

[...a, ...b, ...sum].forEach(c => digits[c.charCodeAt(0) - 'a'.charCodeAt(0)] = '+');

if (cryptarithmeticSolver(0, digits, characters, a, b, sum)) {
    let x = charToDigit(a, digits);
    let y = charToDigit(b, digits);
    let res = charToDigit(sum, digits);
    return [x, y, res];
} else {
    return ["-1"];
}

}

// Driver Code let a = "s"; let b = "p"; let sum = "f"; console.log(solvePuzzle(a, b, sum).join(" "));

`

**Time Complexity: O(10 ^ n), where n is number of unique characters. For each character we have 10 digits, thus the time complexity is 10 multiplied n times = O(10 ^ n).
**Auxiliary Space: O(n), considering the recursive call stack.

[Optimized Approach] - O(10! / (10 - n)!) Time and O(n) Space

The idea is to assign the characters starting from the one's place and moving to the left, at each stage, we can verify the correctness of what we have so far before we continue onwards.

**Below is the step-by-step approach:

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

// Function to check if the puzzle is solvable with the given character assignments bool solvePuzzleHelper(const string &a, const string &b, const string &sum, int pos, int carry, unordered_map<char, int> &charToDigit, bitset<10> &usedDigits) {

// Base case: if we have processed all digits
if (pos >= sum.size()) {
    return carry == 0;
}

// Calculate sum at current position
int sumVal = carry;
if (pos < a.size() && charToDigit.count(a[a.size() - 1 - pos])) {
    sumVal += charToDigit[a[a.size() - 1 - pos]];
}
if (pos < b.size() && charToDigit.count(b[b.size() - 1 - pos])) {
    sumVal += charToDigit[b[b.size() - 1 - pos]];
}

char sumChar = sum[sum.size() - 1 - pos];

// If sumChar is already assigned, check if it matches
if (charToDigit.count(sumChar)) {
    if (charToDigit[sumChar] != sumVal % 10) {
        return false;
    }
    return solvePuzzleHelper(a, b, sum, pos + 1, 
                    sumVal / 10, charToDigit, usedDigits);
}

// Ensure digit is not already used
if (usedDigits[sumVal % 10]) {
    return false;
}

// Assign the digit to sumChar
charToDigit[sumChar] = sumVal % 10;
usedDigits[sumVal % 10] = 1;

// Recur for next position
if (solvePuzzleHelper(a, b, sum, pos + 1, 
                sumVal / 10, charToDigit, usedDigits)) {
    return true;
}

// Backtrack if assignment fails
charToDigit.erase(sumChar);
usedDigits[sumVal % 10] = 0;
return false;

}

// Function to assign digits to unique characters and check if assignment is valid bool assignDigits(const string &a, const string &b, const string &sum, int index, const string &order, unordered_map<char, int> &charToDigit, bitset<10> &usedDigits) {

// Base case: If all characters are assigned
if (index == order.size()) {
    return solvePuzzleHelper(a, b, sum, 0, 0, charToDigit, usedDigits);
}

char ch = order[index];

// Try assigning each digit to the character
for (int digit = 0; digit < 10; digit++) {
    if (!usedDigits[digit]) {
        charToDigit[ch] = digit;
        usedDigits[digit] = 1;
        if (assignDigits(a, b, sum, index + 1, order, charToDigit, usedDigits)) {
            return true;
        }
        // Backtrack if unsuccessful
        usedDigits[digit] = 0;
        charToDigit.erase(ch);
    }
}
return false;

}

// Main function to solve Cryptarithmetic puzzle vector solvePuzzle(string a, string b, string sum) { unordered_map<char, int> charToDigit; bitset<10> usedDigits; unordered_set uniqueChars; string order;

// Identify unique characters in the input strings
for (char ch : a + b + sum) {
    if (uniqueChars.insert(ch).second) {
        order += ch;
    }
}

// Assign digits to characters and check validity
if (assignDigits(a, b, sum, 0, order, charToDigit, usedDigits)) {
    string x, y, z;
    for (char ch : a) x += '0' + charToDigit[ch];
    for (char ch : b) y += '0' + charToDigit[ch];
    for (char ch : sum) z += '0' + charToDigit[ch];
    return {x, y, z};
}
return {"-1"};

}

int main() { string a = "send", b = "more", sum = "money"; vector ans = solvePuzzle(a, b, sum); for (const auto &res : ans) { cout << res << " "; } return 0; }

Java

import java.util.*;

class GFG {

// Function to check if the puzzle is solvable with the given character assignments
static boolean solvePuzzleHelper(String a, String b, String sum, int pos, int carry, 
                                 Map<Character, Integer> charToDigit, boolean[] usedDigits) {
    // Base case: if we have processed all digits
    if (pos >= sum.length()) {
        return carry == 0;
    }

    // Calculate sum at current position
    int sumVal = carry;
    if (pos < a.length() && charToDigit.containsKey(a.charAt(a.length() - 1 - pos))) {
        sumVal += charToDigit.get(a.charAt(a.length() - 1 - pos));
    }
    if (pos < b.length() && charToDigit.containsKey(b.charAt(b.length() - 1 - pos))) {
        sumVal += charToDigit.get(b.charAt(b.length() - 1 - pos));
    }

    char sumChar = sum.charAt(sum.length() - 1 - pos);

    // If sumChar is already assigned, check if it matches
    if (charToDigit.containsKey(sumChar)) {
        if (charToDigit.get(sumChar) != sumVal % 10) {
            return false;
        }
        return solvePuzzleHelper(a, b, sum, pos + 1, sumVal / 10, charToDigit, usedDigits);
    }

    // Ensure digit is not already used
    if (usedDigits[sumVal % 10]) {
        return false;
    }

    // Assign the digit to sumChar
    charToDigit.put(sumChar, sumVal % 10);
    usedDigits[sumVal % 10] = true;

    // Recur for next position
    if (solvePuzzleHelper(a, b, sum, pos + 1, sumVal / 10, charToDigit, usedDigits)) {
        return true;
    }

    // Backtrack if assignment fails
    charToDigit.remove(sumChar);
    usedDigits[sumVal % 10] = false;
    return false;
}

// Function to assign digits to unique characters and check if assignment is valid
static boolean assignDigits(String a, String b, String sum, int index, 
                            String order, Map<Character, Integer> charToDigit, boolean[] usedDigits) {
    // Base case: If all characters are assigned
    if (index == order.length()) {
        return solvePuzzleHelper(a, b, sum, 0, 0, charToDigit, usedDigits);
    }

    char ch = order.charAt(index);

    // Try assigning each digit to the character
    for (int digit = 0; digit < 10; digit++) {
        if (!usedDigits[digit]) {
            charToDigit.put(ch, digit);
            usedDigits[digit] = true;
            if (assignDigits(a, b, sum, index + 1, order, charToDigit, usedDigits)) {
                return true;
            }
            // Backtrack if unsuccessful
            usedDigits[digit] = false;
            charToDigit.remove(ch);
        }
    }
    return false;
}

// Main function to solve Cryptarithmetic puzzle
static List<String> solvePuzzle(String a, String b, String sum) {
    Map<Character, Integer> charToDigit = new HashMap<>();
    boolean[] usedDigits = new boolean[10];
    Set<Character> uniqueChars = new HashSet<>();
    StringBuilder order = new StringBuilder();

    // Identify unique characters in the input strings
    for (char ch : (a + b + sum).toCharArray()) {
        if (uniqueChars.add(ch)) {
            order.append(ch);
        }
    }

    // Assign digits to characters and check validity
    if (assignDigits(a, b, sum, 0, order.toString(), charToDigit, usedDigits)) {
        StringBuilder x = new StringBuilder(), y = new StringBuilder(), z = new StringBuilder();
        for (char ch : a.toCharArray()) x.append(charToDigit.get(ch));
        for (char ch : b.toCharArray()) y.append(charToDigit.get(ch));
        for (char ch : sum.toCharArray()) z.append(charToDigit.get(ch));
        return Arrays.asList(x.toString(), y.toString(), z.toString());
    }
    return Collections.singletonList("-1");
}

public static void main(String[] args) {
    String a = "send", b = "more", sum = "money";
    List<String> ans = solvePuzzle(a, b, sum);
    for (String res : ans) {
        System.out.print(res + " ");
    }
}

}

Python

Function to check if the puzzle is solvable with the given character assignments

def solvePuzzleHelper(a, b, sumStr, pos, carry, charToDigit, usedDigits): # Base case: if we have processed all digits if pos >= len(sumStr): return carry == 0

# Calculate sum at current position
sumVal = carry
if pos < len(a) and a[-(pos + 1)] in charToDigit:
    sumVal += charToDigit[a[-(pos + 1)]]
if pos < len(b) and b[-(pos + 1)] in charToDigit:
    sumVal += charToDigit[b[-(pos + 1)]]

sumChar = sumStr[-(pos + 1)]

# If sumChar is already assigned, check if it matches
if sumChar in charToDigit:
    if charToDigit[sumChar] != sumVal % 10:
        return False
    return solvePuzzleHelper(a, b, sumStr, pos + 1, sumVal // 10, charToDigit, usedDigits)

# Ensure digit is not already used
if usedDigits[sumVal % 10]:
    return False

# Assign the digit to sumChar
charToDigit[sumChar] = sumVal % 10
usedDigits[sumVal % 10] = True

# Recur for next position
if solvePuzzleHelper(a, b, sumStr, pos + 1, sumVal // 10, charToDigit, usedDigits):
    return True

# Backtrack if assignment fails
del charToDigit[sumChar]
usedDigits[sumVal % 10] = False
return False

Function to assign digits to unique characters and check if assignment is valid

def assignDigits(a, b, sumStr, index, order, charToDigit, usedDigits): # Base case: If all characters are assigned if index == len(order): return solvePuzzleHelper(a, b, sumStr, 0, 0, charToDigit, usedDigits)

ch = order[index]

# Try assigning each digit to the character
for digit in range(10):
    if not usedDigits[digit]:
        charToDigit[ch] = digit
        usedDigits[digit] = True
        if assignDigits(a, b, sumStr, index + 1, order, charToDigit, usedDigits):
            return True
        # Backtrack if unsuccessful
        usedDigits[digit] = False
        del charToDigit[ch]

return False

Main function to solve Cryptarithmetic puzzle

def solvePuzzle(a, b, sumStr): charToDigit = {} usedDigits = [False] * 10 uniqueChars = set() order = ""

# Identify unique characters in the input strings
for ch in a + b + sumStr:
    if ch not in uniqueChars:
        uniqueChars.add(ch)
        order += ch

# Assign digits to characters and check validity
if assignDigits(a, b, sumStr, 0, order, charToDigit, usedDigits):
    x = "".join(str(charToDigit[ch]) for ch in a)
    y = "".join(str(charToDigit[ch]) for ch in b)
    z = "".join(str(charToDigit[ch]) for ch in sumStr)
    return [x, y, z]

return ["-1"]

Driver code

a, b, sumStr = "send", "more", "money" ans = solvePuzzle(a, b, sumStr) print(" ".join(ans))

C#

using System; using System.Collections.Generic;

// Function to check if the puzzle is solvable with the given character assignments class GFG { static bool SolvePuzzleHelper(string a, string b, string sum, int pos, int carry, Dictionary<char, int> charToDigit, bool[] usedDigits) {

    // Base case: if we have processed all digits
    if (pos >= sum.Length) {
        return carry == 0;
    }
    
    // Calculate sum at current position
    int sumVal = carry;
    if (pos < a.Length && charToDigit.ContainsKey(a[a.Length - 1 - pos])) {
        sumVal += charToDigit[a[a.Length - 1 - pos]];
    }
    if (pos < b.Length && charToDigit.ContainsKey(b[b.Length - 1 - pos])) {
        sumVal += charToDigit[b[b.Length - 1 - pos]];
    }
    
    char sumChar = sum[sum.Length - 1 - pos];
    
    // If sumChar is already assigned, check if it matches
    if (charToDigit.ContainsKey(sumChar)) {
        if (charToDigit[sumChar] != sumVal % 10) {
            return false;
        }
        return SolvePuzzleHelper(a, b, sum, pos + 1, sumVal / 10, charToDigit, usedDigits);
    }
    
    // Ensure digit is not already used
    if (usedDigits[sumVal % 10]) {
        return false;
    }
    
    // Assign the digit to sumChar
    charToDigit[sumChar] = sumVal % 10;
    usedDigits[sumVal % 10] = true;
    
    // Recur for next position
    if (SolvePuzzleHelper(a, b, sum, pos + 1, sumVal / 10, charToDigit, usedDigits)) {
        return true;
    }
    
    // Backtrack if assignment fails
    charToDigit.Remove(sumChar);
    usedDigits[sumVal % 10] = false;
    return false;
}

static bool AssignDigits(string a, string b, string sum, int index, string order, 
    Dictionary<char, int> charToDigit, bool[] usedDigits) {

    // Base case: If all characters are assigned
    if (index == order.Length) {
        return SolvePuzzleHelper(a, b, sum, 0, 0, charToDigit, usedDigits);
    }
    
    char ch = order[index];
    
    // Try assigning each digit to the character
    for (int digit = 0; digit < 10; digit++) {
        if (!usedDigits[digit]) {
            charToDigit[ch] = digit;
            usedDigits[digit] = true;
            if (AssignDigits(a, b, sum, index + 1, order, charToDigit, usedDigits)) {
                return true;
            }
            // Backtrack if unsuccessful
            usedDigits[digit] = false;
            charToDigit.Remove(ch);
        }
    }
    return false;
}

public static List<string> SolvePuzzle(string a, string b, string sum) {
    Dictionary<char, int> charToDigit = new Dictionary<char, int>();
    bool[] usedDigits = new bool[10];
    HashSet<char> uniqueChars = new HashSet<char>();
    string order = "";

    // Identify unique characters in the input strings
    foreach (char ch in a + b + sum) {
        if (uniqueChars.Add(ch)) {
            order += ch;
        }
    }

    // Assign digits to characters and check validity
    if (AssignDigits(a, b, sum, 0, order, charToDigit, usedDigits)) {
        string x = "", y = "", z = "";
        foreach (char ch in a) x += charToDigit[ch].ToString();
        foreach (char ch in b) y += charToDigit[ch].ToString();
        foreach (char ch in sum) z += charToDigit[ch].ToString();
        return new List<string> { x, y, z };
    }
    return new List<string> { "-1" };
}

public static void Main() {
    string a = "send", b = "more", sum = "money";
    List<string> ans = SolvePuzzle(a, b, sum);
    foreach (string res in ans) {
        Console.Write(res + " ");
    }
}

}

JavaScript

// Function to check if the puzzle is solvable with the given character assignments function solvePuzzleHelper(a, b, sum, pos, carry, charToDigit, usedDigits) {

// Base case: if we have processed all digits
if (pos >= sum.length) {
    return carry === 0;
}

// Calculate sum at current position
let sumVal = carry;
if (pos < a.length && charToDigit.has(a[a.length - 1 - pos])) {
    sumVal += charToDigit.get(a[a.length - 1 - pos]);
}
if (pos < b.length && charToDigit.has(b[b.length - 1 - pos])) {
    sumVal += charToDigit.get(b[b.length - 1 - pos]);
}

let sumChar = sum[sum.length - 1 - pos];

// If sumChar is already assigned, check if it matches
if (charToDigit.has(sumChar)) {
    if (charToDigit.get(sumChar) !== sumVal % 10) {
        return false;
    }
    return solvePuzzleHelper(a, b, sum, pos + 1, Math.floor(sumVal / 10), charToDigit, usedDigits);
}

// Ensure digit is not already used
if (usedDigits[sumVal % 10]) {
    return false;
}

// Assign the digit to sumChar
charToDigit.set(sumChar, sumVal % 10);
usedDigits[sumVal % 10] = true;

// Recur for next position
if (solvePuzzleHelper(a, b, sum, pos + 1, Math.floor(sumVal / 10), charToDigit, usedDigits)) {
    return true;
}

// Backtrack if assignment fails
charToDigit.delete(sumChar);
usedDigits[sumVal % 10] = false;
return false;

}

// Function to assign digits to unique characters and check if assignment is valid function assignDigits(a, b, sum, index, order, charToDigit, usedDigits) {

// Base case: If all characters are assigned
if (index === order.length) {
    return solvePuzzleHelper(a, b, sum, 0, 0, charToDigit, usedDigits);
}

let ch = order[index];

// Try assigning each digit to the character
for (let digit = 0; digit < 10; digit++) {
    if (!usedDigits[digit]) {
        charToDigit.set(ch, digit);
        usedDigits[digit] = true;
        if (assignDigits(a, b, sum, index + 1, order, charToDigit, usedDigits)) {
            return true;
        }
        // Backtrack if unsuccessful
        usedDigits[digit] = false;
        charToDigit.delete(ch);
    }
}
return false;

}

// Main function to solve Cryptarithmetic puzzle function solvePuzzle(a, b, sum) { let charToDigit = new Map(); let usedDigits = new Array(10).fill(false); let uniqueChars = new Set(); let order = "";

// Identify unique characters in the input strings
for (let ch of a + b + sum) {
    if (!uniqueChars.has(ch)) {
        uniqueChars.add(ch);
        order += ch;
    }
}

// Assign digits to characters and check validity
if (assignDigits(a, b, sum, 0, order, charToDigit, usedDigits)) {
    let x = "", y = "", z = "";
    for (let ch of a) x += charToDigit.get(ch);
    for (let ch of b) y += charToDigit.get(ch);
    for (let ch of sum) z += charToDigit.get(ch);
    return [x, y, z];
}
return ["-1"];

}

// Driver code let a = "send", b = "more", sum = "money"; console.log(solvePuzzle(a, b, sum).join(" "));

`

Time Complexity: O(10! / (10 - n)!), where n is the number of unique characters. Let _k be the number of unique characters (k ≤ 10 in typical puzzles) and _n be the length of the strings (digits in the numbers). The assignDigits function tries all possible assignments for _k characters, which in the worst-case is on the order of O(P(10, k)) = O(10!/(10–k)!) assignments.
**Auxiliary Space: O(n), considering the recursive call stack.