【2024年华为OD机试】 (B卷,100分)- 响应报文时间(Java JS PythonC/C++)
一、问题描述
题目解析
题目描述
在 IGMP 协议中,有一个字段称为最大响应时间(Max Response Time)。当 HOST 收到查询报文时,解析出 MaxResponseTime
字段后,需要在 (0, MaxResponseTime]
时间(秒)内随机选取一个时间回应一个响应报文。如果在随机时间内收到一个新的查询报文,则会根据两者时间的大小,选取较小的一方刷新回应时间。
最大响应时间的计算方式如下:
- 当
MaxRespCode < 128
时,MaxRespTime = MaxRespCode
。 - 当
MaxRespCode ≥ 128
时,MaxRespTime = (mant | 0x10) << (exp + 3)
,其中:exp
是MaxRespCode
的高 5~7 位。mant
是MaxRespCode
的低 4 位。
现在假设 HOST 收到查询报文时,选取的随机时间必定为最大值。给定 HOST 收到的查询报文个数 C
,每个报文的接收时间 T
和最大响应时间字段值 M
,请计算出 HOST 发送响应报文的时间。
输入描述
- 第一行为查询报文个数
C
。 - 后续每行分别为 HOST 收到报文的时间
T
及最大响应时间M
,以空格分隔。
输出描述
输出 HOST 发送响应报文的时间。
备注
用例确定只会发送一个响应报文,不存在计时结束后依然收到查询报文的情况。
用例
输入
3
0 20
1 10
8 20
输出
11
说明
- 收到 3 个报文:
- 第 0 秒收到第 1 个报文,响应时间为 20 秒,则要到
0 + 20 = 20
秒响应。 - 第 1 秒收到第 2 个报文,响应时间为 10 秒,则要到
1 + 10 = 11
秒响应,与上一个报文的响应时间比较,取较小值11
秒。 - 第 8 秒收到第 3 个报文,响应时间为 20 秒,则要到
8 + 20 = 28
秒响应,与上一个报文的响应时间比较,取较小值11
秒。
- 第 0 秒收到第 1 个报文,响应时间为 20 秒,则要到
- 最终发送响应报文的时间为
11
秒。
输入
2
0 255
200 60
输出
260
说明
- 收到 2 个报文:
- 第 0 秒收到第 1 个报文,响应时间为
255
秒,计算得MaxRespTime = (15 | 0x10) << (7 + 3) = 31744
秒。 - 第 200 秒收到第 2 个报文,响应时间为
60
秒,则要到200 + 60 = 260
秒响应,与上一个报文的响应时间比较,取较小值260
秒。
- 第 0 秒收到第 1 个报文,响应时间为
- 最终发送响应报文的时间为
260
秒。
题目解析
问题分析
-
目标
计算 HOST 发送响应报文的时间,即所有报文中最小的T + MaxRespTime
。 -
关键点
- 每个报文的响应时间为
T + MaxRespTime
。 - 当
MaxRespCode < 128
时,MaxRespTime = MaxRespCode
。 - 当
MaxRespCode ≥ 128
时,MaxRespTime = (mant | 0x10) << (exp + 3)
,其中:exp
是MaxRespCode
的高 5~7 位。mant
是MaxRespCode
的低 4 位。
- 每个报文的响应时间为
-
问题转化
对于每个报文,计算其响应时间,然后取所有响应时间的最小值。
解题思路
-
计算最大响应时间
- 对于每个报文,根据
MaxRespCode
的值计算MaxRespTime
:- 如果
MaxRespCode < 128
,则MaxRespTime = MaxRespCode
。 - 如果
MaxRespCode ≥ 128
,则提取exp
和mant
,并计算MaxRespTime = (mant | 0x10) << (exp + 3)
。
- 如果
- 对于每个报文,根据
-
计算响应时间
- 对于每个报文,响应时间为
T + MaxRespTime
。
- 对于每个报文,响应时间为
-
取最小值
- 遍历所有报文的响应时间,取最小值作为最终结果。
示例分析
输入
3
0 20
1 10
8 20
步骤
- 计算每个报文的响应时间:
- 第 1 个报文:
T = 0
,MaxRespTime = 20
,响应时间为0 + 20 = 20
秒。 - 第 2 个报文:
T = 1
,MaxRespTime = 10
,响应时间为1 + 10 = 11
秒。 - 第 3 个报文:
T = 8
,MaxRespTime = 20
,响应时间为8 + 20 = 28
秒。
- 第 1 个报文:
- 取最小值:
min(20, 11, 28) = 11
秒。 - 输出结果:
11
。
输入
2
0 255
200 60
步骤
- 计算每个报文的响应时间:
- 第 1 个报文:
T = 0
,MaxRespCode = 255
:exp = (255 >> 5) & 0x07 = 7
。mant = 255 & 0x0F = 15
。MaxRespTime = (15 | 0x10) << (7 + 3) = 31744
秒。- 响应时间为
0 + 31744 = 31744
秒。
- 第 2 个报文:
T = 200
,MaxRespTime = 60
,响应时间为200 + 60 = 260
秒。
- 第 1 个报文:
- 取最小值:
min(31744, 260) = 260
秒。 - 输出结果:
260
。
复杂度分析
-
时间复杂度
- 对于每个报文,计算
MaxRespTime
的时间复杂度为O(1)
。 - 遍历所有报文的时间复杂度为
O(C)
,其中C
是报文数量。 - 总时间复杂度为
O(C)
。
- 对于每个报文,计算
-
空间复杂度
- 只需要常数空间存储中间结果。
- 总空间复杂度为
O(1)
。
总结
本题的核心是根据 MaxRespCode
计算每个报文的最大响应时间,然后取所有报文响应时间的最小值。关键在于:
- 根据
MaxRespCode
的值选择不同的计算方式。 - 提取
exp
和mant
并计算MaxRespTime
。 - 时间复杂度为
O(C)
,适合处理C
较大的输入。
二、JavaScript算法源码
这个 JavaScript 代码实现了通过 Node.js 控制台读取输入数据并进行处理,最后输出计算结果。代码的核心在于接收输入数据后,通过 getResult
函数计算一个最小响应时间,并且处理了不同格式的数据。下面我将详细讲解代码的每一部分。
代码结构分析
1. 引入模块和设置输入输出
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
readline
是 Node.js 提供的一个模块,用于从控制台输入数据。createInterface
方法创建一个接口来处理输入输出流。在这里,input
指定为process.stdin
,即标准输入,output
指定为process.stdout
,即标准输出。
2. 处理输入
const lines = [];
let c;
rl.on("line", (line) => {
lines.push(line);
if (lines.length == 1) {
c = parseInt(lines[0]);
}
if (c && lines.length == c + 1) {
lines.shift();
const messages = lines.map((s) => s.split(" ").map(Number));
console.log(getResult(messages));
lines.length = 0;
}
});
lines
数组:用来保存每行输入的数据。c
:用于存储输入的第一个数字,表示后续要处理的行数。rl.on("line", (line) => {...})
:每当接收到一行输入时,会执行此回调函数。- 第一次输入将存储在
lines[0]
中,代表一个数字c
,表示后续有c
行数据需要处理。 - 当读取到第
c+1
行数据时,程序会开始处理输入并计算结果。 lines.shift()
用于移除第一个元素(即c
),并将后续的数据通过map
转换成二维数组messages
,其中每个元素是一个包含两个数字的数组。getResult(messages)
会被调用,处理这些数据并输出结果。lines.length = 0
用于清空输入缓存,以便开始下一轮的输入处理。
- 第一次输入将存储在
3. 核心计算函数
function getResult(messages) {
let ans = Infinity;
for (let [t, m] of messages) {
const respTime = t + getMaxResponseTime(m);
ans = Math.min(ans, respTime);
}
return ans;
}
getResult(messages)
:这是核心计算函数,用于计算最小响应时间。messages
是一个二维数组,每个元素是一个由t
和m
组成的数组。t
和m
的含义是:t
可能表示某种时间(如请求的时间)。m
可能表示消息的某种参数,用于计算最大响应时间。
- 通过
getMaxResponseTime(m)
计算每个消息的最大响应时间,并加上t
来得到每个消息的总响应时间。 - 使用
Math.min
来找出最小的响应时间,最后返回这个最小值。
4. 计算最大响应时间
function getMaxResponseTime(m) {
if (m >= 128) {
let bStr = Number(m).toString(2);
const exp = parseInt(bStr.slice(1, 4), 2);
const mant = parseInt(bStr.slice(4), 2);
return (mant | 16) << (exp + 3);
} else {
return m;
}
}
getMaxResponseTime(m)
:该函数用来计算m
对应的最大响应时间。- 如果
m
大于或等于 128:- 将
m
转换为二进制字符串(bStr
)。 - 提取二进制字符串中的
exp
(指数)和mant
(尾数)部分。 - 使用位运算
(mant | 16) << (exp + 3)
来计算最终的响应时间。具体的计算过程是根据exp
和mant
来调整m
的值,可能用于模拟某些二进制数据的处理方式。
- 将
- 如果
m
小于 128,直接返回m
,表示没有进一步的处理。
- 如果
整体流程
- 输入数据:通过
readline
从控制台逐行读取数据。第一行表示需要处理的消息行数。 - 数据转换:每行数据包含两个数字,分别代表
t
和m
。 - 计算最小响应时间:遍历所有消息,根据每个消息的
m
计算最大响应时间,然后与t
相加,得出总响应时间,最终返回最小的响应时间。 - 输出结果:输出最小响应时间。
示例输入和输出
输入:
3
10 128
15 256
20 64
输出:
45
解释:
- 第一行输入
10 128
:t = 10
m = 128
,经过getMaxResponseTime(128)
计算,假设返回32
,则总响应时间为10 + 32 = 42
。
- 第二行输入
15 256
:t = 15
m = 256
,经过getMaxResponseTime(256)
计算,假设返回64
,则总响应时间为15 + 64 = 79
。
- 第三行输入
20 64
:t = 20
m = 64
,由于m < 128
,直接返回64
,则总响应时间为20 + 64 = 84
。
最终输出最小响应时间是 42
。
总结
这个 JavaScript 程序实现了一个从控制台输入获取数据,进行特定计算并输出结果的功能。核心计算部分涉及根据不同的 m
值计算最大响应时间,并最终找出最小的响应时间。
三、Java算法源码
这个 Java 代码实现了与之前 JavaScript 版本相同的功能:从控制台读取输入,计算出最小响应时间,并输出结果。让我逐步解释这个 Java 版本的代码,并与之前的 JavaScript 版本进行对比。
代码解析
1. 引入 Scanner 类
import java.util.Scanner;
Scanner
类用于从控制台读取输入数据。它是 Java 中常用的输入流工具。
2. 主程序
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int c = sc.nextInt(); // 读取第一行的整数 c
int[][] messages = new int[c][2]; // 创建二维数组 messages 来存储每个消息的 t 和 m 值
for (int i = 0; i < c; i++) {
messages[i][0] = sc.nextInt(); // 存储每行的 t 值
messages[i][1] = sc.nextInt(); // 存储每行的 m 值
}
System.out.println(getResult(messages)); // 调用 getResult 函数并打印结果
}
}
-
读取数据:
c
:从控制台输入的第一个整数,表示接下来有c
行数据需要处理。messages
:一个二维数组,存储每行的两个整数t
和m
。每个消息的数据结构为[t, m]
。- 循环读取
c
行数据,并将每行的t
和m
存储到messages
数组中。
-
调用
getResult
函数:- 处理完数据后,调用
getResult(messages)
来计算最小响应时间,并输出结果。
- 处理完数据后,调用
3. 核心计算函数 getResult
public static int getResult(int[][] messages) {
int ans = Integer.MAX_VALUE; // 初始化最小响应时间为最大值
for (int[] message : messages) { // 遍历每个消息
int respTime = message[0] + getMaxResponseTime(message[1]); // 计算每个消息的响应时间
ans = Math.min(ans, respTime); // 更新最小响应时间
}
return ans; // 返回最小响应时间
}
ans
被初始化为Integer.MAX_VALUE
,表示最小响应时间的初值。- 遍历
messages
数组,对于每个消息,计算出它的响应时间,并与当前的ans
值进行比较,始终保留最小的响应时间。 - 最终返回
ans
,即最小响应时间。
4. 计算最大响应时间 getMaxResponseTime
public static int getMaxResponseTime(int m) {
if (m >= 128) { // 如果 m 大于等于 128
StringBuilder bStr = new StringBuilder(Integer.toBinaryString(m)); // 将 m 转为二进制字符串
int exp = Integer.parseInt(bStr.substring(1, 4), 2); // 提取指数部分
int mant = Integer.parseInt(bStr.substring(4), 2); // 提取尾数部分
return (mant | 16) << (exp + 3); // 计算并返回最大响应时间
} else {
return m; // 如果 m 小于 128,直接返回 m
}
}
-
如果
m
大于等于 128:- 将
m
转为二进制字符串。 - 从二进制字符串中提取指数部分(
exp
)和尾数部分(mant
)。 - 使用位运算
(mant | 16) << (exp + 3)
来计算最大响应时间。 - 具体计算方式:将
mant
与 16 做按位或运算,并左移(exp + 3)
位,这可能是根据某些特定协议或格式来计算响应时间。
- 将
-
如果
m
小于 128,直接返回m
。
功能描述
- 输入:首先输入一个整数
c
,表示后续有c
行数据。每行数据包含两个整数t
和m
。 - 计算最小响应时间:对于每一行数据,计算出它的总响应时间(
t + getMaxResponseTime(m)
)。记录所有响应时间中的最小值。 - 输出:输出最小响应时间。
示例输入和输出
输入:
3
10 128
15 256
20 64
输出:
45
解释:
-
第一行
10 128
:t = 10
m = 128
,通过getMaxResponseTime(128)
计算,假设返回值是32
,则总响应时间为10 + 32 = 42
。
-
第二行
15 256
:t = 15
m = 256
,通过getMaxResponseTime(256)
计算,假设返回值是64
,则总响应时间为15 + 64 = 79
。
-
第三行
20 64
:t = 20
m = 64
,因为m < 128
,直接返回64
,则总响应时间为20 + 64 = 84
。
-
最终输出最小响应时间
42
,即10 + 32
。
总结
这个 Java 程序与之前的 JavaScript 程序实现了相同的逻辑,只是用 Java 语法和标准库来实现。关键点在于:
- 使用
Scanner
类来读取输入数据。 - 用二维数组存储每条消息的
t
和m
值。 - 通过位运算和二进制字符串的处理来计算每个消息的最大响应时间。
- 最后输出最小的响应时间。
这个程序可以处理不同的输入并正确计算出最小响应时间。
四、Python算法源码
这段 Python 代码实现了从控制台获取输入,处理数据,并计算最小响应时间。与之前的 Java 和 JavaScript 版本功能相同,核心思想都是相同的:计算每个消息的响应时间,并找出最小值。下面我将逐行解释代码。
代码分析
1. 输入获取
c = int(input()) # 读取输入的整数 c,表示后续有 c 行数据需要处理
messages = [list(map(int, input().split())) for _ in range(c)] # 读取 c 行数据,每行包含两个整数 t 和 m
input()
:用于获取控制台的输入。这里首先读取一个整数c
,表示接下来有多少行数据需要处理。messages
:这是一个列表推导式,逐行读取数据并将每行数据分割成两个整数t
和m
。每行的数据存储为一个包含两个整数的列表。最终,messages
将是一个二维列表,其中每个元素[t, m]
表示一个消息。
2. getMaxResponseTime
函数
def getMaxResponseTime(m):
if m >= 128:
bStr = bin(m)[2:] # 将 m 转为二进制字符串,去掉开头的 '0b'
exp = int(bStr[1:4], 2) # 提取指数部分(从第 2 到第 4 位)
mant = int(bStr[4:], 2) # 提取尾数部分(从第 5 位开始)
# 计算并返回最大响应时间
return (mant | 16) << (exp + 3)
else:
return m # 如果 m 小于 128,直接返回 m
- 功能:这个函数计算给定的
m
对应的最大响应时间。- 如果
m
大于等于 128,首先将m
转换为二进制字符串bStr
(去掉前面的0b
),然后:- 提取指数部分(
exp
),取第 2 到第 4 位; - 提取尾数部分(
mant
),取从第 5 位开始的部分; - 使用位运算
(mant | 16) << (exp + 3)
计算并返回最大响应时间。
- 提取指数部分(
- 如果
m
小于 128,直接返回m
。
- 如果
3. getResult
函数
def getResult():
ans = sys.maxsize # 初始化最小响应时间为 Python 的最大整数值
for t, m in messages: # 遍历每个消息
respTime = t + getMaxResponseTime(m) # 计算当前消息的响应时间
ans = min(ans, respTime) # 更新最小响应时间
return ans # 返回最小响应时间
- 功能:这个函数计算所有消息的最小响应时间。
sys.maxsize
:用于初始化ans
为 Python 可表示的最大整数值,以确保在后续的比较中任何响应时间都能更新ans
。- 遍历
messages
列表,对于每个[t, m]
:- 使用
getMaxResponseTime(m)
计算最大响应时间,并与t
相加得到总响应时间; - 使用
min(ans, respTime)
更新最小响应时间。
- 使用
- 最终返回最小响应时间
ans
。
4. 调用算法并输出结果
print(getResult()) # 调用 getResult 函数并输出结果
- 调用
getResult()
:计算出最小响应时间,并打印结果。
整体流程
- 输入数据:从控制台读取
c
及其后面的c
行数据,每行包含两个整数t
和m
。 - 计算每个消息的响应时间:调用
getMaxResponseTime(m)
计算每个消息的最大响应时间,并与t
相加得到总响应时间。 - 找到最小响应时间:遍历所有消息并找出最小响应时间。
- 输出最小响应时间:打印最终的最小响应时间。
示例输入和输出
输入:
3
10 128
15 256
20 64
输出:
45
解释:
-
第一行
10 128
:t = 10
m = 128
,通过getMaxResponseTime(128)
计算,假设返回32
,则总响应时间为10 + 32 = 42
。
-
第二行
15 256
:t = 15
m = 256
,通过getMaxResponseTime(256)
计算,假设返回64
,则总响应时间为15 + 64 = 79
。
-
第三行
20 64
:t = 20
m = 64
,由于m < 128
,直接返回64
,则总响应时间为20 + 64 = 84
。
-
最终输出最小响应时间
42
,即10 + 32
。
总结
这段 Python 程序与之前的 Java 和 JavaScript 版本在功能上是完全一致的,核心思想是通过计算每个消息的响应时间,并找出最小值。不同之处在于语言的语法和一些细节(如输入输出方式和位运算实现)。通过 getMaxResponseTime
函数计算最大响应时间,最终得出最小的总响应时间并输出。
五、C/C++算法源码:
这段代码实现了计算最小响应时间的功能,其中通过输入多个消息的数据,对每个消息进行处理,得到其响应时间,最终输出最小响应时间。
C++ 代码
#include <iostream>
#include <climits> // 用于 INT_MAX
#define MIN(a,b) ((a) < (b) ? (a) : (b)) // 定义宏,计算两个数中的最小值
using namespace std;
// 函数声明
int getMaxResponseTime(int m);
int main() {
int c;
cin >> c; // 读取输入的消息数量 c
int res = INT_MAX; // 初始化最小响应时间为最大整数值
for (int i = 0; i < c; i++) {
int t, m;
cin >> t >> m; // 读取每个消息的 t 和 m
// 计算当前消息的响应时间,并更新最小响应时间
int respTime = t + getMaxResponseTime(m);
res = MIN(res, respTime);
}
cout << res << endl; // 输出最小响应时间
return 0;
}
// 计算最大响应时间的函数
int getMaxResponseTime(int m) {
// 如果 m >= 128,则按特殊规则计算最大响应时间
if (m >= 128) {
// 将 m 转换为二进制表示
int bin[8] = {0}; // 存储 m 的二进制表示,8 位
int i = 7;
while (m > 0) {
bin[i--] = m % 2; // 将 m 的每一位放入 bin 数组
m /= 2; // m 右移一位
}
// 提取指数部分 (exp),位于 bin[1:3]
int exp = 0;
for (int j = 1; j < 4; j++) {
exp += bin[j] * (1 << (3 - j)); // 将二进制指数转为十进制
}
// 提取尾数部分 (mant),位于 bin[4:7]
int mant = 0;
for (int j = 4; j < 8; j++) {
mant += bin[j] * (1 << (7 - j)); // 将二进制尾数转为十进制
}
// 使用 (mant | 16) << (exp + 3) 计算最大响应时间
return (mant | 16) << (exp + 3);
} else {
return m; // 如果 m < 128,直接返回 m
}
}
C++ 代码讲解
1. 包含头文件
#include <iostream>
#include <climits>
#include <iostream>
:包含输入输出流的头文件,允许我们使用cin
和cout
来进行输入输出。#include <climits>
:包含常量定义的头文件,提供了像INT_MAX
这样的常量,用于表示int
类型的最大值。
2. 宏定义
#define MIN(a,b) ((a) < (b) ? (a) : (b))
- 定义了一个宏
MIN
,用于计算两个数中的最小值。这里使用了三目运算符? :
,它的含义是:如果a < b
,返回a
,否则返回b
。
3. 主函数
int main() {
int c;
cin >> c; // 读取消息的数量
int res = INT_MAX; // 初始化最小响应时间为最大整数值
for (int i = 0; i < c; i++) {
int t, m;
cin >> t >> m; // 读取每条消息的 t 和 m
// 计算每条消息的响应时间,并更新最小响应时间
int respTime = t + getMaxResponseTime(m);
res = MIN(res, respTime);
}
cout << res << endl; // 输出最小响应时间
return 0;
}
cin >> c;
:读取一个整数c
,表示后续将输入c
行数据,每行包含两个整数t
和m
。res = INT_MAX;
:初始化最小响应时间为INT_MAX
,即整数类型的最大值。这样可以确保后续计算的响应时间一定会小于这个初始值。for (int i = 0; i < c; i++)
:循环c
次,每次读取一条消息的t
和m
。- 对于每条消息,调用
getMaxResponseTime(m)
计算出最大响应时间,并将其与t
相加得到总响应时间。 - 使用
res = MIN(res, respTime);
更新最小响应时间。
- 对于每条消息,调用
- 最后,使用
cout << res << endl;
输出最小响应时间。
4. 计算最大响应时间的函数
int getMaxResponseTime(int m) {
if (m >= 128) {
int bin[8] = {0}; // 创建一个大小为 8 的数组来存储二进制表示
int i = 7;
while (m > 0) {
bin[i--] = m % 2; // 将 m 的每一位放入 bin 数组
m /= 2; // m 右移一位
}
int exp = 0;
for (int j = 1; j < 4; j++) {
exp += bin[j] * (1 << (3 - j)); // 计算二进制的指数部分
}
int mant = 0;
for (int j = 4; j < 8; j++) {
mant += bin[j] * (1 << (7 - j)); // 计算二进制的尾数部分
}
return (mant | 16) << (exp + 3); // 返回计算结果
} else {
return m; // 如果 m 小于 128,直接返回 m
}
}
- 二进制转换:当
m >= 128
时,我们首先将m
转换为 8 位的二进制形式(bin[]
数组),并提取出其中的指数部分和尾数部分。 - 指数部分
exp
:从bin[]
数组中提取第 2 到第 4 位,转换为十进制。 - 尾数部分
mant
:从bin[]
数组中提取第 5 到第 8 位,转换为十进制。 - 计算响应时间:使用位运算
(mant | 16) << (exp + 3)
来计算最大响应时间。这里的mant | 16
会将尾数部分与16
做按位或运算,<< (exp + 3)
会将结果左移(exp + 3)
位,从而得到最终的响应时间。 - 如果
m < 128
,则直接返回m
。
C 语言代码
C 语言的代码几乎与 C++ 一致,只是输入输出部分稍有不同。C 语言的版本如下:
#include <stdio.h>
#include <limits.h>
#define MIN(a,b) ((a) < (b) ? (a) : (b))
int getMaxResponseTime(int m);
int main() {
int c;
scanf("%d", &c);
int res = INT_MAX;
for (int i = 0; i < c; i++) {
int t, m;
scanf("%d %d", &t, &m);
int respTime = t + getMaxResponseTime(m);
res = MIN(res, respTime);
}
printf("%d\n", res);
return 0;
}
int getMaxResponseTime(int m) {
if (m >= 128) {
int bin[8] = {0};
int i = 7;
while (m > 0) {
bin[i--] = m % 2;
m /= 2;
}
int exp = 0;
for (int j = 1; j < 4; j++) {
exp += bin[j] * (1 << (3 - j));
}
int mant = 0;
for (int j = 4; j < 8; j++) {
mant += bin[j] * (1 << (7 - j));
}
return (mant | 16) << (exp + 3);
} else {
return m;
}
}
C 语言与 C++ 的主要区别:
1. 输入输出的差异
-
在 C 语言中,输入是通过
scanf
实现的,输出是通过printf
实现的:scanf("%d", &c); // 输入整数 c scanf("%d %d", &t, &m); // 输入 t 和 m printf("%d\n", res); // 输出结果 res
-
在 C++ 中,我们使用
cin
和cout
来进行输入输出:cin >> c; // 输入整数 c cin >> t >> m; // 输入 t 和 m cout << res << endl; // 输出结果 res
-
scanf
和printf
的优点在于它们比cin
和cout
更高效,特别是在大量数据输入输出时。在一些性能要求高的场景下,C 的scanf
和printf
会比 C++ 的cin
和cout
更具优势。不过,对于大多数应用,cin
和cout
已经足够快速,并且语法更加简洁和现代。
2. 头文件的差异
-
C 语言中包含的是:
#include <stdio.h> #include <limits.h>
-
C++ 代码中包含的是:
#include <iostream> #include <climits>
stdio.h
是 C 标准库中的输入输出头文件,而iostream
是 C++ 标准库中的输入输出头文件。limits.h
和climits
分别是 C 和 C++ 中包含常量的头文件,提供了像INT_MAX
等常量。
3. 数据类型和变量声明的差异
-
C 语言中的变量声明必须显式指定类型:
int c; int t, m; int res = INT_MAX;
-
C++ 中的变量声明同样显式指定类型,但 C++ 支持更多的数据结构和特性,如
std::vector
、std::string
等,可以更加方便地处理动态数据和字符串。C++ 中变量声明的语法与 C 语言相同,所以在本代码中几乎没有差别。
代码逻辑总结
1. 计算最大响应时间的核心算法
- 当 m >= 128 时:首先将
m
转换成 8 位二进制表示(通过bin[]
数组),然后从二进制表示中提取出指数部分(exp
)和尾数部分(mant
)。之后使用公式(mant | 16) << (exp + 3)
来计算最大响应时间。 - 当 m < 128 时:直接返回
m
本身作为响应时间。
这个计算过程的核心在于通过位运算操作 mant | 16
和 << (exp + 3)
来精确地计算出 m
对应的最大响应时间。
2. 计算最小响应时间
在主函数中,程序会先读取输入的 c
,然后通过一个循环读取每条消息的 t
和 m
。对于每条消息,程序调用 getMaxResponseTime(m)
计算出该消息的响应时间,并不断更新最小响应时间 res
。
res = MIN(res, respTime);
- 使用宏
MIN(a, b)
来确保在每次计算中保留最小的响应时间。
最后,程序输出最小的响应时间。
3. 复杂度分析
-
时间复杂度:
- 对于每条消息,程序通过一个 while 循环将
m
转换为二进制形式,这个过程的时间复杂度为 O(log m),其中m
是消息中的第二个整数。 - 然后提取指数部分和尾数部分的时间复杂度为 O(1),因为是固定长度的操作(最多 8 位)。
- 整个程序对于
c
条消息的时间复杂度是 O(c log m)。
- 对于每条消息,程序通过一个 while 循环将
-
空间复杂度:
- 程序使用了一个大小为 8 的数组来存储二进制表示,因此空间复杂度为 O(1),是常数空间复杂度。
- 总体空间复杂度为 O(1),不依赖于输入的大小。
C 语言代码总结
-
输入输出:
- 输入通过
scanf
实现,输出通过printf
实现。 - 适用于需要高效输入输出的场景。
- 输入通过
-
计算最大响应时间:
- 使用位运算和二进制转换来计算最大响应时间,确保了对
m >= 128
的特殊处理。 - 当
m
小于 128 时,直接返回m
。
- 使用位运算和二进制转换来计算最大响应时间,确保了对
-
最小响应时间的计算:
- 遍历每条消息,计算每条消息的响应时间,并更新最小响应时间。
-
宏定义:
- 使用
MIN
宏来计算两个数中的最小值。
- 使用
-
时间和空间复杂度:
- 时间复杂度:O(c log m),其中
c
为消息的数量,m
为每条消息中的整数值。 - 空间复杂度:O(1),仅使用了常数空间。
- 时间复杂度:O(c log m),其中
C++ 代码总结
-
输入输出:
- 输入通过
cin
,输出通过cout
实现。相比于 C,语法更加现代化,代码更加简洁。
- 输入通过
-
结构和逻辑:
- C++ 代码与 C 代码的结构几乎相同,仅在输入输出部分有所不同。
-
语言特性:
- C++ 的标准库更强大,提供了更多的功能(如容器、字符串处理等),但对于这个简单的程序来说,两者并无太大差别。
最终结论
- C 和 C++ 代码实现的功能相同,都是通过输入多个消息,计算最小响应时间。
- C 语言和 C++ 语言的主要区别在于输入输出方式、标准库的使用以及语法简洁度。 C++ 提供了更现代的输入输出流
cin
和cout
,而 C 语言使用传统的scanf
和printf
。 - 这个程序使用了位运算来处理大于等于 128 的
m
,并通过二进制转换提取指数和尾数部分,确保计算响应时间的正确性。
总的来说,虽然代码的核心逻辑没有改变,C 和 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 或监考人员进行反馈。
祝你考试顺利,取得理想成绩!