Skip to content

Prepare For Coder Interview – Denny

  • Basic
  • Medium
  • Hard
  • Architect
  • Life

LeetCode: Verbal Arithmetic Puzzle

Posted on August 5, 2019July 26, 2020 by braindenny

Verbal Arithmetic Puzzle



Similar Problems:

  • CheatSheet: Leetcode For Code Interview
  • CheatSheet: Common Code Problems & Follow-ups
  • Tag: #manydetails, #backtracking

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

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

  • Each character is decoded as one digit (0 – 9).
  • Every pair of different characters they must map to different digits.
  • Each words[i] and result are decoded as one number without leading zeros.
  • Sum of numbers on left side (words) will equal to the number on 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 = ["THIS","IS","TOO"], result = "FUNNY"
Output: true

Example 4:

Input: words = ["LEET","CODE"], result = "POINT"
Output: false

Constraints:

  • 2 <= words.length <= 5
  • 1 <= words[i].length, results.length <= 7
  • words[i], result contains only upper case English letters.
  • Number of different characters used on the expression is at most 10.

Github: code.dennyzhang.com

Credits To: leetcode.com

Leave me comments, if you have better ways to solve.


  • Solution:
// https://code.dennyzhang.com/verbal-arithmetic-puzzle
// Basic Ideas: backtracking
//
// From right to left
//   Reverse strings
//   DNES
//   EROM
//   YENOM
// Complexity: Time ? Space ?
func reverse(str string) string {
    bytes := []byte(str)
    left, right := 0, len(bytes)-1
    for left<right {
        bytes[left], bytes[right] = bytes[right], bytes[left]
        left++
        right--
    }
    return string(bytes)
}

// Add wordIndex to simplify the backtracking
func dfs(pos int, wordIndex int, mappings map[byte]int, words []string, result string, carry int, values *[]bool) bool {
    if pos == len(result) {
        // collect result
        for _, w := range words {
            if len(w) > pos {
                return false
            }
        }
        return carry==0
    }
    if wordIndex == len(words) {
        // Need to move to next column
        v := carry
        for _, w := range words {
            if pos < len(w) {
                v += mappings[w[pos]]
            }
        }
        // If result[pos] not assigned, there would be only one case
        ch := result[pos]
        if _, ok := mappings[ch]; !ok || mappings[ch] == -1 {
            // leading 0
            if pos == len(result)-1 && v%10 == 0 {
                return false
            }
            // already taken
            if (*values)[v%10] {
                return false
            }
            (*values)[v%10] = true
            mappings[ch] = v%10
            res := dfs(pos, wordIndex, mappings, words, result, carry, values)
            // backtracking
            (*values)[v%10] = false
            mappings[ch] = -1
            return res
        }
        if v%10 == mappings[ch] {
            return dfs(pos+1, 0, mappings, words, result, v/10, values)
        }
    } else {
        // The same column but next word
        if len(words[wordIndex]) <= pos {
            return dfs(pos, wordIndex+1, mappings, words, result, carry, values)
        } else {
            ch := words[wordIndex][pos]
            if _, ok := mappings[ch]; ok && mappings[ch] != -1 {
                return dfs(pos, wordIndex+1, mappings, words, result, carry, values)
            } else {
                // assign values
                for i:=0; i<10; i++ {
                    if !(*values)[i] {
                        // avoid leading characters
                        if i == 0 && pos == len(words[wordIndex])-1 {
                            continue
                        }
                        (*values)[i] = true
                        mappings[ch] = i

                        if dfs(pos, wordIndex+1, mappings, words, result, carry, values) {
                            return true
                        }
                        (*values)[i] = false
                        mappings[ch] = -1
                    }
                }
            }
        }
    }
    return false
}

func isSolvable(words []string, result string) bool {
    result = reverse(result)
    for i, w := range words {
        words[i] = reverse(w)
    }
    mappings := map[byte]int{}
    values := make([]bool, 10)
    return dfs(0, 0, mappings, words, result, 0, &values)
}
linkedin
github
slack

Post Views: 0
Posted in MediumTagged #backtracking, #manydetails, redo

Post navigation

LeetCode: Zuma Game
a

Leave a Reply Cancel reply

Your email address will not be published.

Tags

#array #backtracking #bfs #binarytree #bitmanipulation #blog #classic #codetemplate #combination #dfs #dynamicprogramming #game #graph #greedy #heap #inspiring #interval #linkedlist #manydetails #math #palindrome #recursive #slidingwindow #stack #string #subarray #trie #twopointer #twosum binarysearch editdistance hashmap intervaldp knapsack monotone oodesign presum rectangle redo review rotatelist series sql treetraversal unionfind

Recent Posts

  • a
  • a
  • a
  • a
  • a

Recent Comments

    Archives

    Categories

    • Amusing
    • Basic
    • Easy
    • Hard
    • Life
    • Medium
    • Resource
    • Review
    • Series
    • Uncategorized
    Proudly powered by WordPress | Theme: petals by Aurorum.