#P3847. 第1题-快递单号录入
-
1000ms
Tried: 69
Accepted: 29
Difficulty: 3
所属公司 :
拼多多
时间 :2025年9月28日
-
算法标签>模拟
第1题-快递单号录入
解题思路
本题要求对单号进行格式与校验位核验,并在必要时修复。单号规则为:前 8 位由“2 位大写字母 + 6 位数字”组成,第 9 位为校验位。校验位的计算算法为:对前 8 位每个字符取 ASCII 码求和,结果对 26 取余,再加上 A 的 ASCII 码,得到的大写字母即为校验位。
核心步骤(字符串处理与取模运算):
- 判断长度是否为 9,否则返回
Invalid。 - 校验前 8 位是否满足格式:
[A-Z]{2}\d{6}。若不满足,返回Invalid。 - 计算期望校验位:
check = chr( (sum(ord(c) for c in s[:8]) % 26) + ord('A') ) - 若实际第 9 位等于期望校验位,返回原串;否则返回“前 8 位 + 期望校验位”。
复杂度分析
- 时间复杂度:只处理固定 9 个字符与常数次运算,记为
O(1)。 - 空间复杂度:只使用常数额外空间,
O(1)。
代码实现
Python
import sys
import re
def fix_code(s: str) -> str:
# 若长度不为 9,直接判定为非法
if len(s) != 9:
return "Invalid"
front8 = s[:8]
# 校验前 8 位是否为 2 大写字母 + 6 数字
if not re.fullmatch(r'[A-Z]{2}\d{6}', front8):
return "Invalid"
# 计算期望校验位:ASCII 和取模 26,再加上 'A'
total = sum(ord(ch) for ch in front8)
expected = chr((total % 26) + ord('A'))
# 比较第 9 位;若错误则修复
return s if s[8] == expected else (front8 + expected)
def main():
s = sys.stdin.readline().strip()
print(fix_code(s))
if __name__ == "__main__":
main()
Java
import java.util.Scanner;
public class Main {
// 核心功能函数:按题意校验并修复
public static String fixCode(String s) {
// 长度必须为 9
if (s.length() != 9) return "Invalid";
String front8 = s.substring(0, 8);
// 校验前 8 位格式:2 位大写字母 + 6 位数字
if (!front8.matches("[A-Z]{2}\\d{6}")) return "Invalid";
// 计算 ASCII 和并取模得到期望校验位
int sum = 0;
for (int i = 0; i < 8; i++) {
sum += (int) front8.charAt(i);
}
char expected = (char) ((sum % 26) + 'A');
// 若第 9 位正确则返回原串,否则返回修复后的结果
return (s.charAt(8) == expected) ? s : (front8 + expected);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
if (!sc.hasNextLine()) {
sc.close();
return;
}
String s = sc.nextLine().trim();
System.out.println(fixCode(s));
sc.close();
}
}
C++
#include <iostream>
#include <string>
using namespace std;
// 按题意校验并修复
string fixCode(const string& s) {
// 长度必须为 9
if (s.size() != 9) return "Invalid";
// 校验前 2 位为大写字母
for (int i = 0; i < 2; ++i) {
char c = s[i];
if (!(c >= 'A' && c <= 'Z')) return "Invalid";
}
// 校验接下来的 6 位为数字
for (int i = 2; i < 8; ++i) {
char c = s[i];
if (!(c >= '0' && c <= '9')) return "Invalid";
}
// 计算前 8 位 ASCII 和
int sum = 0;
for (int i = 0; i < 8; ++i) sum += static_cast<int>(s[i]);
// 期望校验位:和 % 26 + 'A'
char expected = static_cast<char>((sum % 26) + 'A');
// 若第 9 位正确则返回原串,否则返回修复结果
if (s[8] == expected) return s;
return s.substr(0, 8) + expected;
}
int main() {
string s;
if (!getline(cin, s)) return 0;
// 去除可能的结尾换行符(稳妥处理)
while (!s.empty() && (s.back() == '\r' || s.back() == '\n')) s.pop_back();
cout << fixCode(s) << endl;
return 0;
}
题目内容
多多在快递公司负责快递单号录入工作,这些单号有严格的格式要求:
1.快递单号由 3 部分组成:2 位大写字母 (A~Z) +6 位数字 +1 位校验位
2.校验位计算规则:取前 8 位( 2 字母+ 6 数字)中每个字符的 ASCII 码之和,对 26 余后,加上 A 的 ASCII 码,得到的字符即为校验位
现在有一批可能存在校验位错误的单号,请你编写程序:
1.若单号格式正确且校验位正确,返回原单号
2.若前 8 位格式正确但校验位错误,返回修复后(校正校验位)的单号
3.若前 8 位格式错误(非 2 字母 +6 数字)或快递单号不满足格式要求,返回字符串 Invalid
输入描述
共一行,一个字符串 (1<=长度 <=1024 ),表示待校验的快递单号
输出描述
共一行,一个字符串,表示修复后的快递单号,若无法修复则返回字符串 Invalid
样例1
输入
AB123456C
输出
AB123456Y
说明
前 8 位字符:A(ASCII 码 =65)、B(ASCII 码 =66)、1(ASCII 码 =49)、2(ASCII 码 =50)、3(ASCII 码 =51)、4(ASCII 码 =52)、5(ASCII 码 =53)、6(ASCII 码 =54)
总和:65+66+49+50+51+52+53+54=440,440 % 26=24,24+65(A 的 ASCII 码 )=89,对应字符 Y
因此该单号校验位错误,正确单号应为 AB123456Y
样例2
输入
AC123456Z
输出
AC123456Z
说明
前 8 位字符:A(ASCII 码 =65)、C(ASCII 码 =67)、1(ASCII 码 =49)、2(ASCII 码 =50)、3(ASCII 码 =51)、4(ASCII 码 =52)、5(ASCII 码 =53)、6(ASCII 码 =54)
总和:65+67+49+50+51+52+53+54=441,441 % 26=25 ,25+65( A 的
ASCII 码)=90,对应字符 Z
因此该单号校验位正确,直接返回单号 AC123456Z
样例3
输入
AC123M56Z
输出
Invalid
说明
快递单号由 3 部分组成:2 位大写字母 +6 位数字 +1 位大写母校验位,不满足规则,直接返回 Invalid