
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。
一、题目描述
请开发一个快递驿站计费系统,根据给定的一组快递存取记录,系统计算每位业主需要缴纳的总费用,并按总费用从高到低输出。
系统计费规则如下:
- 免费存放时间为12小时,从存件时间开始计时,总存放时间≤12小时不收费,存放时间=取件时间—存件时间;
- 超出免费存放时间的,每12小时收取1元,不足12小时按12小时计算,比如存放了25个小时,超出免费时间13小时,需要收费2元;
- 同一个房间号的业主,可能有多条存取记录,需要将业主所有快递的超时费用累加得到总费用。
二、输入描述
一组快递存取记录列表,其中一条存取记录对应一个数组,该数组包含3个非负整数字段:存件时间、取件时间和业主房间号;存取时间已简化处理采用整型数字,非24小时制格式;
0 <= 存件时间 <= 取件时间 <= 100000100 < 房间号 < 10000- 输入记录条数范围
1 <= N <= 1000
三、输出描述
一个二维数组/列表,表述一组收费记录,每一条收费记录对应一个数组,该数组包含2个整数字段:业主房间号和总费用;收费按总费用从高到低排序,总费用相同的,按房间号从小到大排序;
四、测试用例
测试用例1:
1、输入
100,110,1111
200,210,2222
150,165,3333
180,190,1111
2、输出
3333,1
1111,0
2222,0
3、说明
3333 房间存放 15 小时,超出免费时间 3 小时,收费 1 元;1111 有两件快递,但都没有超过 12 小时,因此总费用仍为 0。1111 和 2222 同为 0 元,房间号较小的 1111 在前。
测试用例2:
1、输入
0,12,101
0,13,102
0,24,103
0,25,104
2、输出
104,2
102,1
103,1
101,0
3、说明
12 小时免费;13 小时超时 1 小时,收费 1 元;24 小时超时正好 12 小时,收费 1 元;25 小时超时 13 小时,收费 2 元。102 和 103 都收费 1 元,因此房间号 102 在前。
五、解题思路
本题主要分为“单条快递计费、同房间费用汇总、结果排序”三个步骤。
首先计算每条快递的实际存放时间 duration = 取件时间 - 存件时间。当 duration <= 12 时属于免费存放,费用为 0;当存放时间超过 12 小时时,只对超过的部分计费。设超时时间为 overtime = duration - 12,每 12 小时收费 1 元,并且不足 12 小时也按 12 小时计算,因此本质上需要计算 ceil(overtime / 12)。为了避免使用浮点数,可以通过整数公式 (overtime + 11) / 12 完成向上取整。例如存放 25 小时,超时 13 小时,费用为 (13 + 11) / 12 = 2 元。
由于同一个房间可能有多条快递记录,需要按照房间号累计费用。Java 中使用 HashMap<Integer, Integer>,键为房间号,值为该房间累计费用。遍历每条记录后,通过 getOrDefault 将本次产生的费用累加进去。即使某条记录费用为 0,也必须保存房间号,因为最终结果要求输出所有出现过的业主。
完成统计后,将 HashMap 中的键值对转换成 List 并排序。排序规则首先比较总费用,费用大的排在前面;如果总费用相同,再比较房间号,房间号小的排在前面。
假设输入记录数为 N,不同房间数为 M。统计过程平均时间复杂度为 O(N),排序复杂度为 O(M log M),因此总体时间复杂度为 O(N + M log M),空间复杂度为 O(M)。N 最大只有 1000,该方案可以高效完成计算。
六、Python算法源码
import sys
def main():
# key:房间号,value:该房间所有快递累计产生的费用
total_fee = {}
# 题目没有提供单独的记录数量 N,因此一直读取到 EOF
for raw_line in sys.stdin:
line = raw_line.strip()
if not line:
continue
store_time, pickup_time, room_no = map(
int,
(part.strip() for part in line.split(','))
)
duration = pickup_time - store_time
# 前 12 小时免费。
# 超过 12 小时的部分每 12 小时收费 1 元,
# 不足 12 小时按照 12 小时计算,因此进行向上取整。
fee = (
0
if duration <= 12
else (duration - 12 + 11) // 12
)
# 累加同一房间所有快递产生的费用
total_fee[room_no] = (
total_fee.get(room_no, 0) + fee
)
# 排序条件:
# -item[1]:费用从高到低
# item[0]:费用相同时房间号从小到大
result = sorted(
total_fee.items(),
key=lambda item: (-item[1], item[0])
)
for room_no, fee in result:
print(f"{room_no},{fee}")
if __name__ == "__main__":
main()
七、JavaScript算法源码
const fs = require('fs');
const input = fs.readFileSync(0, 'utf8');
// key:房间号
// value:该房间所有快递累计产生的费用
const totalFee = new Map();
// 输入没有给出记录数 N,因此读取所有输入行
for (const rawLine of input.split(/\r?\n/)) {
const line = rawLine.trim();
if (!line) {
continue;
}
const [storeTime, pickupTime, roomNo] = line
.split(',')
.map(part => Number(part.trim()));
const duration = pickupTime - storeTime;
/*
* 12 小时以内免费。
* 超过 12 小时后,每 12 小时收费 1 元。
* 不足 12 小时也按照 12 小时计算。
*
* 通过 (超时时间 + 11) / 12 实现整数向上取整。
*/
const fee = duration <= 12
? 0
: Math.floor((duration - 12 + 11) / 12);
// 累加同一个房间号产生的所有费用
totalFee.set(
roomNo,
(totalFee.get(roomNo) || 0) + fee
);
}
// Map 转换成数组后进行排序
const result = Array.from(totalFee.entries());
result.sort((a, b) => {
// 首先按照总费用从高到低
if (a[1] !== b[1]) {
return b[1] - a[1];
}
// 总费用相同时,按照房间号从小到大
return a[0] - b[0];
});
console.log(
result
.map(([roomNo, fee]) => `${roomNo},${fee}`)
.join('\n')
);
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int room;
int fee;
} Record;
/*
* qsort 的比较函数:
* 1. 总费用从高到低
* 2. 总费用相同则房间号从小到大
*/
int compareRecord(const void *p1, const void *p2) {
const Record *a = (const Record *)p1;
const Record *b = (const Record *)p2;
if (a->fee != b->fee) {
return (a->fee < b->fee) ? 1 : -1;
}
return (a->room > b->room)
- (a->room < b->room);
}
int main(void) {
/*
* 房间号范围:
* 100 < 房间号 < 10000
*
* 因此可以直接使用房间号作为数组下标。
* totalFee 保存累计费用;
* appeared 用于判断该房间是否在输入中出现过。
*/
int totalFee[10000] = {0};
int appeared[10000] = {0};
int storeTime;
int pickupTime;
int roomNo;
/*
* 一直读取到 EOF。
* 格式中的空格能够兼容换行等空白字符。
*/
while (scanf(
" %d , %d , %d",
&storeTime,
&pickupTime,
&roomNo
) == 3) {
int duration = pickupTime - storeTime;
/*
* 12 小时以内免费。
* 超时部分每 12 小时收费 1 元,
* 不足 12 小时进行向上取整。
*/
int fee = (duration <= 12)
? 0
: (duration - 12 + 11) / 12;
// 累加同一房间号的费用
totalFee[roomNo] += fee;
// 即使费用为 0,也需要记录该房间出现过
appeared[roomNo] = 1;
}
Record result[10000];
int count = 0;
// 收集所有出现过的房间及其总费用
for (int room = 101; room < 10000; ++room) {
if (appeared[room]) {
result[count].room = room;
result[count].fee = totalFee[room];
++count;
}
}
// 按题目要求进行排序
qsort(
result,
count,
sizeof(Record),
compareRecord
);
for (int i = 0; i < count; ++i) {
printf(
"%d,%d\n",
result[i].room,
result[i].fee
);
}
return 0;
}
九、C++算法源码
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
// key:房间号
// value:该房间所有快递累计产生的费用
unordered_map<int, int> totalFee;
string line;
// 题目没有给出 N,因此按行读取直到 EOF
while (getline(cin, line)) {
if (line.empty()) {
continue;
}
/*
* 原输入格式为:
* 存件时间,取件时间,房间号
*
* 将逗号替换为空格以后,
* 可以直接利用 stringstream 读取三个整数。
*/
replace(
line.begin(),
line.end(),
',',
' '
);
stringstream ss(line);
int storeTime;
int pickupTime;
int roomNo;
ss >> storeTime
>> pickupTime
>> roomNo;
int duration = pickupTime - storeTime;
/*
* 12 小时以内免费;
* 超时部分每 12 小时收费 1 元;
* 不足 12 小时按照 12 小时计算。
*/
int fee = (duration <= 12)
? 0
: (duration - 12 + 11) / 12;
// 同一房间多条记录需要累加
totalFee[roomNo] += fee;
}
// 将哈希表转换为 vector,以便排序
vector<pair<int, int>> result(
totalFee.begin(),
totalFee.end()
);
/*
* 排序规则:
* 1. 总费用从高到低
* 2. 总费用相同则房间号从小到大
*/
sort(
result.begin(),
result.end(),
[](const auto &a, const auto &b) {
if (a.second != b.second) {
return a.second > b.second;
}
return a.first < b.first;
}
);
for (const auto &[roomNo, fee] : result) {
cout << roomNo
<< ','
<< fee
<< '\n';
}
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 新系统 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。

725

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



