給定三個 3 字母字串 num1、num2、result,每字母代表唯一數字 (A-Z 對應 0-9 不重複),首字母不為 0。求滿足 num1 + num2 = result 的合法數字對應總數。例如 "AAA" + "BBB" = "CCC" 返回 32。
num1、num2 可能值,推導 result = num1 + num2num1 + num2 ≤ 999 → num2 ≤ 999 - num1num1 最大 899(當 num2=100 時)Σ(999-i) for i=100..899 = 320,400,遠小於 900×900=810,000將字串字母關係編碼為 3 位掩碼:
// 位 0: pos0==pos1, 位 1: pos0==pos2, 位 2: pos1==pos2
"ABA" → 010 (二進制) = 2
"AAA" → 111 = 7
"ABC" → 000 = 0
預計算三字串掩碼 pattern[3]。枚舉數字時同樣計算掩碼,不匹配即跳過,大幅減少進入精確驗證的候選數。
將三字串視為 3×3 字母矩陣:
Row 0: num1[0] num1[1] num1[2]
Row 1: num2[0] num2[1] num2[2]
Row 2: res[0] res[1] res[2]
建立字母→座標列表映射:letterPos[26] = vector<{row,col}>。僅保留出現過字母的指標陣列 usedLetters。
bool Verify(int n1, int n2, int n3) {
char digits[3][4];
sprintf(digits[0], "%03d", n1);
sprintf(digits[1], "%03d", n2);
sprintf(digits[2], "%03d", n3);
bool used[10] = {false};
for (auto vecPtr : usedLetters) {
auto& vec = *vecPtr;
int d = digits[vec[0].row][vec[0].col] - '0'; // 該字母第一次出現的數字
if (used[d]) return false; // 數字已被其他字母使用
for (size_t i=1; i
class SecretSum {
int pattern[3]; // 三字串字母掩碼
vector> pos[26]; // 字母→座標列表
vector>*> used; // 出現字母指標陣列
void Init(const string& n1, const string& n2, const string& r) {
string s[3] = {n1, n2, r};
memset(pattern, 0, sizeof(pattern));
for (int i=0; i<26; ++i) pos[i].clear();
used.clear();
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
char c = s[i][j];
pos[c-'A'].push_back({char(i), char(j)});
}
// 計算掩碼
if (s[i][0]==s[i][1]) pattern[i] |= 1;
if (s[i][0]==s[i][2]) pattern[i] |= 2;
if (s[i][1]==s[i][2]) pattern[i] |= 4;
}
for (int i=0; i<26; ++i)
if (!pos[i].empty()) used.push_back(&pos[i]);
}
bool MatchPattern(int idx, int num) {
char buf[4]; sprintf(buf, "%03d", num);
int m = 0;
if (buf[0]==buf[1]) m |= 1;
if (buf[0]==buf[2]) m |= 2;
if (buf[1]==buf[2]) m |= 4;
return m == pattern[idx];
}
bool Verify(int n1, int n2, int n3) { /* 上述驗證邏輯 */ }
public:
int countPossible(string n1, string n2, string r) {
Init(n1, n2, r);
int count = 0;
for (int i=100; i<=899; ++i) {
if (!MatchPattern(0, i)) continue;
for (int j=100; j<=999-i; ++j) {
if (!MatchPattern(1, j)) continue;
int k = i + j;
if (!MatchPattern(2, k)) continue;
if (Verify(i, j, k)) ++count;
}
}
return count;
}
};
| 測例 | 模式 | Verify 呼叫次數 | 備註 |
|---|---|---|---|
| Example 5 | 全 000 模式 | 117,662 | 最慢,無字母重複無法預過濾 |
| Example 4 | result=111 | 2,144 | result 掩碼 111 強力過濾 |
優化思路:
bool used[10]
"AAA"+"BBB"="CCC" → 32 ✓
"ABB"+"DEE"="TTT" → 112 ✓
"ABC"+"ABA"="ACC" → 0 ✓
"AAA"+"CDD"="BAA" → 32 ✓
"TEF"+"FET"="AAA" → 12 ✓
"ABC"+"ABC"="BCE" → 5 ✓
"AAA"+"AAA"="BBB" → 4 ✓
本解法採用範圍縮減 + 掩碼預過濾 + 座標映射精確驗證三層策略,將搜尋空間從 81萬壓縮至最差 16萬、典型情況千級。代碼結構清晰、易擴充至任意長度字串(修改矩陣維度即可),展示了組合優化在約束滿足問題中的威力。