专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。
一、题目描述
小明是核心网工程师,客户交给小明一个任务:给定一个网络配置列表,每个配置是一个字符串,仅有数字和"*“、”?"符号组成。
输入用户的IMSI(国际移动用户识别码),根据以下规则生成配置列表:
"*"匹配0个或多个任意字符。
"?“匹配下标为奇数的单个字符,比如123?中的”?"可以匹配123456789012345下标为3的字符’4’,下标从0开始。
二、输入描述
输入第一行为网络配置列表,列表中的每个配置由数字和*、?组成的字符串,每个字符串中*不超过一个,?若干,网络配置列表长度小于200,每个字符串以英文逗号隔开。
输入第二行为用户的IMSI(国际移动用户识别码),仅有数字组成,长度等于15。
备注
确保输入格式正确,无需考虑格式错误。
三、输出描述
输出为满足匹配规则的配置字符串列表,列表按照字典序升序输出,每个字符串以英文逗号隔开。若没有满足条件的配置,则返回字符串"null"。
四、测试用例
测试用例1:
1、输入
1234567,1234567*
123456789012345
2、输出
1234567*
3、说明
1234567长度不够无法匹配15位IMSI,1234567中的可以匹配剩余的89012345
测试用例2:
1、输入
123???345,123???*???345
123456789012345
2、输出
null
3、说明
123???345有16个字符,超过IMSI的15位
123???*???345中的?需要匹配奇数位置,但位置不对应
五、解题思路
1、主要解题思路
- 使用递归的方式实现配置字符串与IMSI的匹配
- 对于每个配置中的字符,根据其类型(数字、*、?)采用不同的匹配策略
- 特别处理*的回溯匹配,尝试匹配0个到多个字符
- ?只能匹配IMSI中下标为奇数位置的字符
2、数据结构:
ArrayList:存储所有匹配成功的配置字符串
String数组:存储分割后的配置列表
递归调用栈:用于回溯匹配
3、算法:
递归回溯算法:处理*的多种匹配可能性
字符串匹配算法:逐字符比对配置和IMSI
六、Python算法源码
def is_match(config, imsi):
"""
判断配置是否能匹配IMSI
:param config: 配置字符串
:param imsi: IMSI字符串
:return: 是否匹配
"""
return match(config, 0, imsi, 0)
def match(config, c_idx, imsi, i_idx):
"""
递归匹配函数
:param config: 配置字符串
:param c_idx: 配置字符串当前索引
:param imsi: IMSI字符串
:param i_idx: IMSI字符串当前索引
:return: 是否匹配
"""
# 如果配置字符串已经遍历完
if c_idx == len(config):
# 检查IMSI是否也遍历完
return i_idx == len(imsi)
# 获取当前配置字符
c = config[c_idx]
# 如果是*,尝试匹配0个或多个字符
if c == '*':
# 尝试匹配0个字符
if match(config, c_idx + 1, imsi, i_idx):
return True
# 尝试匹配1个或多个字符
for i in range(i_idx, len(imsi)):
if match(config, c_idx + 1, imsi, i + 1):
return True
return False
# 如果IMSI已经遍历完,但配置还有非*字符
if i_idx >= len(imsi):
return False
# 如果是?,检查是否在奇数位置
if c == '?':
# 只有在IMSI的奇数位置才能匹配
if i_idx % 2 == 1:
return match(config, c_idx + 1, imsi, i_idx + 1)
else:
return False
# 如果是数字,必须完全匹配
if c == imsi[i_idx]:
return match(config, c_idx + 1, imsi, i_idx + 1)
return False
def main():
# 读取网络配置列表
config_line = input()
configs = config_line.split(',')
# 读取IMSI
imsi = input()
# 存储匹配成功的配置
matched_configs = []
# 遍历每个配置进行匹配
for config in configs:
if is_match(config, imsi):
matched_configs.append(config)
# 如果没有匹配的配置,输出null
if not matched_configs:
print("null")
else:
# 按字典序排序
matched_configs.sort()
# 输出结果,用逗号分隔
print(','.join(matched_configs))
if __name__ == "__main__":
main()
七、JavaScript算法源码
const readline = require('readline');
// 创建读取接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 存储输入行
let lines = [];
// 读取输入
rl.on('line', (line) => {
lines.push(line);
if (lines.length === 2) {
// 处理输入
processInput(lines[0], lines[1]);
rl.close();
}
});
/**
* 处理输入并输出结果
* @param {string} configLine - 配置列表字符串
* @param {string} imsi - IMSI字符串
*/
function processInput(configLine, imsi) {
// 分割配置列表
const configs = configLine.split(',');
// 存储匹配成功的配置
const matchedConfigs = [];
// 遍历每个配置进行匹配
for (const config of configs) {
if (isMatch(config, imsi)) {
matchedConfigs.push(config);
}
}
// 如果没有匹配的配置,输出null
if (matchedConfigs.length === 0) {
console.log("null");
} else {
// 按字典序排序
matchedConfigs.sort();
// 输出结果,用逗号分隔
console.log(matchedConfigs.join(','));
}
}
/**
* 判断配置是否能匹配IMSI
* @param {string} config - 配置字符串
* @param {string} imsi - IMSI字符串
* @returns {boolean} - 是否匹配
*/
function isMatch(config, imsi) {
return match(config, 0, imsi, 0);
}
/**
* 递归匹配函数
* @param {string} config - 配置字符串
* @param {number} cIdx - 配置字符串当前索引
* @param {string} imsi - IMSI字符串
* @param {number} iIdx - IMSI字符串当前索引
* @returns {boolean} - 是否匹配
*/
function match(config, cIdx, imsi, iIdx) {
// 如果配置字符串已经遍历完
if (cIdx === config.length) {
// 检查IMSI是否也遍历完
return iIdx === imsi.length;
}
// 获取当前配置字符
const c = config[cIdx];
// 如果是*,尝试匹配0个或多个字符
if (c === '*') {
// 尝试匹配0个字符
if (match(config, cIdx + 1, imsi, iIdx)) {
return true;
}
// 尝试匹配1个或多个字符
for (let i = iIdx; i < imsi.length; i++) {
if (match(config, cIdx + 1, imsi, i + 1)) {
return true;
}
}
return false;
}
// 如果IMSI已经遍历完,但配置还有非*字符
if (iIdx >= imsi.length) {
return false;
}
// 如果是?,检查是否在奇数位置
if (c === '?') {
// 只有在IMSI的奇数位置才能匹配
if (iIdx % 2 === 1) {
return match(config, cIdx + 1, imsi, iIdx + 1);
} else {
return false;
}
}
// 如果是数字,必须完全匹配
if (c === imsi[iIdx]) {
return match(config, cIdx + 1, imsi, iIdx + 1);
}
return false;
}
八、C算法源码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 最大配置长度
#define MAX_CONFIG_LEN 200
// 最大配置数量
#define MAX_CONFIG_COUNT 200
// 函数声明
int match(char* config, int cIdx, char* imsi, int iIdx);
int isMatch(char* config, char* imsi);
int compareStrings(const void* a, const void* b);
/**
* 递归匹配函数
* @param config 配置字符串
* @param cIdx 配置字符串当前索引
* @param imsi IMSI字符串
* @param iIdx IMSI字符串当前索引
* @return 是否匹配 (1: 匹配, 0: 不匹配)
*/
int match(char* config, int cIdx, char* imsi, int iIdx) {
// 如果配置字符串已经遍历完
if (config[cIdx] == '\0') {
// 检查IMSI是否也遍历完
return imsi[iIdx] == '\0';
}
// 获取当前配置字符
char c = config[cIdx];
// 如果是*,尝试匹配0个或多个字符
if (c == '*') {
// 尝试匹配0个字符
if (match(config, cIdx + 1, imsi, iIdx)) {
return 1;
}
// 尝试匹配1个或多个字符
int i;
for (i = iIdx; imsi[i] != '\0'; i++) {
if (match(config, cIdx + 1, imsi, i + 1)) {
return 1;
}
}
return 0;
}
// 如果IMSI已经遍历完,但配置还有非*字符
if (imsi[iIdx] == '\0') {
return 0;
}
// 如果是?,检查是否在奇数位置
if (c == '?') {
// 只有在IMSI的奇数位置才能匹配
if (iIdx % 2 == 1) {
return match(config, cIdx + 1, imsi, iIdx + 1);
} else {
return 0;
}
}
// 如果是数字,必须完全匹配
if (c == imsi[iIdx]) {
return match(config, cIdx + 1, imsi, iIdx + 1);
}
return 0;
}
/**
* 判断配置是否能匹配IMSI
* @param config 配置字符串
* @param imsi IMSI字符串
* @return 是否匹配 (1: 匹配, 0: 不匹配)
*/
int isMatch(char* config, char* imsi) {
return match(config, 0, imsi, 0);
}
/**
* 字符串比较函数,用于排序
*/
int compareStrings(const void* a, const void* b) {
return strcmp(*(char**)a, *(char**)b);
}
int main() {
char configLine[1000]; // 输入的配置行
char imsi[16]; // IMSI (15位 + '\0')
char* configs[MAX_CONFIG_COUNT]; // 配置数组
char* matchedConfigs[MAX_CONFIG_COUNT]; // 匹配的配置数组
int configCount = 0; // 配置数量
int matchedCount = 0; // 匹配的配置数量
// 读取配置行
scanf("%s", configLine);
// 读取IMSI
scanf("%s", imsi);
// 分割配置字符串
char* token = strtok(configLine, ",");
while (token != NULL && configCount < MAX_CONFIG_COUNT) {
// 为每个配置分配内存
configs[configCount] = (char*)malloc(strlen(token) + 1);
strcpy(configs[configCount], token);
configCount++;
token = strtok(NULL, ",");
}
// 遍历每个配置进行匹配
int i;
for (i = 0; i < configCount; i++) {
if (isMatch(configs[i], imsi)) {
matchedConfigs[matchedCount++] = configs[i];
}
}
// 如果没有匹配的配置,输出null
if (matchedCount == 0) {
printf("null\n");
} else {
// 按字典序排序
qsort(matchedConfigs, matchedCount, sizeof(char*), compareStrings);
// 输出结果,用逗号分隔
for (i = 0; i < matchedCount; i++) {
printf("%s", matchedConfigs[i]);
if (i < matchedCount - 1) {
printf(",");
}
}
printf("\n");
}
// 释放内存
for (i = 0; i < configCount; i++) {
free(configs[i]);
}
return 0;
}
九、C++算法源码
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;
/**
* 递归匹配函数
* @param config 配置字符串
* @param cIdx 配置字符串当前索引
* @param imsi IMSI字符串
* @param iIdx IMSI字符串当前索引
* @return 是否匹配
*/
bool match(const string& config, int cIdx, const string& imsi, int iIdx) {
// 如果配置字符串已经遍历完
if (cIdx == config.length()) {
// 检查IMSI是否也遍历完
return iIdx == imsi.length();
}
// 获取当前配置字符
char c = config[cIdx];
// 如果是*,尝试匹配0个或多个字符
if (c == '*') {
// 尝试匹配0个字符
if (match(config, cIdx + 1, imsi, iIdx)) {
return true;
}
// 尝试匹配1个或多个字符
for (int i = iIdx; i < imsi.length(); i++) {
if (match(config, cIdx + 1, imsi, i + 1)) {
return true;
}
}
return false;
}
// 如果IMSI已经遍历完,但配置还有非*字符
if (iIdx >= imsi.length()) {
return false;
}
// 如果是?,检查是否在奇数位置
if (c == '?') {
// 只有在IMSI的奇数位置才能匹配
if (iIdx % 2 == 1) {
return match(config, cIdx + 1, imsi, iIdx + 1);
} else {
return false;
}
}
// 如果是数字,必须完全匹配
if (c == imsi[iIdx]) {
return match(config, cIdx + 1, imsi, iIdx + 1);
}
return false;
}
/**
* 判断配置是否能匹配IMSI
* @param config 配置字符串
* @param imsi IMSI字符串
* @return 是否匹配
*/
bool isMatch(const string& config, const string& imsi) {
return match(config, 0, imsi, 0);
}
/**
* 分割字符串函数
* @param str 要分割的字符串
* @param delimiter 分隔符
* @return 分割后的字符串向量
*/
vector<string> split(const string& str, char delimiter) {
vector<string> tokens;
stringstream ss(str);
string token;
// 使用getline按分隔符分割
while (getline(ss, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
int main() {
string configLine; // 配置行
string imsi; // IMSI
// 读取输入
getline(cin, configLine);
getline(cin, imsi);
// 分割配置字符串
vector<string> configs = split(configLine, ',');
// 存储匹配成功的配置
vector<string> matchedConfigs;
// 遍历每个配置进行匹配
for (const string& config : configs) {
if (isMatch(config, imsi)) {
matchedConfigs.push_back(config);
}
}
// 如果没有匹配的配置,输出null
if (matchedConfigs.empty()) {
cout << "null" << endl;
} else {
// 按字典序排序
sort(matchedConfigs.begin(), matchedConfigs.end());
// 输出结果,用逗号分隔
for (int i = 0; i < matchedConfigs.size(); i++) {
cout << matchedConfigs[i];
if (i < matchedConfigs.size() - 1) {
cout << ",";
}
}
cout << endl;
}
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2025 C卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。