
- DSA - Home
- DSA - Overview
- DSA - Environment Setup
- DSA - Algorithms Basics
- DSA - Asymptotic Analysis
- Data Structures
- DSA - Data Structure Basics
- DSA - Data Structures and Types
- DSA - Array Data Structure
- DSA - Skip List Data Structure
- Linked Lists
- DSA - Linked List Data Structure
- DSA - Doubly Linked List Data Structure
- DSA - Circular Linked List Data Structure
- Stack & Queue
- DSA - Stack Data Structure
- DSA - Expression Parsing
- DSA - Queue Data Structure
- DSA - Circular Queue Data Structure
- DSA - Priority Queue Data Structure
- DSA - Deque Data Structure
- Searching Algorithms
- DSA - Searching Algorithms
- DSA - Linear Search Algorithm
- DSA - Binary Search Algorithm
- DSA - Interpolation Search
- DSA - Jump Search Algorithm
- DSA - Exponential Search
- DSA - Fibonacci Search
- DSA - Sublist Search
- DSA - Hash Table
- Sorting Algorithms
- DSA - Sorting Algorithms
- DSA - Bubble Sort Algorithm
- DSA - Insertion Sort Algorithm
- DSA - Selection Sort Algorithm
- DSA - Merge Sort Algorithm
- DSA - Shell Sort Algorithm
- DSA - Heap Sort Algorithm
- DSA - Bucket Sort Algorithm
- DSA - Counting Sort Algorithm
- DSA - Radix Sort Algorithm
- DSA - Quick Sort Algorithm
- Matrices Data Structure
- DSA - Matrices Data Structure
- DSA - Lup Decomposition In Matrices
- DSA - Lu Decomposition In Matrices
- Graph Data Structure
- DSA - Graph Data Structure
- DSA - Depth First Traversal
- DSA - Breadth First Traversal
- DSA - Spanning Tree
- DSA - Topological Sorting
- DSA - Strongly Connected Components
- DSA - Biconnected Components
- DSA - Augmenting Path
- DSA - Network Flow Problems
- DSA - Flow Networks In Data Structures
- DSA - Edmonds Blossom Algorithm
- DSA - Maxflow Mincut Theorem
- Tree Data Structure
- DSA - Tree Data Structure
- DSA - Tree Traversal
- DSA - Binary Search Tree
- DSA - AVL Tree
- DSA - Red Black Trees
- DSA - B Trees
- DSA - B+ Trees
- DSA - Splay Trees
- DSA - Range Queries
- DSA - Segment Trees
- DSA - Fenwick Tree
- DSA - Fusion Tree
- DSA - Hashed Array Tree
- DSA - K-Ary Tree
- DSA - Kd Trees
- DSA - Priority Search Tree Data Structure
- Recursion
- DSA - Recursion Algorithms
- DSA - Tower of Hanoi Using Recursion
- DSA - Fibonacci Series Using Recursion
- Divide and Conquer
- DSA - Divide and Conquer
- DSA - Max-Min Problem
- DSA - Strassen's Matrix Multiplication
- DSA - Karatsuba Algorithm
- Greedy Algorithms
- DSA - Greedy Algorithms
- DSA - Travelling Salesman Problem (Greedy Approach)
- DSA - Prim's Minimal Spanning Tree
- DSA - Kruskal's Minimal Spanning Tree
- DSA - Dijkstra's Shortest Path Algorithm
- DSA - Map Colouring Algorithm
- DSA - Fractional Knapsack Problem
- DSA - Job Sequencing with Deadline
- DSA - Optimal Merge Pattern Algorithm
- Dynamic Programming
- DSA - Dynamic Programming
- DSA - Matrix Chain Multiplication
- DSA - Floyd Warshall Algorithm
- DSA - 0-1 Knapsack Problem
- DSA - Longest Common Sub-sequence Algorithm
- DSA - Travelling Salesman Problem (Dynamic Approach)
- Hashing
- DSA - Hashing Data Structure
- DSA - Collision In Hashing
- Disjoint Set
- DSA - Disjoint Set
- DSA - Path Compression And Union By Rank
- Heap
- DSA - Heap Data Structure
- DSA - Binary Heap
- DSA - Binomial Heap
- DSA - Fibonacci Heap
- Tries Data Structure
- DSA - Tries
- DSA - Standard Tries
- DSA - Compressed Tries
- DSA - Suffix Tries
- Treaps
- DSA - Treaps Data Structure
- Bit Mask
- DSA - Bit Mask In Data Structures
- Bloom Filter
- DSA - Bloom Filter Data Structure
- Approximation Algorithms
- DSA - Approximation Algorithms
- DSA - Vertex Cover Algorithm
- DSA - Set Cover Problem
- DSA - Travelling Salesman Problem (Approximation Approach)
- Randomized Algorithms
- DSA - Randomized Algorithms
- DSA - Randomized Quick Sort Algorithm
- DSA - Karger’s Minimum Cut Algorithm
- DSA - Fisher-Yates Shuffle Algorithm
- Miscellaneous
- DSA - Infix to Postfix
- DSA - Bellmon Ford Shortest Path
- DSA - Maximum Bipartite Matching
- DSA Useful Resources
- DSA - Questions and Answers
- DSA - Selection Sort Interview Questions
- DSA - Merge Sort Interview Questions
- DSA - Insertion Sort Interview Questions
- DSA - Heap Sort Interview Questions
- DSA - Bubble Sort Interview Questions
- DSA - Bucket Sort Interview Questions
- DSA - Radix Sort Interview Questions
- DSA - Cycle Sort Interview Questions
- DSA - Quick Guide
- DSA - Useful Resources
- DSA - Discussion
Solving Cryptarithmetic Puzzles
What is Crypt-arithmetic Puzzle?
A Crypt-arithmetic puzzle, also known as a cryptogram, is a type of mathematical puzzle in which we assign digits to alphabetical letters or symbols. The end goal is to find the unique digit assignment to each letter so that the given mathematical operation holds true. In this puzzle, the equation performing an addition operation is the most commonly used. However, it also involves other arithmetic operations, such as subtraction, multiplication etc.
The rules for a Crypt-arithmetic puzzle are as follows −
We can use digits from 0 to 9 only to represent a unique alphabetical letter in the puzzle.
The same digit cannot be assigned to different letters in the whole equation.
The resulting equation formed by replacing letters with digits should be mathematically correct.
Input Output Scenario
Suppose the given equation is −
Input: B A S E B A L L ---------- G A M E S
In the above equation, the words namely "BASE" and "BALL" are added to produce "GAMES". The algorithm will associate each letter of the given words with a unique number from 0 to 9. For the above input, the ouput should be −

Solving Crypt-arithmetic Puzzles using Backtracking Approach
The naive approach to solving the cryptarithmetic problem is by taking one letter from each operand starting from the left-hand side and assigning digits from 0 to 9 one by one. After assigning the digits, check the validity of the arithmetic expression. However, this method is inefficient for larger operands.
To solve a crypt-arithmetic problem using the backtracking approach, follow the below steps −
First, identify all the unique characters from the given arithmetic expression.
Next, try assigning digits to the letters. If duplicacy is found backtrack and unassign. This way all possible combinations of digits for each letter will be generated.
Now, replace the letters with digits and check if the expression is true.
Example
In the following example, we will practically demonstrate how to solve the cryptarithmetic problem.
#include <stdio.h> #include <string.h> //set 1, when one character is assigned previously int use[10] = {0}; // structure struct node { char letter; int value; }; int isValid(struct node* nodeList, const int count, char* s1, char* s2, char* s3) { int val1 = 0, val2 = 0, val3 = 0, m = 1, j, i; //find number for first string for (i = strlen(s1) - 1; i >= 0; i--) { char ch = s1[i]; for (j = 0; j < count; j++) //when ch is present, break the loop if (nodeList[j].letter == ch) break; val1 += m * nodeList[j].value; m *= 10; } m = 1; //find number for second string for (i = strlen(s2) - 1; i >= 0; i--) { char ch = s2[i]; for (j = 0; j < count; j++) if (nodeList[j].letter == ch) break; val2 += m * nodeList[j].value; m *= 10; } m = 1; //find number for third string for (i = strlen(s3) - 1; i >= 0; i--) { char ch = s3[i]; for (j = 0; j < count; j++) if (nodeList[j].letter == ch) break; val3 += m * nodeList[j].value; m *= 10; } //check whether the sum is same as 3rd string or not if (val3 == (val1 + val2)) return 1; return 0; } int permutation(int count, struct node* nodeList, int n, char* s1, char* s2, char* s3) { //when values are assigned for all characters if (n == count - 1) { for (int i = 0; i < 10; i++) { // for those numbers, which are not used if (use[i] == 0) { //assign value i nodeList[n].value = i; //check validation if (isValid(nodeList, count, s1, s2, s3) == 1) { printf("Solution found: "); //print code, which are assigned for (int j = 0; j < count; j++) printf(" %c = %d", nodeList[j].letter, nodeList[j].value); return 1; } } } return 0; } for (int i = 0; i < 10; i++) { // for those numbers, which are not used if (use[i] == 0) { //assign value i and mark as not available for future use nodeList[n].value = i; use[i] = 1; //go for next characters if (permutation(count, nodeList, n + 1, s1, s2, s3) == 1) return 1; //when backtracks, make available again use[i] = 0; } } return 0; } int solvePuzzle(char* s1, char* s2, char* s3) { //Number of unique characters int uniqueChar = 0; int len1 = strlen(s1); int len2 = strlen(s2); int len3 = strlen(s3); //There are 26 different characters int freq[26] = {0}; for (int i = 0; i < len1; i++) ++freq[s1[i] - 'A']; for (int i = 0; i < len2; i++) ++freq[s2[i] - 'A']; for (int i = 0; i < len3; i++) ++freq[s3[i] - 'A']; for (int i = 0; i < 26; i++) //whose frequency is > 0, they are present if (freq[i] > 0) uniqueChar++; //as there are 10 digits in decimal system if (uniqueChar > 10) { printf("Invalid strings"); return 0; } struct node nodeList[uniqueChar]; //assign all characters found in three strings for (int i = 0, j = 0; i < 26; i++) { if (freq[i] > 0) { nodeList[j].letter = (char)(i + 'A'); j++; } } return permutation(uniqueChar, nodeList, 0, s1, s2, s3); } int main() { char s1[] = "BASE"; char s2[] = "BALL"; char s3[] = "GAMES"; if (solvePuzzle(s1, s2, s3) == 0) printf("No solution"); return 0; }
#include <iostream> #include <vector> using namespace std; //set 1, when one character is assigned previously vector<int> use(10); struct node { char letter; int value; }; int isValid(node* nodeList, const int count, string s1, string s2, string s3) { int val1 = 0, val2 = 0, val3 = 0, m = 1, j, i; //find number for first string for (i = s1.length() - 1; i >= 0; i--) { char ch = s1[i]; for (j = 0; j < count; j++) //when ch is present, break the loop if (nodeList[j].letter == ch) break; val1 += m * nodeList[j].value; m *= 10; } m = 1; //find number for second string for (i = s2.length() - 1; i >= 0; i--) { char ch = s2[i]; for (j = 0; j < count; j++) if (nodeList[j].letter == ch) break; val2 += m * nodeList[j].value; m *= 10; } m = 1; //find number for third string for (i = s3.length() - 1; i >= 0; i--) { char ch = s3[i]; for (j = 0; j < count; j++) if (nodeList[j].letter == ch) break; val3 += m * nodeList[j].value; m *= 10; } //check whether the sum is same as 3rd string or not if (val3 == (val1 + val2)) return 1; return 0; } bool permutation(int count, node* nodeList, int n, string s1, string s2, string s3) { //when values are assigned for all characters if (n == count - 1) { for (int i = 0; i < 10; i++) { // for those numbers, which are not used if (use[i] == 0) { //assign value i nodeList[n].value = i; //check validation if (isValid(nodeList, count, s1, s2, s3) == 1) { cout << "Solution found: "; //print code, which are assigned for (int j = 0; j < count; j++) cout << " " << nodeList[j].letter << " = " << nodeList[j].value; return true; } } } return false; } for (int i = 0; i < 10; i++) { // for those numbers, which are not used if (use[i] == 0) { //assign value i and mark as not available for future use nodeList[n].value = i; use[i] = 1; //go for next characters if (permutation(count, nodeList, n + 1, s1, s2, s3)) return true; //when backtracks, make available again use[i] = 0; } } return false; } bool solvePuzzle(string s1, string s2,string s3) { //Number of unique characters int uniqueChar = 0; int len1 = s1.length(); int len2 = s2.length(); int len3 = s3.length(); //There are 26 different characters vector<int> freq(26); for (int i = 0; i < len1; i++) ++freq[s1[i] - 'A']; for (int i = 0; i < len2; i++) ++freq[s2[i] - 'A']; for (int i = 0; i < len3; i++) ++freq[s3[i] - 'A']; for (int i = 0; i < 26; i++) //whose frequency is > 0, they are present if (freq[i] > 0) uniqueChar++; //as there are 10 digits in decimal system if (uniqueChar > 10) { cout << "Invalid strings"; return 0; } node nodeList[uniqueChar]; //assign all characters found in three strings for (int i = 0, j = 0; i < 26; i++) { if (freq[i] > 0) { nodeList[j].letter = char(i + 'A'); j++; } } return permutation(uniqueChar, nodeList, 0, s1, s2, s3); } int main() { string s1 = "BASE"; string s2 = "BALL"; string s3 = "GAMES"; if (solvePuzzle(s1, s2, s3) == false) cout << "No solution"; }
public class Main { // Set 1 when one character is assigned previously int[] use = new int[10]; class Node { char letter; int value; } public int isValid(Node[] nodeList, int count, String s1, String s2, String s3) { int val1 = 0, val2 = 0, val3 = 0; int m = 1; int j, i; //find number for first string for (i = s1.length() - 1; i >= 0; i--) { char ch = s1.charAt(i); for (j = 0; j < count; j++) { // when ch is present, break the loop if (nodeList[j].letter == ch) { break; } } val1 += m * nodeList[j].value; m *= 10; } m = 1; //find number for second string for (i = s2.length() - 1; i >= 0; i--) { char ch = s2.charAt(i); for (j = 0; j < count; j++) { if (nodeList[j].letter == ch) { break; } } val2 += m * nodeList[j].value; m *= 10; } m = 1; //find number for third string for (i = s3.length() - 1; i >= 0; i--) { char ch = s3.charAt(i); for (j = 0; j < count; j++) { if (nodeList[j].letter == ch) { break; } } val3 += m * nodeList[j].value; m *= 10; } //check whether the sum is same as 3rd string or not if (val3 == (val1 + val2)) { return 1; } return 0; } public int permutation(int count, Node[] nodeList, int n, String s1, String s2, String s3) { //when values are assign if (n == count - 1) { // for those numbers, which are not used for (int i = 0; i < 10; i++) { if (use[i] == 0) { //assign value i nodeList[n].value = i; if (isValid(nodeList, count, s1, s2, s3) == 1) { System.out.print("Solution found:"); //print code, which are assigned for (int j = 0; j < count; j++) { System.out.print(" " + nodeList[j].letter + " = " + nodeList[j].value); } return 1; } } } return 0; } // for those numbers, which are not used for (int i = 0; i < 10; i++) { if (use[i] == 0) { //assign value i and mark as not available for future use nodeList[n].value = i; use[i] = 1; if (permutation(count, nodeList, n + 1, s1, s2, s3) == 1) { //go for next characters return 1; } //when backtracks, make available again use[i] = 0; } } return 0; } public int solvePuzzle(String s1, String s2, String s3) { //Number of unique characters int uniqueChar = 0; int len1 = s1.length(); int len2 = s2.length(); int len3 = s3.length(); // There are 26 different characters int[] freq = new int[26]; for (int i = 0; i < len1; i++) { freq[s1.charAt(i) - 'A']++; } for (int i = 0; i < len2; i++) { freq[s2.charAt(i) - 'A']++; } for (int i = 0; i < len3; i++) { freq[s3.charAt(i) - 'A']++; } //whose frequency is > 0, they are present for (int i = 0; i < 26; i++) { if (freq[i] > 0) { uniqueChar++; } } //as there are 10 digits in decimal system if (uniqueChar > 10) { System.out.println("Invalid strings"); return 0; } Node[] nodeList = new Node[uniqueChar]; int j = 0; for (int i = 0; i < 26; i++) { //assign all characters found in three strings if (freq[i] > 0) { nodeList[j] = new Node(); nodeList[j].letter = (char) (i + 'A'); j++; } } return permutation(uniqueChar, nodeList, 0, s1, s2, s3); } public static void main(String[] args) { Main main = new Main(); String s1 = "BASE"; String s2 = "BALL"; String s3 = "GAMES"; if (main.solvePuzzle(s1, s2, s3) == 0) { System.out.println("No solution"); } } }
class Main: #Set 1 when one character is assigned previously use = [0] * 10 class Node: def __init__(self): self.letter = '' self.value = 0 def isValid(self, nodeList, count, s1, s2, s3): val1 = 0 val2 = 0 val3 = 0 m = 1 j = 0 i = 0 #find number for first string for i in range(len(s1) - 1, -1, -1): ch = s1[i] for j in range(count): #when ch is present, break the loop if nodeList[j].letter == ch: break val1 += m * nodeList[j].value m *= 10 m = 1 #find number for the second string for i in range(len(s2) - 1, -1, -1): ch = s2[i] for j in range(count): if nodeList[j].letter == ch: break val2 += m * nodeList[j].value m *= 10 m = 1 #find number for the third string for i in range(len(s3) - 1, -1, -1): ch = s3[i] for j in range(count): if nodeList[j].letter == ch: break val3 += m * nodeList[j].value m *= 10 #check whether the sum is the same as the 3rd string or not if val3 == (val1 + val2): return 1 return 0 def permutation(self, count, nodeList, n, s1, s2, s3): #when values are assigned if n == count - 1: for i in range(10): #for those numbers, which are not used if self.use[i] == 0: #assign value i nodeList[n].value = i if self.isValid(nodeList, count, s1, s2, s3) == 1: print("Solution found:", end='') #print code, which is assigned for j in range(count): print(f" {nodeList[j].letter} = {nodeList[j].value}", end='') return 1 return 0 for i in range(10): #for those numbers, which are not used if self.use[i] == 0: #assign value i and mark as not available for future use nodeList[n].value = i self.use[i] = 1 if self.permutation(count, nodeList, n + 1, s1, s2, s3) == 1: #go for the next characters return 1 #when backtracking, make available again self.use[i] = 0 return 0 def solvePuzzle(self, s1, s2, s3): #Number of unique characters uniqueChar = 0 len1 = len(s1) len2 = len(s2) len3 = len(s3) #There are 26 different characters freq = [0] * 26 for i in range(len1): freq[ord(s1[i]) - ord('A')] += 1 for i in range(len2): freq[ord(s2[i]) - ord('A')] += 1 for i in range(len3): freq[ord(s3[i]) - ord('A')] += 1 for i in range(26): #whose frequency is > 0, they are present if freq[i] > 0: uniqueChar += 1 #as there are 10 digits in the decimal system if uniqueChar > 10: print("Invalid strings") return 0 nodeList = [self.Node() for _ in range(uniqueChar)] j = 0 for i in range(26): #assign all characters found in three strings if freq[i] > 0: nodeList[j].letter = chr(i + ord('A')) j += 1 return self.permutation(uniqueChar, nodeList, 0, s1, s2, s3) if __name__ == "__main__": main = Main() s1 = "BASE" s2 = "BALL" s3 = "GAMES" if main.solvePuzzle(s1, s2, s3) == 0: print("No solution")
Output
Solution found: A = 4 B = 2 E = 1 G = 0 L = 5 M = 9 S = 6