华为OD机试 2024E卷题库疯狂收录中,刷题点这里
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。
一、题目描述
某软件系统在运行过程中持续产生日志,系统每天运行N个单位时间,运行期间每单位时间产生的日志条数保存在数组records中。由于系统磁盘空间限制,每天可记录保存的日志总数上限为total条。
如果一天产生的日志条数大于total,则需要对当天每单位时间产生的日志条数进行限流后保存,要求计算每单位时间最大可保存日志数上限limit,使得每天保存的日志总量不超过total。
- 对于单位时间内产生日志条数超过limit的日志会被记录limit条;
- 对于单位时间内产生日志条数少于或等于limit的日志,记录全部日志。
如果一天产生的日志条数总和小于或等于total,则不需要限流,结果为-1。
任务:返回result的最大值Q或者-1。
二、输入描述
第一行为系统某一天运行的单位时间数N,1 <= N <= 10^5;
第二行为表示这一天每单位时间产生的日志条数数组records[],0 <= records[i] <= 10^5;
第三行为系统一天可以保存的日志总数total,1 <= total <= 10^9。
三、输出描述
每单位时间内最大可保存的日志条数limit,如果不需要启动限流机制,返回-1。
四、测试用例
测试用例1:
1、输入
6
3 3 8 7 10 15
40
2、输出
9
3、说明
如题目所示,limit=9 时,保存日志总数为39 ≤40,且无法找到更大的limit满足条件。
测试用例2:
1、输入
5
1 2 3 4 5
15
2、输出
-1
3、说明
总日志数为15,等于total,无需限流,返回-1。
五、解题思路
需要在日志总量超过系统保存上限 total 的情况下,找到一个每单位时间保存日志的最大上限 limit,使得每天保存的日志总量不超过 total。
具体步骤如下:
- 计算日志总量:首先计算数组 records 中所有日志的总和。如果总和小于或等于 total,则无需限流,直接返回 -1。
- 二分查找:如果总和超过 total,则需要确定一个合适的 limit。我们可以采用二分查找的方法,搜索可能的 limit 值范围从 1 到 records 数组中的最大值。对于每一个中间值 mid,计算在限流 mid 的情况下,每单位时间实际保存的日志总数。如果总数小于或等于 total,则尝试增大 mid;否则,减小 mid。最终找到的最大满足条件的 limit 即为所求。
- 优化计算:为了高效计算在某个 limit 下的保存日志总数,我们可以遍历数组,对每个记录取 min(records[i], mid) 的和。
采用二分查找的原因是它能在对数时间内快速缩小可能的 limit 范围,特别适用于本题中 N 和 records[i] 较大的情况。
六、Python算法源码
# Python 代码实现
import sys
def main():
import sys
import math
# 读取输入
input = sys.stdin.read().split()
idx = 0
# 读取单位时间数N
N = int(input[idx])
idx += 1
# 读取每单位时间产生的日志数数组records
records = []
max_record = 0 # 记录数组中的最大值
total_logs = 0 # 记录总日志数
for _ in range(N):
num = int(input[idx])
records.append(num)
total_logs += num
if num > max_record:
max_record = num
idx += 1
# 读取系统一天可以保存的日志总数total
total = int(input[idx])
idx += 1
# 如果总日志数小于或等于total,不需要限流,输出-1
if total_logs <= total:
print(-1)
return
# 初始化二分查找的左边界和右边界
left = 1
right = max_record
result = -1
# 执行二分查找,寻找最大的limit值
while left <= right:
mid = left + (right - left) // 2 # 计算中间值
saved_logs = 0 # 当前limit下保存的日志总数
# 计算在当前limit下保存的日志总数
for record in records:
saved_logs += min(record, mid)
# 如果已经超过total,提前退出循环
if saved_logs > total:
break
# 判断当前limit是否可行
if saved_logs <= total:
result = mid # 更新结果为当前mid
left = mid + 1 # 尝试寻找更大的limit
else:
right = mid - 1 # 限流过多,减少limit
# 输出最终结果
print(result)
if __name__ == "__main__":
main()
七、JavaScript算法源码
// JavaScript 代码实现
const readline = require('readline');
// 创建接口以读取输入
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let input = [];
// 读取所有输入行
rl.on('line', (line) => {
input = input.concat(line.trim().split(' '));
}).on('close', () => {
let idx = 0;
// 读取单位时间数N
const N = parseInt(input[idx++]);
// 读取每单位时间产生的日志数数组records
const records = [];
let maxRecord = 0; // 记录数组中的最大值
let totalLogs = 0; // 记录总日志数
for (let i = 0; i < N; i++) {
const num = parseInt(input[idx++]);
records.push(num);
totalLogs += num;
if (num > maxRecord) {
maxRecord = num;
}
}
// 读取系统一天可以保存的日志总数total
const total = parseInt(input[idx++]);
// 如果总日志数小于或等于total,不需要限流,输出-1
if (totalLogs <= total) {
console.log(-1);
return;
}
// 初始化二分查找的左边界和右边界
let left = 1;
let right = maxRecord;
let result = -1;
// 执行二分查找,寻找最大的limit值
while (left <= right) {
const mid = Math.floor(left + (right - left) / 2); // 计算中间值
let savedLogs = 0; // 当前limit下保存的日志总数
// 计算在当前limit下保存的日志总数
for (let i = 0; i < N; i++) {
savedLogs += Math.min(records[i], mid);
// 如果已经超过total,提前退出循环
if (savedLogs > total) {
break;
}
}
// 判断当前limit是否可行
if (savedLogs <= total) {
result = mid; // 更新结果为当前mid
left = mid + 1; // 尝试寻找更大的limit
} else {
right = mid - 1; // 限流过多,减少limit
}
}
// 输出最终结果
console.log(result);
});
八、C算法源码
/* C 代码实现 */
#include <stdio.h>
// 主函数
int main() {
int N;
// 读取单位时间数N
scanf("%d", &N);
int records[N];
int max_record = 0; // 记录数组中的最大值
long long total_logs = 0; // 记录总日志数
// 读取每单位时间产生的日志数数组records
for(int i = 0; i < N; i++) {
scanf("%d", &records[i]);
total_logs += records[i];
if(records[i] > max_record) {
max_record = records[i];
}
}
long long total;
// 读取系统一天可以保存的日志总数total
scanf("%lld", &total);
// 如果总日志数小于或等于total,不需要限流,输出-1
if(total_logs <= total) {
printf("-1\n");
return 0;
}
// 初始化二分查找的左边界和右边界
int left = 1;
int right = max_record;
int result = -1;
// 执行二分查找,寻找最大的limit值
while(left <= right) {
int mid = left + (right - left) / 2; // 计算中间值
long long saved_logs = 0; // 当前limit下保存的日志总数
// 计算在当前limit下保存的日志总数
for(int i = 0; i < N; i++) {
if(records[i] > mid) {
saved_logs += mid;
}
else {
saved_logs += records[i];
}
// 如果已经超过total,提前退出循环
if(saved_logs > total) {
break;
}
}
// 判断当前limit是否可行
if(saved_logs <= total) {
result = mid; // 更新结果为当前mid
left = mid + 1; // 尝试寻找更大的limit
}
else {
right = mid - 1; // 限流过多,减少limit
}
}
// 输出最终结果
printf("%d\n", result);
return 0;
}
九、C++算法源码
// C++ 代码实现
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int N;
// 读取单位时间数N
cin >> N;
vector<int> records(N);
int max_record = 0; // 记录数组中的最大值
ll total_logs = 0; // 记录总日志数
// 读取每单位时间产生的日志数数组records
for(int i = 0; i < N; i++) {
cin >> records[i];
total_logs += records[i];
if(records[i] > max_record){
max_record = records[i];
}
}
ll total;
// 读取系统一天可以保存的日志总数total
cin >> total;
// 如果总日志数小于或等于total,不需要限流,输出-1
if(total_logs <= total){
cout << "-1\n";
return 0;
}
// 初始化二分查找的左边界和右边界
int left = 1;
int right = max_record;
int result = -1;
// 执行二分查找,寻找最大的limit值
while(left <= right){
int mid = left + (right - left) / 2; // 计算中间值
ll saved_logs = 0; // 当前limit下保存的日志总数
// 计算在当前limit下保存的日志总数
for(int i = 0; i < N; i++){
saved_logs += min((ll)records[i], (ll)mid);
// 如果已经超过total,提前退出循环
if(saved_logs > total){
break;
}
}
// 判断当前limit是否可行
if(saved_logs <= total){
result = mid; // 更新结果为当前mid
left = mid + 1; // 尝试寻找更大的limit
}
else{
right = mid - 1; // 限流过多,减少limit
}
}
// 输出最终结果
cout << result << "\n";
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。