
专栏导读
本专栏收录于《华为OD机试真题(Python/JS/C/C++)》。
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。
一、题目描述
为了提升软件编码能力,小王制定了刷题计划,他选了题库中的 n 道题,编号从 0 到 n-1,并计划在 m 天内按照题目编号顺序刷完所有的题目(注意,小王不能用多天完成同一题)。
在小王刷题计划中,小王需要用 time[i] 的时间完成编号 i 的题目。
此外,小王还可以查看答案,可以省去该题的做题时间。为了真正达到刷题效果,小王每天最多直接看一次答案。
我们定义 m 天中做题时间最多的一天耗时为 T(直接看答案的题目不计入做题总时间)。
请你帮小王求出最小的 T 是多少。
二、输入描述
第一行输入为 time 数组,time[i] 的时间完成编号 i 的题目
第二行输入为 m,m 表示几天内完成所有题目,1 ≤ m ≤ 180
三、输出描述
最小耗时整数 T
四、测试用例
测试用例1:
1、输入
999,999,999
4
2、输出
0
3、说明
在前三天中,小王每天都直接看答案,这样他可以在三天内完成所有的题目并不花任何时间
测试用例2:
1、输入
1,2,2,3,5,4,6,7,8
5
2、输出
4
3、说明
第一天完成前3题,第3题看答案;
第二天完成第4题和第5题,第5题看答案;
第三天完成第6和第7题,第7提看答案;
第四天完成第8题,直接看答案;
第五天完成第9题,直接看答案
五、解题思路
最小化“每天做题时间上限 T”,用二分 + 贪心判定即可。
核心判定:一天内一段连续题目可行当且仅当 sum - max <= T(跳过耗时最大的一题)。
判定方法:对固定 T,用贪心划分每天尽量多的题。一天内可跳过 1 题,故当天有效耗时为 sum - max,只要 sum - max <= T 就可行。
数据结构:数组存储时间;使用累计和与当前最大值即可,空间 O(1)。
六、Python算法源码
import sys
def can_finish(time, m, T):
days = 1
s = 0
mx = 0
for t in time:
ns = s + t
nmx = mx if mx > t else t
# 跳过当天最大题后,仍不超过 T 才能放进同一天
if ns - nmx <= T:
s = ns
mx = nmx
else:
days += 1
s = t
mx = t
if days > m:
return False
return True
def main():
data = sys.stdin.read().strip().splitlines()
if len(data) < 2:
return
parts = [p.strip() for p in data[0].split(",") if p.strip()]
time = list(map(int, parts))
m = int(data[1].strip())
left, right = 0, sum(time)
while left < right:
mid = (left + right) // 2
if can_finish(time, m, mid):
right = mid
else:
left = mid + 1
print(left)
if __name__ == "__main__":
main()
七、JavaScript算法源码
'use strict';
const fs = require('fs');
const input = fs.readFileSync(0, 'utf8').trim().split(/\r?\n/);
if (input.length < 2) process.exit(0);
const time = input[0].split(',').map(s => s.trim()).filter(s => s.length > 0).map(Number);
const m = parseInt(input[1].trim(), 10);
function canFinish(time, m, T) {
let days = 1;
let sum = 0;
let max = 0;
for (const t of time) {
const newSum = sum + t;
const newMax = Math.max(max, t);
// 跳过当天最大题后,仍不超过 T 才能放进同一天
if (newSum - newMax <= T) {
sum = newSum;
max = newMax;
} else {
days++;
sum = t;
max = t;
if (days > m) return false;
}
}
return true;
}
let left = 0;
let right = time.reduce((a, b) => a + b, 0);
while (left < right) {
const mid = Math.floor((left + right) / 2);
if (canFinish(time, m, mid)) right = mid;
else left = mid + 1;
}
console.log(left.toString());
八、C算法源码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int canFinish(long *time, int n, int m, long T) {
int days = 1;
long sum = 0;
long max = 0;
for (int i = 0; i < n; i++) {
long t = time[i];
long newSum = sum + t;
long newMax = (max > t) ? max : t;
/* 跳过当天最大题后,仍不超过 T 才能放进同一天 */
if (newSum - newMax <= T) {
sum = newSum;
max = newMax;
} else {
days++;
sum = t;
max = t;
if (days > m) return 0;
}
}
return 1;
}
int main() {
char line1[10000];
char line2[10000];
if (!fgets(line1, sizeof(line1), stdin)) return 0;
if (!fgets(line2, sizeof(line2), stdin)) return 0;
// 解析 time 数组
long time[10000];
int n = 0;
char *token = strtok(line1, ",");
while (token != NULL) {
// 去掉前后空白
while (*token == ' ' || *token == '\t') token++;
char *end = token + strlen(token) - 1;
while (end > token && (*end == '\n' || *end == ' ' || *end == '\t')) {
*end = '\0';
end--;
}
time[n++] = atol(token);
token = strtok(NULL, ",");
}
int m = atoi(line2);
long sum = 0;
for (int i = 0; i < n; i++) sum += time[i];
long left = 0, right = sum;
while (left < right) {
long mid = (left + right) / 2;
if (canFinish(time, n, m, mid)) right = mid;
else left = mid + 1;
}
printf("%ld", left);
return 0;
}
九、C++算法源码
#include <bits/stdc++.h>
using namespace std;
bool canFinish(const vector<long long>& time, int m, long long T) {
int days = 1;
long long sum = 0;
long long mx = 0;
for (long long t : time) {
long long newSum = sum + t;
long long newMax = max(mx, t);
// 跳过当天最大题后,仍不超过 T 才能放进同一天
if (newSum - newMax <= T) {
sum = newSum;
mx = newMax;
} else {
days++;
sum = t;
mx = t;
if (days > m) return false;
}
}
return true;
}
int main() {
string line1, line2;
if (!getline(cin, line1)) return 0;
if (!getline(cin, line2)) return 0;
vector<long long> time;
stringstream ss(line1);
string token;
while (getline(ss, token, ',')) {
// 去掉前后空白
size_t l = token.find_first_not_of(" \t\r\n");
size_t r = token.find_last_not_of(" \t\r\n");
if (l != string::npos) {
time.push_back(stoll(token.substr(l, r - l + 1)));
}
}
int m = stoi(line2);
long long sum = 0;
for (auto v : time) sum += v;
long long left = 0, right = sum;
while (left < right) {
long long mid = (left + right) / 2;
if (canFinish(time, m, mid)) right = mid;
else left = mid + 1;
}
cout << left;
return 0;
}
🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 双机位C卷 200分)
🏆本文收录于,华为OD机试真题(Python/JS/C/C++)
刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新。


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



