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]
andresult
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, result.length <= 7
words[i], result
contains 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);
}
};