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]andresultare 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 <= 51 <= words[i].length, result.length <= 7words[i], resultcontains only upper case English letters.- Number of different characters used on the expression is at most 10.
Related Topics:
Math, Backtracking
Try to map the characters from right to left so that we can check the validity along the way.
Assume the maximum length of result or words[i] is L, and words is of length W.
There are L! permutations. For each permutation, we need to check validity. Checking validity takes O(LW). We check validity when each new character is mapped, so we check L times for a permutation.
So overall the time complexity is O(L! * L^2 * W).
// OJ: https://leetcode.com/problems/verbal-arithmetic-puzzle/
// Author: github.com/lzl124631x
// Time: O(L! * L^2 * W)
// Space: O(L)
class Solution {
unordered_map<char, int> m; // map from char to the corresponding integer
vector<char> chs; // chars to consider, right most chars are first considered.
unordered_set<char> leading; // leading chars can't be zero
int used[10] = {}; // digit `i` is used if `used[i] == 1`
bool valid(vector<string>& words, string result) { // check if the current map `m` is valid
int sum = 0;
for (int i = 0; i < result.size(); ++i) {
for (auto &w : words) {
if (i >= w.size()) continue;
char c = w[w.size() - i - 1];
if (m.count(c) == 0) return true;
sum += m[c];
}
char c = result[result.size() - i - 1];
if (m.count(c) == 0) return true;
sum -= m[c];
if (sum % 10) return false;
sum /= 10;
}
return true;
}
bool dfs(vector<string>& words, string result, int index) {
if (index == chs.size()) return true;
for (int i = 0; i < 10; ++i) {
if (used[i] || (i == 0 && leading.count(chs[index]))) continue;
used[i] = 1;
m[chs[index]] = i;
if (valid(words, result) && dfs(words, result, index + 1)) return true;
m.erase(chs[index]);
used[i] = 0;
}
return false;
}
void addChar(char ch) {
for (char c : chs) {
if (c == ch) return;
}
chs.push_back(ch);
}
public:
bool isSolvable(vector<string>& words, string result) {
for (auto &w : words) {
if (w.size() > result.size()) return false;
if (w.size() > 1) leading.insert(w[0]);
}
if (result.size() > 1) leading.insert(result[0]);
for (int i = 0; i < result.size(); ++i) {
for (auto &w : words) {
if (i < w.size()) addChar(w[w.size() - i - 1]);
}
addChar(result[result.size() - i - 1]);
}
return dfs(words, result, 0);
}
};