整理学生编号(2026.11.01)
2026年最新华为OD机考题库(按考点分类): 2026年最新华为OD机考题库
题目描述
一小学需要把来源各异的学生编号整理成规定的格式后录入系统。
这些初始编号五花八门,可能含有数字、字母、空格与特殊符号:有的符合基本要求,可以整理后使用;有的不符合要求,需要学生重新提供。不符合基本要求的编号一律丢弃,不会出现在输出中。
合法编号(需同时满足以下 5 条):
- 只含数字、英文字母和空格;出现任何其他字符(如
#、-、@)即非法。 - 去掉全部空格后的字符个数 n 满足 1≤n≤6。长度是按去掉空格后计算的,例如
"1234 567"去掉空格后有 7 个字符,非法。 - 去掉空格后,有且仅有 1 个英文字母(大写、小写均可)。
- 去掉空格后,除这个字母外的其余字符全部是数字,并且数字字符至少有 1 个(例如
"Q"只有字母、没有数字,非法)。 - 数字部分不能全为 0,即把这些数字字符当作十进制整数时它必须大于 0(例如
"t000"、"M0000"非法)。
规范化(对每个合法编号依次执行):
- 把其中唯一的字母转成大写,放到编号首位;
- 去掉编号中的全部空格;
- 把数字部分左补
0补齐到 5 位,使整个编号恰好 6 位:1 个大写字母 + 5 位数字。例如"a123"→"A00123","a 001"→"A00001","00a1"→"A00001","a1"→"A00001"。
重复处理:按输入顺序处理每个合法编号。对同一个规范化结果(即「1 个大写字母 + 5 位数字」这个 6 位串),若它是输入中的第 k 次出现(k 从 0 开始计数),则把它的数字部分加上 k×10000(等价于从第二位数字起按「第二位 =104、第三位 =105……」的位权依次累加)作为最终结果:
- 若有 3 个都规范化为
"A00001"的编号,则依次得到"A00001"、"A10001"、"A20001"; - 若
"B99999"出现了第 2 次,则数字部分变成 99999+10000=109999。
若加上 k×10000 后数字部分 >99999(超过 5 位),该编号被丢弃。k 统计的是该规范化结果在输入中的全部出现次数(包括已经被丢弃的那些),因此一旦某个规范化结果开始被丢弃,它之后的所有出现也都会被丢弃。
输出:把所有保留下来的编号按字典序升序排列后输出(每个编号都是「1 个大写字母 + 5 位数字」,长度相同,所以字典序等价于先比较字母、再比较后 5 位数字);若一个都没有保留,输出空数组 []。
输入描述
输入只有一行,是一个 JSON 风格的字符串数组,表示待整理的初始学生编号,格式为:
["s0","s1",...,"s(X-1)"]
即整行用方括号包裹,元素之间用半角逗号 , 分隔,每个元素用半角双引号包裹,逗号后没有空格。
- 元素内部可以包含空格(例如
"a 001"),空格是元素的正常字符,请原样读入。 - 本题数据不含需要转义的字符(不会出现双引号与反斜杠),直接按引号成对提取元素即可。
- 元素可能含有数字、英文字母、空格与特殊符号。
取值范围:
- 1≤X≤80,其中 X 为编号个数(数组长度);
- 0<L≤10,其中 L 为单个原始编号的长度(含其中的空格)。
输出描述
输出一行,形如 ["A00123","C00101"]:字符串带半角双引号,元素之间用半角逗号分隔、逗号后无空格;保留下来的编号按字典序升序排列。若没有任何编号被保留,输出空数组 []。
用例输入 1
["a123","1C01","dd123","t000"]
用例输出 1
["A00123","C00101"]
用例解释 1
"a123"合法,整理为"A00123";"1C01"合法,整理为"C00101";"dd123"不符合「有且仅有 1 个字母」的要求,丢弃;"t000"不符合「数字不能全是 0」的要求,丢弃。
剩下的两个编号按字典序升序排列即为输出。
用例输入 2
["a 001","00a1","001a","B99999","b99999"]
用例输出 2
["A00001","A10001","A20001","B99999"]
用例解释 2
"a 001"、"00a1"、"001a"去掉空格后都只有字母a与数字001,规范化结果都是"A00001";按输入顺序它们是第 1、2、3 个,数字部分依次加 0、10000、20000,得到"A00001"、"A10001"、"A20001";"B99999"规范化后是"B99999",数字部分为 99999≤99999,保留;"b99999"规范化后同样是"B99999",它是第 2 次出现,数字部分变成 99999+10000=109999>99999,超出 5 位,丢弃。
用例输入 3
["a00 1","a0011","0001 b"," 00c2","d00001","e1234568"]
用例输出 3
["A00001","A00011","B00001","C00002","D00001"]
用例解释 3
"a00 1"去掉空格是"a001",规范化后"A00001";"a0011"规范化后"A00011"(数字部分 11,补到 5 位是00011);"0001 b"去掉空格是"0001b",规范化后"B00001";" 00c2"去掉空格是"00c2",规范化后"C00002";"d00001"去掉空格后长度恰为 6,规范化后"D00001";"e1234568"去掉空格后长度为 8,超过 6,不满足长度要求,丢弃。
这五个编号的规范化结果互不相同,按字典序升序排列即为输出。
来源
本题来源于网络、非官方材料、仅供学习交流,侵删
🧠 解题思路
第一步:按 5 条规则过滤非法编号
对每个原始字符串依次检查,有一条不满足就直接丢弃:
- 遍历原串,只能有英文字母、数字、空格,出现
#、-等其他字符即非法; - 把空格全部去掉,得到紧缩串 s,检查长度是否在 1~6 之间(注意长度按去掉空格后算);
- 统计 s 里英文字母的个数,必须恰好 1 个;
- 剩下的字符必须全是数字,且至少有 1 个数字;
- 把数字部分转成整数 num,必须 > 0(全为 0 如
t000非法)。
第二步:规范化成 6 位标准串
合法编号里那唯一的字母转成大写放到最前面,数字 num 左边补 0 补足 5 位,拼成形如 A00001 的 6 位标准串 key。例如 "a 001"、"00a1"、"001a" 字母都是 a、数字值都是 1,规范化后都是 "A00001"。
第三步:用哈希表处理重复
同一个标准串 key 可能出现多次。用哈希表 count[key] 记录 key 此前已经出现过几次(即题目说的 k,从 0 开始):
- 先取出
k = count.get(key, 0),并立刻把count[key]加 1; - 新的数字部分为
final_num = num + k * 10000(相当于万位上加 k); - 若
final_num > 99999(超过 5 位),这个编号丢弃;否则拼成大写字母 + 5位final_num加入保留列表。
注意 count[key] 必须在判断是否超过 99999 之前自增,因为题目规定被丢弃的也占一次出现;其实一旦某次超过 99999,后面的 k 更大,也必然全部超过。
第四步:排序输出
把所有保留下来的 6 位编号按字典序升序排列即可。
用样例 1 和样例 2 走一遍
样例 1:["a123","1C01","dd123","t000"]
| 原串 | 去空格 | 校验 | 规范化 key | k | 结果 |
|---|---|---|---|---|---|
"a123" | "a123" | 1 个字母 a,数字 123 > 0 | A00123 | 0 | A00123 |
"1C01" | "1C01" | 1 个字母 C,数字 101 > 0 | C00101 | 0 | C00101 |
"dd123" | "dd123" | 2 个字母,非法 | — | — | 丢弃 |
"t000" | "t000" | 数字为 0,非法 | — | — | 丢弃 |
排序后输出 ["A00123","C00101"]。
样例 2:["a 001","00a1","001a","B99999","b99999"]
- 前三个规范化都是
A00001,k 依次为 0、1、2,数字部分变成 1、10001、20001,得到A00001、A10001、A20001; "B99999"和"b99999"规范化都是B99999:第一次 k = 0 保留为B99999;第二次 k = 1,99999 + 10000 = 109999 > 99999,丢弃。
输出 ["A00001","A10001","A20001","B99999"]。
⚠️ 易错点
- 长度 1~6 是按去掉空格后计算的,不是原始长度(如
"a00 1"原始长 5、去空格长 4,合法;"e1234568"去空格长 8,非法)。 - 字母个数必须恰为 1,两个字母或没有字母都非法。
- 数字部分不能全为 0,且至少要有 1 个数字(如单独一个
"Q"非法)。 "00a1"中字母前后的数字连起来是"001",转整数为 1,规范化是A00001。- 加上 k × 10000 后超过 99999 的要丢弃,不能输出 6 位数字。
- 输出需要按字典序升序排序。
⏱️ 复杂度
时间复杂度:O(X · L + M log M),其中 X ≤ 80 为编号个数,L ≤ 10 为单个编号长度,M 为保留编号个数。
空间复杂度:O(X),用于哈希表与结果数组。
💻 参考代码(Java)
import java.util.*;
class Solution {
public String[] cleanStudentIds(String[] ids) {
// count 记录每个规范化结果已出现的次数 k
Map<String, Integer> count = new HashMap<>();
List<String> kept = new ArrayList<>();
for (String raw : ids) {
// 规则1:只允许数字、字母、空格
boolean ok = true;
for (int i = 0; i < raw.length(); i++) {
char ch = raw.charAt(i);
if (!(isLetter(ch) || isDigit(ch) || ch == ' ')) {
ok = false;
break;
}
}
if (!ok) continue;
// 去掉全部空格
StringBuilder sb = new StringBuilder();
for (int i = 0; i < raw.length(); i++) {
char ch = raw.charAt(i);
if (ch != ' ') sb.append(ch);
}
String s = sb.toString();
// 规则2:去空格后长度 1..6
if (s.length() < 1 || s.length() > 6) continue;
// 规则3:有且仅有一个字母
int letterCnt = 0;
char letter = 0;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isLetter(ch)) {
letterCnt++;
letter = ch;
}
}
if (letterCnt != 1) continue;
// 规则4:其余全是数字且至少一个数字
StringBuilder db = new StringBuilder();
boolean valid = true;
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (isLetter(ch)) continue;
if (!isDigit(ch)) {
valid = false;
break;
}
db.append(ch);
}
if (!valid || db.length() == 0) continue;
// 规则5:数字部分不能全为 0
int num = Integer.parseInt(db.toString());
if (num <= 0) continue;
// 规范化:大写字母 + 5 位数字
char up = Character.toUpperCase(letter);
String numStr = String.format("%05d", num);
String key = up + numStr;
int k = count.getOrDefault(key, 0);
count.put(key, k + 1);
// 核心转移:数字部分加上 k*10000,超过 99999 丢弃
int finalNum = num + k * 10000;
if (finalNum > 99999) continue;
kept.add(up + String.format("%05d", finalNum));
}
// 按字典序升序输出
Collections.sort(kept);
return kept.toArray(new String[0]);
}
// 题目只允许英文字母和阿拉伯数字;Character.isLetter/isDigit 会把 é、中、全角数字也算进来
private static boolean isLetter(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
private static boolean isDigit(char ch) {
return ch >= '0' && ch <= '9';
}
}
💻 参考代码(C++)
class Solution {
public:
vector<string> cleanStudentIds(vector<string> ids) {
// count 记录每个规范化结果已出现的次数 k
map<string, int> count;
vector<string> kept;
for (string raw : ids) {
// 规则1:只允许数字、字母、空格
bool ok = true;
for (char ch : raw) {
if (!(isalnum((unsigned char)ch) || ch == ' ')) {
ok = false;
break;
}
}
if (!ok) continue;
// 去掉全部空格
string s;
for (char ch : raw) {
if (ch != ' ') s += ch;
}
// 规则2:去空格后长度 1..6
if (s.size() < 1 || s.size() > 6) continue;
// 规则3:有且仅有一个字母
int letterCnt = 0;
char letter = 0;
for (char ch : s) {
if (isalpha((unsigned char)ch)) {
letterCnt++;
letter = ch;
}
}
if (letterCnt != 1) continue;
// 规则4:其余全是数字且至少一个数字
string digits;
bool valid = true;
for (char ch : s) {
if (isalpha((unsigned char)ch)) continue;
if (!isdigit((unsigned char)ch)) {
valid = false;
break;
}
digits += ch;
}
if (!valid || digits.empty()) continue;
// 规则5:数字部分不能全为 0
int num = stoi(digits);
if (num <= 0) continue;
// 规范化:大写字母 + 5 位数字
char up = toupper((unsigned char)letter);
string numStr = to_string(num);
while (numStr.size() < 5) numStr = "0" + numStr;
string key = string(1, up) + numStr;
int k = count[key];
count[key] = k + 1;
// 核心转移:数字部分加上 k*10000,超过 99999 丢弃
int finalNum = num + k * 10000;
if (finalNum > 99999) continue;
string fstr = to_string(finalNum);
while (fstr.size() < 5) fstr = "0" + fstr;
kept.push_back(string(1, up) + fstr);
}
// 按字典序升序输出
sort(kept.begin(), kept.end());
return kept;
}
};
💻 参考代码(Python)
class Solution:
def cleanStudentIds(self, ids):
def is_letter(ch):
return ('a' <= ch <= 'z') or ('A' <= ch <= 'Z')
def is_digit(ch):
return '0' <= ch <= '9'
def pad5(num):
s = str(num)
while len(s) < 5:
s = '0' + s
return s
# count 记录每个规范化结果已出现的次数 k
count = {}
kept = []
for raw in ids:
# 规则1:只允许数字、字母、空格
ok = True
for ch in raw:
if not (is_letter(ch) or is_digit(ch) or ch == ' '):
ok = False
break
if not ok:
continue
# 去掉全部空格
s = ''
for ch in raw:
if ch != ' ':
s += ch
# 规则2:去空格后长度 1..6
if len(s) < 1 or len(s) > 6:
continue
# 规则3:有且仅有一个字母
letter = ''
letter_cnt = 0
for ch in s:
if is_letter(ch):
letter_cnt += 1
letter = ch
if letter_cnt != 1:
continue
# 规则4:其余全是数字且至少一个数字
digits = ''
valid = True
for ch in s:
if is_letter(ch):
continue
if not is_digit(ch):
valid = False
break
digits += ch
if not valid or len(digits) < 1:
continue
# 规则5:数字部分不能全为 0
num = int(digits)
if num <= 0:
continue
# 规范化:大写字母 + 5 位数字
key = letter.upper() + pad5(num)
k = count.get(key, 0)
count[key] = k + 1
# 核心转移:数字部分加上 k*10000,超过 99999 丢弃
final_num = num + k * 10000
if final_num > 99999:
continue
kept.append(letter.upper() + pad5(final_num))
# 按字典序升序输出
kept.sort()
return kept
💻 参考代码(JavaScript)
class Solution {
cleanStudentIds(ids) {
// count 记录每个规范化结果已出现的次数 k
const count = new Map();
const kept = [];
for (const raw of ids) {
// 规则1:只允许数字、字母、空格
let ok = true;
for (const ch of raw) {
if (!(/[0-9a-zA-Z]/.test(ch) || ch === ' ')) {
ok = false;
break;
}
}
if (!ok) continue;
// 去掉全部空格
let s = '';
for (const ch of raw) {
if (ch !== ' ') s += ch;
}
// 规则2:去空格后长度 1..6
if (s.length < 1 || s.length > 6) continue;
// 规则3:有且仅有一个字母
let letterCnt = 0;
let letter = '';
for (const ch of s) {
if (/[a-zA-Z]/.test(ch)) {
letterCnt++;
letter = ch;
}
}
if (letterCnt !== 1) continue;
// 规则4:其余全是数字且至少一个数字
let digits = '';
let valid = true;
for (const ch of s) {
if (/[a-zA-Z]/.test(ch)) continue;
if (!/[0-9]/.test(ch)) {
valid = false;
break;
}
digits += ch;
}
if (!valid || digits.length < 1) continue;
// 规则5:数字部分不能全为 0
const num = parseInt(digits, 10);
if (num <= 0) continue;
// 规范化:大写字母 + 5 位数字
const up = letter.toUpperCase();
const key = up + String(num).padStart(5, '0');
const k = count.get(key) || 0;
count.set(key, k + 1);
// 核心转移:数字部分加上 k*10000,超过 99999 丢弃
const finalNum = num + k * 10000;
if (finalNum > 99999) continue;
kept.push(up + String(finalNum).padStart(5, '0'));
}
// 按字典序升序输出
kept.sort();
return kept;
}
}
module.exports = Solution;
29万+



被折叠的 条评论
为什么被折叠?



