SecretSum 是 Google 競賽第二輪淘汰賽 500 分題目。給定三個由大寫字母組成的 3 字符串 num1、num2、result,每個字母代表唯一數字(0-9),同字母同數字,不同字母不同數字,且最高位字母不能為 0。求滿足 num1 + num2 = result 的合法數字映射總數。
k 個分配給 k 個字母;#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
class SecretSum {
public:
int countPossible(std::string num1, std::string num2, std::string result) {
// 1. 收集唯一字母
std::string all = num1 + num2 + result;
std::sort(all.begin(), all.end());
all.erase(std::unique(all.begin(), all.end()), all.end());
int n = all.size();
if (n > 10) return 0; // 超過 10 個不同字母不可能
// 2. 字母→索引映射
std::unordered_map<char, int> idx;
for (int i = 0; i < n; ++i) idx[all[i]] = i;
// 3. 標記首字母
std::vector<bool> isLeading(10, false);
isLeading[idx[num1[0]]] = true;
isLeading[idx[num2[0]]] = true;
isLeading[idx[result[0]]] = true;
// 4. 數字陣列 0-9
std::vector<int> digits(10);
std::iota(digits.begin(), digits.end(), 0);
int count = 0;
// 5. 全排列枚舉
do {
// 檢查首字母非零
bool ok = true;
for (int i = 0; i < n; ++i) {
if (isLeading[i] && digits[i] == 0) { ok = false; break; }
}
if (!ok) continue;
// 轉換字符串為數值
auto toVal = [&](const std::string& s) {
int val = 0;
for (char c : s) val = val * 10 + digits[idx[c]];
return val;
};
if (toVal(num1) + toVal(num2) == toVal(result))
++count;
} while (std::next_permutation(digits.begin(), digits.end()));
return count;
}
};
| num1 | num2 | result | 輸出 | 說明 |
|---|---|---|---|---|
| AAA | BBB | CCC | 32 | A+B=C,A,B,C≠0,A≠B≠C |
| ABB | DEE | TTT | 112 | 進位情況較多 |
| ABC | ABA | ACC | 0 | 無解 |
O(10! / (10-n)!) * n,n ≤ 10,最壞 ~360 萬次迭代,極快;O(1)。vector<int> 加速排列生成;do { ... } while(next_permutation) 無需切片。本題核心在於將「字母唯一映射數字」轉化為「數字全排列分配給字母」,利用 STL next_permutation 簡潔實現完整搜索,是典型的「暴力可行」競賽題範例。