【2024年华为OD机试】 (B卷,100分)- 敏感字段加密(Java JS PythonC/C++)
一、问题描述
题目描述
给定一个由多个命令字组成的命令字符串:
- 字符串长度小于等于 127 字节,只包含大小写字母、数字、下划线和偶数个双引号;
- 命令字之间以一个或多个下划线
_
进行分割; - 可以通过两个双引号
""
来标识包含下划线_
的命令字或空命令字(仅包含两个双引号的命令字),双引号不会在命令字内部出现。
请对指定索引的敏感字段进行加密,替换为 ******
(6 个 *
),并删除命令字前后多余的下划线 _
。
如果无法找到指定索引的命令字,输出字符串 ERROR
。
输入描述
输入为两行:
- 第一行为命令字索引
K
(从 0 开始); - 第二行为命令字符串
S
。
输出描述
输出处理后的命令字符串。如果无法找到指定索引的命令字,输出字符串 ERROR
。
用例
用例 1
输入:
1
password__a12345678_timeout_100
输出:
password_******_timeout_100
说明:
- 命令字符串被分割为
["password", "a12345678", "timeout", "100"]
。 - 索引
1
对应的命令字是a12345678
,替换为******
。 - 最终输出为
password_******_timeout_100
。
用例 2
输入:
2
aaa_password_"a12_45678"_timeout__100_""_
输出:
aaa_password_******_timeout_100_""
说明:
- 命令字符串被分割为
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
。 - 过滤掉空串后为
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
。 - 索引
2
对应的命令字是"a12_45678"
,替换为******
。 - 最终输出为
aaa_password_******_timeout_100_""
。
题目解析
问题分析
我们需要处理一个命令字符串,将其分割为多个命令字,并对指定索引的命令字进行加密。命令字之间通过下划线 _
分割,但包含在双引号 ""
中的下划线 _
是命令字的一部分,而不是分隔符。
解题思路
-
分割命令字符串:
- 使用栈结构来遍历字符串,逐个字符处理。
- 遇到下划线
_
时,判断是否是命令字分隔符:- 如果栈底是双引号
"
,则当前下划线是命令字的一部分,保留。 - 否则,当前下划线是分隔符,将栈中的内容作为一个命令字保存,并清空栈。
- 如果栈底是双引号
- 遇到双引号
"
时,判断是否是命令字的开始或结束:- 如果栈为空,则当前双引号是命令字的开始。
- 否则,当前双引号是命令字的结束,将栈中的内容作为一个命令字保存,并清空栈。
- 其他字符直接压入栈中。
-
过滤空命令字:
- 分割后的命令字列表中可能包含空字符串,需要过滤掉。
-
加密指定索引的命令字:
- 如果指定索引超出命令字列表的范围,输出
ERROR
。 - 否则,将指定索引的命令字替换为
******
。
- 如果指定索引超出命令字列表的范围,输出
-
拼接最终结果:
- 将处理后的命令字列表用下划线
_
连接,形成最终的输出字符串。
- 将处理后的命令字列表用下划线
关键点
- 栈的使用:通过栈结构可以灵活处理包含在双引号中的下划线。
- 双引号的处理:双引号用于标识包含下划线的命令字或空命令字。
- 空命令字的过滤:分割后的命令字列表中可能包含空字符串,需要过滤掉。
示例解析
示例 1
输入:
1
password__a12345678_timeout_100
处理过程:
- 分割命令字符串:
["password", "a12345678", "timeout", "100"]
- 加密索引
1
的命令字:["password", "******", "timeout", "100"]
- 拼接结果:
password_******_timeout_100
示例 2
输入:
2
aaa_password_"a12_45678"_timeout__100_""_
处理过程:
- 分割命令字符串:
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
- 过滤空命令字:
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
- 加密索引
2
的命令字:["aaa", "password", "******", "timeout", "100", "\"\""]
- 拼接结果:
aaa_password_******_timeout_100_""
总结
通过栈结构可以有效地处理包含双引号的命令字符串,确保下划线在双引号内不被误认为分隔符。过滤空命令字后,对指定索引的命令字进行加密,最终拼接为处理后的字符串。
二、JavaScript算法源码
代码详细注释与讲解
1. 输入获取
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const lines = [];
rl.on("line", (line) => {
lines.push(line);
if (lines.length === 2) {
const k = parseInt(lines[0]); // 解析命令字索引 K
const s = lines[1]; // 获取命令字符串 S
console.log(encryptSensitive(s, k)); // 调用核心逻辑并输出结果
lines.length = 0; // 清空输入缓存
}
});
- 功能:从控制台读取输入并解析为命令字索引
K
和命令字符串S
。 - 关键点:
readline
模块用于逐行读取输入。lines
数组用于存储输入的两行数据。- 当输入行数为 2 时,解析
K
和S
,并调用核心逻辑函数encryptSensitive
。
2. 核心逻辑
function encryptSensitive(s, k) {
let stack = []; // 用于存储当前命令字的字符
let result = []; // 用于存储所有命令字
for (let i = 0; i < s.length; i++) {
if (s[i] === "_" && stack[0] !== '"') {
// 如果当前字符是下划线且栈底不是双引号,则说明是分隔符
result.push(stack.join("")); // 将栈中的字符拼接为命令字并存入结果
stack.length = 0; // 清空栈
} else if (s[i] === '"' && stack.length !== 0) {
// 如果当前字符是双引号且栈不为空,则说明是命令字的结束
result.push(stack.join("") + '"'); // 将栈中的字符拼接为命令字并存入结果
stack.length = 0; // 清空栈
} else {
// 其他字符直接压入栈中
stack.push(s[i]);
}
}
if (stack.length) result.push(stack.join("")); // 处理最后一个命令字
result = result.filter((ele) => ele !== ""); // 过滤掉空命令字
if (k > result.length - 1) return "ERROR"; // 如果索引超出范围,返回 ERROR
result[k] = "******"; // 加密指定索引的命令字
return result.join("_"); // 将命令字用下划线连接并返回
}
- 功能:对命令字符串进行处理,加密指定索引的命令字。
- 关键点:
- 栈的使用:
stack
用于存储当前命令字的字符。- 当遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入
result
。
- 命令字分割:
- 如果当前字符是下划线
_
且栈底不是双引号"
,则说明是分隔符。 - 如果当前字符是双引号
"
且栈不为空,则说明是命令字的结束。
- 如果当前字符是下划线
- 过滤空命令字:
- 使用
filter
方法过滤掉空字符串。
- 使用
- 索引检查:
- 如果索引
k
超出命令字列表的范围,返回ERROR
。
- 如果索引
- 加密命令字:
- 将指定索引的命令字替换为
******
。
- 将指定索引的命令字替换为
- 拼接结果:
- 使用
join("_")
将命令字用下划线连接并返回。
- 使用
- 栈的使用:
代码逻辑总结
-
输入处理:
- 从控制台读取输入并解析为命令字索引
K
和命令字符串S
。
- 从控制台读取输入并解析为命令字索引
-
命令字分割:
- 使用栈结构遍历字符串,逐个字符处理。
- 遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入结果列表。
-
过滤空命令字:
- 过滤掉结果列表中的空字符串。
-
索引检查与加密:
- 如果索引
K
超出范围,返回ERROR
。 - 否则,将指定索引的命令字替换为
******
。
- 如果索引
-
拼接结果:
- 将处理后的命令字列表用下划线
_
连接并返回。
- 将处理后的命令字列表用下划线
示例运行
输入 1:
1
password__a12345678_timeout_100
输出 1:
password_******_timeout_100
解释:
- 命令字符串被分割为
["password", "a12345678", "timeout", "100"]
。 - 索引
1
对应的命令字是a12345678
,替换为******
。 - 最终输出为
password_******_timeout_100
。
输入 2:
2
aaa_password_"a12_45678"_timeout__100_""_
输出 2:
aaa_password_******_timeout_100_""
解释:
- 命令字符串被分割为
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
。 - 过滤掉空串后为
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
。 - 索引
2
对应的命令字是"a12_45678"
,替换为******
。 - 最终输出为
aaa_password_******_timeout_100_""
。
总结
- 通过栈结构可以有效地处理包含双引号的命令字符串,确保下划线在双引号内不被误认为分隔符。
- 过滤空命令字后,对指定索引的命令字进行加密,最终拼接为处理后的字符串。
- 代码逻辑清晰,易于理解和扩展。
三、Java算法源码
代码详细注释与讲解
以下是代码的逐行注释和逻辑讲解:
1. 输入获取
Scanner sc = new Scanner(System.in);
int k = Integer.parseInt(sc.nextLine()); // 读取命令字索引 K
String s = sc.nextLine(); // 读取命令字符串 S
System.out.println(getResult(k, s)); // 调用核心逻辑并输出结果
- 功能:从控制台读取输入并解析为命令字索引
K
和命令字符串S
。 - 关键点:
Scanner
用于读取输入。sc.nextLine()
读取一行输入。Integer.parseInt
将字符串转换为整数。
2. 核心逻辑
public static String getResult(int k, String s) {
StringBuilder stack = new StringBuilder(); // 用于存储当前命令字的字符
LinkedList<String> result = new LinkedList<>(); // 用于存储所有命令字
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == '_' && (stack.length() == 0 || stack.charAt(0) != '"')) {
// 如果当前字符是下划线且栈为空或栈底不是双引号,则说明是分隔符
result.add(stack.toString()); // 将栈中的字符拼接为命令字并存入结果
stack = new StringBuilder(); // 清空栈
} else if (c == '"' && stack.length() != 0) {
// 如果当前字符是双引号且栈不为空,则说明是命令字的结束
stack.append('"'); // 将双引号加入栈中
result.add(stack.toString()); // 将栈中的字符拼接为命令字并存入结果
stack = new StringBuilder(); // 清空栈
} else {
// 其他字符直接加入栈中
stack.append(c);
}
}
if (stack.length() > 0) result.add(stack.toString()); // 处理最后一个命令字
// 过滤掉空命令字
List<String> ans = result.stream().filter(str -> !"".equals(str)).collect(Collectors.toList());
if (k > ans.size() - 1) return "ERROR"; // 如果索引超出范围,返回 ERROR
ans.set(k, "******"); // 加密指定索引的命令字
// 将命令字用下划线连接并返回
StringJoiner sj = new StringJoiner("_");
for (String an : ans) sj.add(an);
return sj.toString();
}
- 功能:对命令字符串进行处理,加密指定索引的命令字。
- 关键点:
- 栈的使用:
StringBuilder
用于存储当前命令字的字符。- 当遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入
result
。
- 命令字分割:
- 如果当前字符是下划线
_
且栈为空或栈底不是双引号"
,则说明是分隔符。 - 如果当前字符是双引号
"
且栈不为空,则说明是命令字的结束。
- 如果当前字符是下划线
- 过滤空命令字:
- 使用
filter
方法过滤掉空字符串。
- 使用
- 索引检查:
- 如果索引
k
超出命令字列表的范围,返回ERROR
。
- 如果索引
- 加密命令字:
- 将指定索引的命令字替换为
******
。
- 将指定索引的命令字替换为
- 拼接结果:
- 使用
StringJoiner
将命令字用下划线_
连接并返回。
- 使用
- 栈的使用:
代码逻辑总结
-
输入处理:
- 从控制台读取输入并解析为命令字索引
K
和命令字符串S
。
- 从控制台读取输入并解析为命令字索引
-
命令字分割:
- 使用
StringBuilder
遍历字符串,逐个字符处理。 - 遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入结果列表。
- 使用
-
过滤空命令字:
- 过滤掉结果列表中的空字符串。
-
索引检查与加密:
- 如果索引
K
超出范围,返回ERROR
。 - 否则,将指定索引的命令字替换为
******
。
- 如果索引
-
拼接结果:
- 使用
StringJoiner
将处理后的命令字列表用下划线_
连接并返回。
- 使用
示例运行
输入 1:
1
password__a12345678_timeout_100
输出 1:
password_******_timeout_100
解释:
- 命令字符串被分割为
["password", "a12345678", "timeout", "100"]
。 - 索引
1
对应的命令字是a12345678
,替换为******
。 - 最终输出为
password_******_timeout_100
。
输入 2:
2
aaa_password_"a12_45678"_timeout__100_""_
输出 2:
aaa_password_******_timeout_100_""
解释:
- 命令字符串被分割为
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
。 - 过滤掉空串后为
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
。 - 索引
2
对应的命令字是"a12_45678"
,替换为******
。 - 最终输出为
aaa_password_******_timeout_100_""
。
总结
- 通过
StringBuilder
和LinkedList
可以有效地处理包含双引号的命令字符串,确保下划线在双引号内不被误认为分隔符。 - 过滤空命令字后,对指定索引的命令字进行加密,最终拼接为处理后的字符串。
- 代码逻辑清晰,易于理解和扩展。
四、Python算法源码
代码详细注释与讲解
以下是代码的逐行注释和逻辑讲解:
1. 输入获取
k = int(input()) # 读取命令字索引 K
s = input() # 读取命令字符串 S
- 功能:从控制台读取输入并解析为命令字索引
K
和命令字符串S
。 - 关键点:
input()
用于读取一行输入。int()
将字符串转换为整数。
2. 核心逻辑
def getResult(k, s):
stack = [] # 用于存储当前命令字的字符
res = [] # 用于存储所有命令字
for c in s:
if c == '_' and (len(stack) == 0 or stack[0] != '"'):
# 如果当前字符是下划线且栈为空或栈底不是双引号,则说明是分隔符
res.append("".join(stack)) # 将栈中的字符拼接为命令字并存入结果
stack = [] # 清空栈
elif c == '"' and len(stack) != 0:
# 如果当前字符是双引号且栈不为空,则说明是命令字的结束
stack.append(c) # 将双引号加入栈中
res.append("".join(stack)) # 将栈中的字符拼接为命令字并存入结果
stack = [] # 清空栈
else:
# 其他字符直接加入栈中
stack.append(c)
if len(stack) > 0:
res.append("".join(stack)) # 处理最后一个命令字
# 过滤掉空命令字
ans = list(filter(lambda x: x != "", res))
if k > len(ans) - 1:
return "ERROR" # 如果索引超出范围,返回 ERROR
ans[k] = "******" # 加密指定索引的命令字
return "_".join(ans) # 将命令字用下划线连接并返回
- 功能:对命令字符串进行处理,加密指定索引的命令字。
- 关键点:
- 栈的使用:
stack
用于存储当前命令字的字符。- 当遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入
res
。
- 命令字分割:
- 如果当前字符是下划线
_
且栈为空或栈底不是双引号"
,则说明是分隔符。 - 如果当前字符是双引号
"
且栈不为空,则说明是命令字的结束。
- 如果当前字符是下划线
- 过滤空命令字:
- 使用
filter
方法过滤掉空字符串。
- 使用
- 索引检查:
- 如果索引
k
超出命令字列表的范围,返回ERROR
。
- 如果索引
- 加密命令字:
- 将指定索引的命令字替换为
******
。
- 将指定索引的命令字替换为
- 拼接结果:
- 使用
join("_")
将命令字用下划线_
连接并返回。
- 使用
- 栈的使用:
代码逻辑总结
-
输入处理:
- 从控制台读取输入并解析为命令字索引
K
和命令字符串S
。
- 从控制台读取输入并解析为命令字索引
-
命令字分割:
- 使用栈结构遍历字符串,逐个字符处理。
- 遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入结果列表。
-
过滤空命令字:
- 过滤掉结果列表中的空字符串。
-
索引检查与加密:
- 如果索引
K
超出范围,返回ERROR
。 - 否则,将指定索引的命令字替换为
******
。
- 如果索引
-
拼接结果:
- 将处理后的命令字列表用下划线
_
连接并返回。
- 将处理后的命令字列表用下划线
示例运行
输入 1:
1
password__a12345678_timeout_100
输出 1:
password_******_timeout_100
解释:
- 命令字符串被分割为
["password", "a12345678", "timeout", "100"]
。 - 索引
1
对应的命令字是a12345678
,替换为******
。 - 最终输出为
password_******_timeout_100
。
输入 2:
2
aaa_password_"a12_45678"_timeout__100_""_
输出 2:
aaa_password_******_timeout_100_""
解释:
- 命令字符串被分割为
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
。 - 过滤掉空串后为
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
。 - 索引
2
对应的命令字是"a12_45678"
,替换为******
。 - 最终输出为
aaa_password_******_timeout_100_""
。
总结
- 通过栈结构可以有效地处理包含双引号的命令字符串,确保下划线在双引号内不被误认为分隔符。
- 过滤空命令字后,对指定索引的命令字进行加密,最终拼接为处理后的字符串。
- 代码逻辑清晰,易于理解和扩展。
五、C/C++算法源码:
以下是代码的 C++ 和 C 语言实现,并附带详细的中文注释和讲解。
C++ 实现
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
// 核心逻辑函数
string getResult(int k, const string& s) {
vector<char> stack; // 用于存储当前命令字的字符
vector<string> res; // 用于存储所有命令字
for (char c : s) {
if (c == '_' && (stack.empty() || stack[0] != '"')) {
// 如果当前字符是下划线且栈为空或栈底不是双引号,则说明是分隔符
res.push_back(string(stack.begin(), stack.end())); // 将栈中的字符拼接为命令字并存入结果
stack.clear(); // 清空栈
} else if (c == '"' && !stack.empty()) {
// 如果当前字符是双引号且栈不为空,则说明是命令字的结束
stack.push_back(c); // 将双引号加入栈中
res.push_back(string(stack.begin(), stack.end())); // 将栈中的字符拼接为命令字并存入结果
stack.clear(); // 清空栈
} else {
// 其他字符直接加入栈中
stack.push_back(c);
}
}
// 处理最后一个命令字
if (!stack.empty()) {
res.push_back(string(stack.begin(), stack.end()));
}
// 过滤掉空命令字
vector<string> ans;
for (const string& str : res) {
if (!str.empty()) {
ans.push_back(str);
}
}
// 如果索引超出范围,返回 ERROR
if (k > ans.size() - 1) {
return "ERROR";
}
// 加密指定索引的命令字
ans[k] = "******";
// 将命令字用下划线连接并返回
string result;
for (size_t i = 0; i < ans.size(); i++) {
if (i != 0) {
result += "_";
}
result += ans[i];
}
return result;
}
int main() {
int k;
string s;
// 读取输入
cin >> k;
cin.ignore(); // 忽略换行符
getline(cin, s);
// 调用核心逻辑并输出结果
cout << getResult(k, s) << endl;
return 0;
}
C 语言实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1000
// 核心逻辑函数
char* getResult(int k, const char* s) {
char stack[MAX_SIZE]; // 用于存储当前命令字的字符
int stackSize = 0; // 栈的大小
char* res[MAX_SIZE]; // 用于存储所有命令字
int resSize = 0; // 结果数组的大小
for (int i = 0; s[i] != '\0'; i++) {
char c = s[i];
if (c == '_' && (stackSize == 0 || stack[0] != '"')) {
// 如果当前字符是下划线且栈为空或栈底不是双引号,则说明是分隔符
stack[stackSize] = '\0'; // 添加字符串结束符
res[resSize] = (char*)malloc((stackSize + 1) * sizeof(char));
strcpy(res[resSize], stack); // 将栈中的字符拼接为命令字并存入结果
resSize++;
stackSize = 0; // 清空栈
} else if (c == '"' && stackSize != 0) {
// 如果当前字符是双引号且栈不为空,则说明是命令字的结束
stack[stackSize++] = c; // 将双引号加入栈中
stack[stackSize] = '\0'; // 添加字符串结束符
res[resSize] = (char*)malloc((stackSize + 1) * sizeof(char));
strcpy(res[resSize], stack); // 将栈中的字符拼接为命令字并存入结果
resSize++;
stackSize = 0; // 清空栈
} else {
// 其他字符直接加入栈中
stack[stackSize++] = c;
}
}
// 处理最后一个命令字
if (stackSize > 0) {
stack[stackSize] = '\0'; // 添加字符串结束符
res[resSize] = (char*)malloc((stackSize + 1) * sizeof(char));
strcpy(res[resSize], stack); // 将栈中的字符拼接为命令字并存入结果
resSize++;
}
// 过滤掉空命令字
char* ans[MAX_SIZE];
int ansSize = 0;
for (int i = 0; i < resSize; i++) {
if (strlen(res[i]) > 0) {
ans[ansSize++] = res[i];
} else {
free(res[i]); // 释放空字符串的内存
}
}
// 如果索引超出范围,返回 ERROR
if (k > ansSize - 1) {
for (int i = 0; i < ansSize; i++) {
free(ans[i]); // 释放内存
}
return "ERROR";
}
// 加密指定索引的命令字
free(ans[k]); // 释放原命令字的内存
ans[k] = (char*)malloc(7 * sizeof(char));
strcpy(ans[k], "******");
// 将命令字用下划线连接并返回
char* result = (char*)malloc(MAX_SIZE * sizeof(char));
result[0] = '\0'; // 初始化结果字符串
for (int i = 0; i < ansSize; i++) {
if (i != 0) {
strcat(result, "_");
}
strcat(result, ans[i]);
}
// 释放内存
for (int i = 0; i < ansSize; i++) {
free(ans[i]);
}
return result;
}
int main() {
int k;
char s[MAX_SIZE];
// 读取输入
scanf("%d", &k);
getchar(); // 忽略换行符
fgets(s, MAX_SIZE, stdin);
s[strcspn(s, "\n")] = '\0'; // 去掉换行符
// 调用核心逻辑并输出结果
char* result = getResult(k, s);
printf("%s\n", result);
// 释放内存
free(result);
return 0;
}
代码详细注释与讲解
1. 输入获取
- C++:
- 使用
cin
读取命令字索引k
和命令字符串s
。 cin.ignore()
用于忽略换行符。
- 使用
- C:
- 使用
scanf
读取命令字索引k
。 - 使用
fgets
读取命令字符串s
,并去掉换行符。
- 使用
2. 核心逻辑
- 栈的使用:
- 使用栈结构遍历字符串,逐个字符处理。
- 当遇到分隔符或双引号时,将栈中的字符拼接为命令字并存入结果列表。
- 命令字分割:
- 如果当前字符是下划线
_
且栈为空或栈底不是双引号"
,则说明是分隔符。 - 如果当前字符是双引号
"
且栈不为空,则说明是命令字的结束。
- 如果当前字符是下划线
- 过滤空命令字:
- 过滤掉结果列表中的空字符串。
- 索引检查与加密:
- 如果索引
k
超出范围,返回ERROR
。 - 否则,将指定索引的命令字替换为
******
。
- 如果索引
- 拼接结果:
- 将处理后的命令字列表用下划线
_
连接并返回。
- 将处理后的命令字列表用下划线
3. 内存管理
- C++:
- 使用
vector
和string
自动管理内存。
- 使用
- C:
- 使用
malloc
和free
手动管理内存,避免内存泄漏。
- 使用
示例运行
输入 1:
1
password__a12345678_timeout_100
输出 1:
password_******_timeout_100
解释:
- 命令字符串被分割为
["password", "a12345678", "timeout", "100"]
。 - 索引
1
对应的命令字是a12345678
,替换为******
。 - 最终输出为
password_******_timeout_100
。
输入 2:
2
aaa_password_"a12_45678"_timeout__100_""_
输出 2:
aaa_password_******_timeout_100_""
解释:
- 命令字符串被分割为
["aaa", "password", "\"a12_45678\"", "timeout", "", "100", "\"\"", ""]
。 - 过滤掉空串后为
["aaa", "password", "\"a12_45678\"", "timeout", "100", "\"\""]
。 - 索引
2
对应的命令字是"a12_45678"
,替换为******
。 - 最终输出为
aaa_password_******_timeout_100_""
。
总结
- C++ 和 C 的实现逻辑一致,主要区别在于输入处理和内存管理。
- C++ 使用
vector
和string
简化了数组和字符串的操作。 - C 使用数组和指针手动处理字符串分割和内存管理。
- 代码通过栈结构可以有效地处理包含双引号的命令字符串,确保下划线在双引号内不被误认为分隔符。
六、尾言
什么是华为OD?
华为OD(Outsourcing Developer,外包开发工程师)是华为针对软件开发工程师岗位的一种招聘形式,主要包括笔试、技术面试以及综合面试等环节。尤其在笔试部分,算法题的机试至关重要。
为什么刷题很重要?
-
机试是进入技术面的第一关:
华为OD机试(常被称为机考)主要考察算法和编程能力。只有通过机试,才能进入后续的技术面试环节。 -
技术面试需要手撕代码:
技术一面和二面通常会涉及现场编写代码或算法题。面试官会注重考察候选人的思路清晰度、代码规范性以及解决问题的能力。因此提前刷题、多练习是通过面试的重要保障。 -
入职后的可信考试:
入职华为后,还需要通过“可信考试”。可信考试分为三个等级:- 入门级:主要考察基础算法与编程能力。
- 工作级:更贴近实际业务需求,可能涉及复杂的算法或与工作内容相关的场景题目。
- 专业级:最高等级,考察深层次的算法以及优化能力,与薪资直接挂钩。
刷题策略与说明:
2024年8月14日之后,华为OD机试的题库转为 E卷,由往年题库(D卷、A卷、B卷、C卷)和全新题目组成。刷题时可以参考以下策略:
-
关注历年真题:
- 题库中的旧题占比较大,建议优先刷历年的A卷、B卷、C卷、D卷题目。
- 对于每道题目,建议深度理解其解题思路、代码实现,以及相关算法的适用场景。
-
适应新题目:
- E卷中包含全新题目,需要掌握全面的算法知识和一定的灵活应对能力。
- 建议关注新的刷题平台或交流群,获取最新题目的解析和动态。
-
掌握常见算法:
华为OD考试通常涉及以下算法和数据结构:- 排序算法(快速排序、归并排序等)
- 动态规划(背包问题、最长公共子序列等)
- 贪心算法
- 栈、队列、链表的操作
- 图论(最短路径、最小生成树等)
- 滑动窗口、双指针算法
-
保持编程规范:
- 注重代码的可读性和注释的清晰度。
- 熟练使用常见编程语言,如C++、Java、Python等。
如何获取资源?
-
官方参考:
- 华为招聘官网或相关的招聘平台会有一些参考信息。
- 华为OD的相关公众号可能也会发布相关的刷题资料或学习资源。
-
加入刷题社区:
- 找到可信的刷题交流群,与其他备考的小伙伴交流经验。
- 关注知名的刷题网站,如LeetCode、牛客网等,这些平台上有许多华为OD的历年真题和解析。
-
寻找系统性的教程:
- 学习一本经典的算法书籍,例如《算法导论》《剑指Offer》《编程之美》等。
- 完成系统的学习课程,例如数据结构与算法的在线课程。
积极心态与持续努力:
刷题的过程可能会比较枯燥,但它能够显著提升编程能力和算法思维。无论是为了通过华为OD的招聘考试,还是为了未来的职业发展,这些积累都会成为重要的财富。
考试注意细节
-
本地编写代码
- 在本地 IDE(如 VS Code、PyCharm 等)上编写、保存和调试代码,确保逻辑正确后再复制粘贴到考试页面。这样可以减少语法错误,提高代码准确性。
-
调整心态,保持冷静
- 遇到提示不足或实现不确定的问题时,不必慌张,可以采用更简单或更有把握的方法替代,确保思路清晰。
-
输入输出完整性
- 注意训练和考试时都需要编写完整的输入输出代码,尤其是和题目示例保持一致。完成代码后务必及时调试,确保功能符合要求。
-
快捷键使用
- 删除行可用
Ctrl+D
,复制、粘贴和撤销分别为Ctrl+C
,Ctrl+V
,Ctrl+Z
,这些可以正常使用。 - 避免使用
Ctrl+S
,以免触发浏览器的保存功能。
- 删除行可用
-
浏览器要求
- 使用最新版的 Google Chrome 浏览器完成考试,确保摄像头开启并正常工作。考试期间不要切换到其他网站,以免影响考试成绩。
-
交卷相关
- 答题前,务必仔细查看题目示例,避免遗漏要求。
- 每完成一道题后,点击【保存并调试】按钮,多次保存和调试是允许的,系统会记录得分最高的一次结果。完成所有题目后,点击【提交本题型】按钮。
- 确保在考试结束前提交试卷,避免因未保存或调试失误而丢分。
-
时间和分数安排
- 总时间:150 分钟;总分:400 分。
- 试卷结构:2 道一星难度题(每题 100 分),1 道二星难度题(200 分)。及格分为 150 分。合理分配时间,优先完成自己擅长的题目。
-
考试环境准备
- 考试前请备好草稿纸和笔。考试中尽量避免离开座位,确保监控画面正常。
- 如需上厕所,请提前规划好时间以减少中途离开监控的可能性。
-
技术问题处理
- 如果考试中遇到断电、断网、死机等技术问题,可以关闭浏览器并重新打开试卷链接继续作答。
- 出现其他问题,请第一时间联系 HR 或监考人员进行反馈。
祝你考试顺利,取得理想成绩!