本題核心思想:**字母順序無關時,將字符串排序作為「指紋」比較**。通過預處理字典構建有序索引,實現高效異構詞查找。
****** 結束),隨後多個查詢單詞兩單詞字母重排等價 ⇔ 排序後字符串相同
"listen" → 排序 → "eilnst"
"silent" → 排序 → "eilnst"
→ 判定為字母重排關係
word[i] (原詞) 和 sorted[i] (指紋)ss 的指紋:qsort(s, len, sizeof(char), cmp_char)sorted[i] == s_fingerprintword[i] (原詞,非排序後):()#include
#include
#include
#define MAX_WORDS 2000
#define MAX_LEN 10
char word[MAX_WORDS][MAX_LEN];
char sorted[MAX_WORDS][MAX_LEN];
int n = 0;
// 字符比較:用於 qsort 排序單字符
int cmp_char(const void* a, const void* b) {
return *(char*)a - *(char*)b;
}
// 字符串比較:用於 qsort 排序字典
int cmp_str(const void* a, const void* b) {
return strcmp((char*)a, (char*)b);
}
int main() {
// 1. 讀入字典
while (scanf("%s", word[n]) == 1) {
if (word[n][0] == '*') break; // 結束標記
n++;
}
// 2. 字典按字典序排序 (保證輸出順序)
qsort(word, n, sizeof(word[0]), cmp_str);
// 3. 計算每個單詞的指紋
for (int i = 0; i < n; i++) {
strcpy(sorted[i], word[i]);
qsort(sorted[i], strlen(sorted[i]), sizeof(char), cmp_char);
}
// 4. 處理查詢
char query[MAX_LEN];
while (scanf("%s", query) == 1) {
// 計算查詢詞指紋
qsort(query, strlen(query), sizeof(char), cmp_char);
int found = 0;
for (int i = 0; i < n; i++) {
if (strcmp(sorted[i], query) == 0) {
if (!found) found = 1;
printf("%s ", word[i]); // 輸出原詞
}
}
if (!found) printf(":(");
printf("\n");
}
return 0;
}
| 技術點 | 說明 |
|---|---|
qsort 通用排序 | stdlib.h 提供,O(n log n),比冒泡快得多 |
| 比較函數 | cmp_char 接收 const void*,轉換後比較字符值 |
| 指紋預計算 | 避免每次查詢重複排序字典詞,時間換空間 |
| 雙重排序 | 字典排序保證輸出序;字符排序產生指紋 |
| 輸出原詞 | 題目要求輸出字典原始單詞,非排序後形式 |
O(n log n × L + n × L log L) (字典排序 + 指紋計算),L ≤ 6O(L log L + n × L) (查詢排序 + 線性掃描)O(n × L)L ≤ 6, n ≤ 2000,極其高效若字典極大 (如 10 萬詞),線性掃描過慢,可構建:
// 映射:指紋 → 原詞列表 (鏈表/動態數組)
HashMap>
// 查詢:計算指紋 → O(1) 定位列表 → 直接輸出
// 需實現哈希表或使用 uthash / C++ unordered_map
輸入:
listen
silent
enlist
google
goo
*
listen
silent
abc
輸出:
listen silent enlist
listen silent enlist
:(
****** (六個星號),非單個 *tolower%s 讀取以空白分隔的詞,自動處理換行「排序標準化」是處理順序無關等價關係的通用技巧:**將無序結構映射為有序標準形式**,轉化為精確匹配問題。本題展示了預處理 + 指紋匹配的經典模式,適用於異構詞、同構圖、多集合相等等場景。掌握 qsort 靈活運用、比較函數編寫、預計算權衡,是算法競賽基本功。