把单词按九键键盘映射成数字串,顺序扫描字典筛选出等于目标编号的单词。
OJ: roj
题目 ID: 2006
难度:入门
标签:模拟字符串
创建: 2026-10-01 02:27
更新: 2026-10-06 09:19
题目描述
经典九键电话键盘(不含 Q、Z):2 ABC / 3 DEF / 4 GHI / 5 JKL / 6 MNO / 7 PRS / 8 TUV / 9 WXY。
输入前部是字典中的大写单词(按字典序,少于 5000 个),最后一行是长度 1~12 的编号;输出所有按键映射后等于该编号的单词,每行一个,无解输出 NONE。
样例输入 4734,样例输出 GREG。
思路
字母到数字的映射是唯一的,所以不必从数字反向枚举字母,只需顺序扫描字典,把每个等长单词翻译成数字串并与编号比较。字典本身有序,输出天然按字典序。
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 02:27
# update_at: 2026-10-04 11:16
import sys
# 九宫格键盘字符到数字的映射(不包含 Q 和 Z)
CHAR_TO_DIGIT = str.maketrans("ABCDEFGHIJKLMNOPRSTUVWXY", "222333444555666777888999")
def word_to_number(word: str) -> str:
"""将英文名字转换为九宫格按键数字串。"""
return word.translate(CHAR_TO_DIGIT)
def find_matching_names(words: list[str], target: str) -> list[str]:
"""从字典单词列表中筛选出与目标数字匹配的所有名字。"""
return [w for w in words if len(w) == len(target) and word_to_number(w) == target]
def solve() -> None:
data = iter(sys.stdin.read().split())
# 输入前部为字典名字列表,最后一个词为目标数字串:
# 顺序消费时先拿首词当目标,之后每读到新词,就把旧目标降级为字典词
target = next(data, "")
if not target:
return
words: list[str] = []
for token in data:
words.append(target)
target = token
matches = find_matching_names(words, target)
print("\n".join(matches) if matches else "NONE")
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-06 09:19
* update_at: 2026-10-06 09:19
*/
#include <iostream>
#include <string>
using namespace std;
typedef long long ll;
const int MAXN = 5005; // 字典中单词数量的上限
const int MAXL = 32; // 单个单词与数字串的最大长度
string words[MAXN]; // 字典中的单词,输入时按字典序给出
char words_len[MAXN]; // 每个单词的长度,避免反复调用 size()
char digit_of[128]; // digit_of[ch] = 字母 ch 对应的按键数字字符
// 把单词的每个字母翻译成按键数字,结果写入 buf 并返回长度。
int word_to_digits(const string &w, char *buf) {
int len = w.size();
for (int i = 0; i < len; i++) {
buf[i] = digit_of[(int)w[i]];
}
return len;
}
int main() {
// 建立字母到按键数字的映射(Q 与 Z 不在键盘上)
const char *letters = "ABCDEFGHIJKLMNOPRSTUVWXY";
const char *digits = "222333444555666777888999";
for (int i = 0; letters[i] != '\0'; i++) {
digit_of[(int)letters[i]] = digits[i];
}
// 输入前部是字典单词,最后一个串是目标数字串
int word_cnt = 0;
string target;
string token;
if (!(cin >> target)) {
return 0; // 空输入不输出
}
while (cin >> token) {
words[word_cnt] = target;
words_len[word_cnt] = target.size();
word_cnt++;
target = token;
}
int target_len = target.size();
char buf[MAXL];
bool found = false;
// 字典本身按字典序排列,顺序扫描得到的答案天然有序
for (int i = 0; i < word_cnt; i++) {
if (words_len[i] != target_len) {
continue;
}
int len = word_to_digits(words[i], buf);
bool same = true;
for (int j = 0; j < len; j++) {
if (buf[j] != target[j]) {
same = false;
break;
}
}
if (same) {
cout << words[i] << "\n";
found = true;
}
}
if (!found) {
cout << "NONE" << "\n";
}
return 0;
}