LeetCode 1307. Verbal Arithmetic Puzzel
原题链接
困难
作者:
JasonSun
,
2020-01-16 06:23:35
,
所有人可见
,
阅读 642
Algorithm (Recursion)
- Let $\Gamma$ denote the set of alphabets in all input words and $eval(\Gamma)$ the corresponding map between the character and integer number.
- Then this question is equivalent to asking us to find if there exits a map $eval$ such that $$
\sum_{i} \sum_{\{\text{ch}, id(\text{ch})\} \in \Gamma \cap \text{word[i]}} 10^{id(\text{ch})}\cdot eval(\text{ch})= 0
$$
- This could be done using backtracking search techcnique or direct recursion.
- There are several pruning techniques that could speed things up. For example one could combine the coefficients and start from the largest one in absolute value. But none of these would reduce the worst case complexity.
Code
class Solution {
public:
bool isSolvable(vector<string>& words, string result) {
#define ALL(x) begin(x), end(x)
using namespace utils::dynamic_bitset;
const auto pow10 = [](array<int, 10> self = {}) {
for (int i = 0; i < 10; i++)
self[i] = (i == 0 ? 1 : self[i - 1] * 10);
return self;
}();
const auto terms = [&](vector<pair<char, int>> self = {}) {
const auto holder = [&] (unordered_map<char, int> self = {}) {
for (const string word : words)
for (int i = 0; i < word.size(); ++i)
self[word[i]] += pow10[size(word) - i - 1];
for (int i = 0; i < result.size(); ++i)
self[result[i]] -= pow10[size(result) - i - 1];
return self;
}();
std::copy(ALL(holder), std::back_inserter(self));
std::sort(ALL(self));
return self;
}();
const auto lead_zero = [&](array<bool, 255> self = {}) {
for (const auto & word : words)
self[word[0]] = true;
if (size(result) > 1)
self[result[0]] = true;
return self;
}();
const int max_result = [&](int acc = 0) {
for (int i = size(result) - 1, h = 9; i >= 0; --i)
acc += pow10[i] * (h--);
return acc;
}();
function<bool(int, int, int)> dfs = [&](int pos, int total, int U) -> bool {
if (pos == size(terms))
return total == 0;
else if (total > max_result)
return false;
else
return [&](bool acc = false) {
const auto [ch, coeff] = terms[pos];
for (int i = lead_zero[ch] ? 1 : 0; i < 10 and acc == false; ++i) {
if (not test(U, i))
acc |= dfs(pos + 1, total + coeff * i, flip(U, i));
}
return acc;
}();
};
return dfs(0, 0, 0);
}
};