题解
因为一共只有10种可能的数字[0-9],所以等式中包含的所有的字符最多包含10种,我们只需要枚举每一种字符对应到每一种数字,得到满足条件的那一个即可,但是要注意,首字符不能为0。
思路非常的简单,但是也要注意,处理不当可能会超时。我们如果直接枚举每一种字符可能对应的数字,然后再根据等式计算结果,这样非常可能超时。可以先进行预处理,求出给定的所有串中出现的字符的出现的次数和出现的位置代表的数字的和,最终将这些和加上就能判断正确结果。最后这一点不好描述,但是代码非常清晰,可以查看代码
// 每一种字符出现的权重
int[] weights = new int[26];
// 哪些字符不能为0
boolean[] notZero = new boolean[26];
public boolean isSolvable(String[] words, String result) {
// 标记字符是否出现过
boolean[] has = new boolean[26];
for (int i = 0; i < words.length; i++) {
int p = 1;
for (int j = words[i].length() - 1; j >= 0; j--) {
has[words[i].charAt(j) - 'A'] = true;
weights[words[i].charAt(j) - 'A'] += p;
p *= 10;
}
notZero[words[i].charAt(0) - 'A'] = true;
}
int p = 1;
for (int i = result.length() - 1; i >= 0; i--) {
has[result.charAt(i) - 'A'] = true;
// 注意这里是负号!!因为这是等式的右边
weights[result.charAt(i) - 'A'] -= p;
p *= 10;
}
notZero[result.charAt(0) - 'A'] = true;
List<Integer> list = new ArrayList<>();
// 获取到所有出现的字符
for (int i = 0; i < 26; i++) {
if (has[i]) {
list.add(i);
}
}
Integer[] ints = list.toArray(new Integer[0]);
return dfs(ints, new boolean[10], 0, 0);
}
public boolean dfs(Integer[] chars, boolean[] vis, int index, int sum) {
if (index == chars.length) {
return sum == 0;
}
for (int i = 0; i < 10; i++) {
if (!vis[i]) {
if (notZero[chars[index]] && i == 0) {
continue;
}
vis[i] = true;
if (dfs(chars, vis, index + 1, sum + i * weights[chars[index]])) {
return true;
}
vis[i] = false;
}
}
return false;
}