Talentd
FleetCode
Make and follow sheets.Sign in

Verbal Arithmetic Puzzle solution and explanation

HardArrayBacktrackingMathString5 min read33.5% acceptanceUpdated 9 Apr 2026
Leetcode 1307: Verbal Arithmetic Puzzle (Leetcode Hard)Algorithms Casts · 35:59 · 5K viewsWatch on YouTube
4 more videos on this problem
  1. Leetcode 1307: Verbal Arithmetic Puzzle (Leetcode Hard)Algorithms Casts · 35:59 · 5K views
  2. 【每日一题】1307. Verbal Arithmetic Puzzle, 12/9/2020Huifeng Guan · 41:53 · 1K views
  3. Leetcode 1307. Verbal Arithmetic PuzzleFearless Learner · 30:51 · 851 views
  4. Live Coding Leetcode 1307: Verbal Arithmetic PuzzleCS Live Coding · 1:15:50 · 371 views
  5. LeetCode 1307: Verbal Arithmetic PuzzleAlitaCode · 34:53 · 64 views

The problem

Given an equation, represented by words on the left side and the result on the right side.

You need to check if the equation is solvable under the following rules:

  • Each character is decoded as one digit (0 - 9).
  • No two characters can map to the same digit.
  • Each words[i] and result are decoded as one number without leading zeros.
  • Sum of numbers on the left side (words) will equal to the number on the right side (result).

Return true if the equation is solvable, otherwise return false.

Example 1:

Input: words = ["SEND","MORE"], result = "MONEY"
Output: true
Explanation: Map 'S'-> 9, 'E'->5, 'N'->6, 'D'->7, 'M'->1, 'O'->0, 'R'->8, 'Y'->'2'
Such that: "SEND" + "MORE" = "MONEY" ,  9567 + 1085 = 10652

Example 2:

Input: words = ["SIX","SEVEN","SEVEN"], result = "TWENTY"
Output: true
Explanation: Map 'S'-> 6, 'I'->5, 'X'->0, 'E'->8, 'V'->7, 'N'->2, 'T'->1, 'W'->'3', 'Y'->4
Such that: "SIX" + "SEVEN" + "SEVEN" = "TWENTY" ,  650 + 68782 + 68782 = 138214

Example 3:

Input: words = ["LEET","CODE"], result = "POINT"
Output: false
Explanation: There is no possible mapping to satisfy the equation, so we return false.
Note that two different characters cannot map to the same digit.

Constraints:

  • 2 <= words.length <= 5
  • 1 <= words[i].length, result.length <= 7
  • words[i], result contain only uppercase English letters.
  • The number of different characters used in the expression is at most 10.

Approach overview

Problem Overview: You are given several words representing numbers where each character maps to a unique digit (0–9). The goal is to determine whether a digit assignment exists such that the sum of the first n‑1 words equals the final word. Leading characters cannot map to zero, and every letter must map to a distinct digit.

Approach 1: Backtracking Search (Exponential, ~O(10!) time, O(1) space)

This approach treats the puzzle as a digit assignment problem. First collect all unique characters across the input words. Then recursively assign digits from 0–9 while maintaining a used set so no digit is reused. After assigning digits to all characters, convert each word into a number and check whether the arithmetic equation holds. The key pruning rule prevents assigning 0 to leading characters. This brute-force backtracking search explores permutations of digits but prunes many invalid states early.

Approach 2: Constraint Satisfaction with Bit Masking (Optimized Backtracking, ~O(10!) worst case, O(1) space)

A more structured solution evaluates the equation column by column from right to left, similar to manual addition. Instead of constructing full numbers, maintain the running column sum and propagate carry values during recursion. A bit mask tracks which digits are already assigned, enabling constant-time digit availability checks. This turns the problem into a constraint satisfaction system where partial assignments are validated immediately. Early pruning dramatically reduces the search space because invalid column sums are discarded before exploring deeper states. This method combines ideas from math, string processing, and constraint-based backtracking.

Recommended for interviews: Start by explaining the basic backtracking permutation idea since it demonstrates understanding of the search space and constraints. Then move to the column-wise constraint approach with bit masking. Interviewers prefer this optimized strategy because it prunes invalid assignments early and models the arithmetic addition directly, which significantly reduces unnecessary recursion.

Approach 1: Backtracking Approach

The backtracking approach involves recursively trying to assign digits to each character ensuring all constraints are met. By assigning digits to characters one by one, we calculate if they sum to the required result, backtracking if an assignment leads to an invalid state.

This solution explores different configurations and checks their validity, making it suitable due to the limited number of possible mappings.

def is_solvable(words, result):
    from itertools import permutations

    unique_chars = list(set(''.join(words) + result))
    if len(unique_chars) > 10:
        return False
    
    first_letters = set(word[0] for word in words + [result])
    
    for perm in permutations(range(10), len(unique_chars)):
        char_to_digit = dict(zip(unique_chars, perm))
        if any(char_to_digit[c] == 0 for c in first_letters):
            continue
        
        words_sum = sum(
            int(''.join(str(char_to_digit[c]) for c in word)) for word in words
        )
        
        result_value = int(''.join(str(char_to_digit[c]) for c in result))
        
        if words_sum == result_value:
            return True
    
    return False
function isSolvable(words, result) {
  const uniqueChars = new Set([...words.join(''), result]);
  if (uniqueChars.size > 10) return false;

  const firstLetters = new Set([result[0], ...words.map(word => word[0])]);
  const allChars = Array.from(uniqueChars);

  function evaluate(mapping) {
    const wordToNumber = word => [...word].reduce((acc, char) => acc * 10 + mapping[char], 0);
    const wordsSum = words.reduce((acc, word) => acc + wordToNumber(word), 0);
    return wordsSum === wordToNumber(result);
  }

  function dfs(pos, used = new Array(10).fill(false), mapping = {}) {
    if (pos === allChars.length) return evaluate(mapping);
    let char = allChars[pos];
    for (let digit = 0; digit <= 9; digit++) {
      if (used[digit] || (digit === 0 && firstLetters.has(char))) continue;
      mapping[char] = digit;
      used[digit] = true;
      if (dfs(pos + 1, used, mapping)) return true;
      used[digit] = false;
      delete mapping[char];
    }
    return false;
  }

  return dfs(0);
}

This function begins by identifying all unique characters present in the words and result. If there are more than 10 unique characters, it's impossible to find a unique digit for each character, so it returns False immediately.

The function goes through all possible permutations of digits for these characters, ensuring no character that leads a word is assigned a zero (to avoid leading zeros). If any permutation yields a valid sum, True is returned. Otherwise, the function returns False after checking all permutations.

Complexity

Time Complexity: O(10^n) where n is the number of unique characters, considering the worst possibility of evaluating all permutations.
Space Complexity: O(1) as transformations exist within constant space primarily bound by auxiliary data structures.

Try this approach in the editor

Approach 2: Constraint Satisfaction with Bit Masking

The bit masking approach iteratively assigns digits to characters using bit masks to represent remaining available digits instead of checking conventional arrays. This method helps speed up operations by reducing assignments overhead and allows faster constraint checks.

import java.util.*;

public class VerbalArithmetic {
    public boolean isSolvable(String[] words, String result) {
        Set<Character> uniqueChars = new HashSet<>();
        for (String word : words) {
            for (char c : word.toCharArray()) uniqueChars.add(c);
        }
        for (char c : result.toCharArray()) uniqueChars.add(c);
        if (uniqueChars.size() > 10) return false;

        List<Character> allChars = new ArrayList<>(uniqueChars);
        int[] charToDigit = new int[256];
        Arrays.fill(charToDigit, -1);

        Set<Integer> usedDigits = new HashSet<>();

        return dfs(0, usedDigits, charToDigit, allChars, words, result);
    }

    private boolean dfs(int pos, Set<Integer> usedDigits, int[] charToDigit, List<Character> allChars, String[] words, String result) {
        if (pos == allChars.size()) {
            return checkSolution(words, result, charToDigit);
        }

        char c = allChars.get(pos);
        for (int digit = 0; digit < 10; digit++) {
            if (!usedDigits.contains(digit)) {
                charToDigit[c] = digit;
                usedDigits.add(digit);

                if (dfs(pos + 1, usedDigits, charToDigit, allChars, words, result)) return true;

                usedDigits.remove(digit);
                charToDigit[c] = -1;
            }
        }
        return false;
    }

    private boolean checkSolution(String[] words, String result, int[] charToDigit) {
        Integer yearSum = Arrays.stream(words).mapToInt(word -> getValue(word, charToDigit)).sum();
        Integer resultValue = getValue(result, charToDigit);
        return yearSum.equals(resultValue);
    }

    private Integer getValue(String word, int[] charToDigit) {
        StringBuilder sb = new StringBuilder();
        for (char c : word.toCharArray()) sb.append(charToDigit[c]);
        return sb.charAt(0) == '0' ? -1 : Integer.parseInt(sb.toString());
    }
}
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;

bool isSolvable(vector<string>& words, string result) {
    unordered_set<char> uniqueChars;
    for (auto &w : words) uniqueChars.insert(w.begin(), w.end());
    uniqueChars.insert(result.begin(), result.end());
    if (uniqueChars.size() > 10) return false;

    vector<char> allChars(uniqueChars.begin(), uniqueChars.end());
    vector<int> charValue(256, -1); 
    vector<bool> usedDigits(10, false);

    auto getDigit = [&](string &word) {
        int num = 0;
        for (char c : word) num = num * 10 + charValue[c];
        return num;
    };

    function<bool(int, int)> dfs = [&](int pos, int mask) {
        if (pos == allChars.size()) {
            int wordSum = 0;
            for (auto &word : words) wordSum += getDigit(word);
            return wordSum == getDigit(result);
        }

        char currentChar = allChars[pos];
        for (int digit = 0; digit <= 9; ++digit) {
            if (mask & (1 << digit)) continue;
            charValue[currentChar] = digit;
            if (dfs(pos + 1, mask | (1 << digit))) return true;
            charValue[currentChar] = -1;
        }
        return false;
    };

    return dfs(0, 0);
}

This Java solution uses DFS with a set of constraints considering both character and digit assignments along with valid transitions among available digits using set storage.
The solution checks configurations against constructed results, ensuring proper checks for digit assignments via DFS and using sets/mapping for constraints. It returns True when matching a valid permutation, otherwise False.

Complexity

Time Complexity: O(10^n) due to recursion through all character permutations;
Space Complexity: O(n), dedicated to recursion depth and character mapping artifacts.

Try this approach in the editor

Complexity comparison

ApproachComplexity
Backtracking Approach

Time Complexity: O(10^n) where n is the number of unique characters, considering the worst possibility of evaluating all permutations.
Space Complexity: O(1) as transformations exist within constant space primarily bound by auxiliary data structures.

Constraint Satisfaction with Bit Masking

Time Complexity: O(10^n) due to recursion through all character permutations;
Space Complexity: O(n), dedicated to recursion depth and character mapping artifacts.

Complexity analysis

ApproachTimeSpaceWhen to Use
Backtracking Digit AssignmentO(10!)O(1)Good starting point to explain brute-force search and permutation generation
Constraint Satisfaction with Bit MaskingO(10!) worst case (heavily pruned)O(1)Preferred approach for interviews and competitive coding due to strong pruning

Frequently asked questions

Is Verbal Arithmetic Puzzle easy or hard?

Verbal Arithmetic Puzzle is classified as a Hard problem because it combines recursion, constraint satisfaction, and arithmetic reasoning. Efficient solutions require careful pruning strategies rather than simple brute-force permutations.

Verbal Arithmetic Puzzle Python/Java solution

Python solutions usually implement recursive backtracking with dictionaries for character-digit mapping. Java and C++ implementations often add bit masking for faster digit availability checks and column-wise constraint validation to reduce unnecessary recursion.

How to solve Verbal Arithmetic Puzzle in O(n)?

An O(n) solution is not possible because the problem requires exploring combinations of digit assignments. The optimal strategy uses backtracking with constraint pruning, which has factorial worst-case complexity but performs well due to early elimination of invalid assignments.

What is the best approach for Verbal Arithmetic Puzzle?

The most effective solution models the puzzle as a constraint satisfaction problem using backtracking with column-wise addition. By processing digits from right to left and validating partial sums with carry values, invalid assignments are pruned early. A bit mask tracks used digits efficiently, reducing the search space compared to naive permutation checks.

Is Verbal Arithmetic Puzzle asked at Google/Amazon/Meta?

Verbal arithmetic and cryptarithm problems frequently appear in interviews at companies like Google and Meta because they test recursion, constraint reasoning, and pruning strategies. Variants of this problem are common in algorithm interviews focused on backtracking and search.

What data structure is used in Verbal Arithmetic Puzzle?

Typical solutions use hash maps or arrays to store character-to-digit mappings, along with a boolean array or bit mask to track used digits. Recursion with backtracking drives the search while enforcing arithmetic constraints.

What is the time complexity of Verbal Arithmetic Puzzle?

The worst-case time complexity is O(10!) because each unique letter may be assigned a different digit from 0–9. In practice, constraints such as leading-zero restrictions and column-wise validation prune most branches, making the search much faster than exploring all permutations.

Comments

Now write it yourselfClose this page and solve Verbal Arithmetic Puzzle in the editor, without looking.
Practise Verbal Arithmetic Puzzle