华为OD机试真题 - 编码能力提升计划 - 2024 E卷(Java、Python、JavaScript、C、C++合集)

一、题目描述

为了提升软件编程能力,小王制定了刷题计划,他选择了题库中的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、说明

五、解题思路

1、题目分析

小王共选择了 n 道题,按顺序完成,每天必须完成连续的一段题目。每天允许“看答案”一次,即可以将当天某一道题的时间变为0,从而该天的耗时为该天所有题目的时间和减去当天所选“看答案”的题目的时间(最优策略是选择耗时最大的题目来“看答案”,从而最大化时间减免)。记每一天的实际耗时为 cost=(当天题目总时间)−(当天最大题目时间)。

目标是将所有题目分成不超过 m 段,使得各天耗时的最大值 T 尽可能小。

2、解题思路

决策问题转换:对于给定的 T,判断是否存在一种分割方法,使得每一天的实际耗时不超过 T。

动态规划(DP)检查可行性:设 dp[i] 表示前 i 道题可以用最少多少天完成,使得每一段(连续一部分题目)的耗时(总和减去该段最大值)均不超过 T。初始 dp[0] = 0;从 i 出发,尝试延伸连续段 [i, j],维护累计和 sum 和当前最大值 max,每次计算 cost = sum – max。如果 cost ≤ T,则可以更新 dp[j+1] = min(dp[j+1], dp[i] + 1);最后若 dp[n] ≤ m,则 T 可行。

二分答案:由于 T 的范围在 0 到 sum(time) 内,我们采用二分搜索最小的 T,使得上述DP可行。

通过动态规划遍历所有可能的分割区间,并更新所需的最小天数。通过二分查找在答案范围内二分查找最小可行 T。

选择这两种方法主要原因是题目具有分割问题的特点,使用动态规划可准确判断某个 T 是否可行,而二分搜索可以高效地缩小答案范围。

六、Java算法源码

public class OdTest {
    // 判断在给定T下是否能在不超过m天内完成所有题目
    public static boolean canPartition(long T, int[] time, int m) {
        int n = time.length;
        int[] dp = new int[n + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0; // 0道题需要0天

        // 遍历每个起点i
        for (int i = 0; i < n; i++) {
            if (dp[i] == Integer.MAX_VALUE) continue;
            long sum = 0;
            int maxVal = 0;
            // 尝试从i开始延伸到j
            for (int j = i; j < n; j++) {
                sum += time[j];
                maxVal = Math.max(maxVal, time[j]);
                long cost = sum - maxVal;  // 当前区间的实际耗时
                if (cost <= T) {
                    dp[j + 1] = Math.min(dp[j + 1], dp[i] + 1);
                }
            }
        }
        return dp[n] <= m;
    }

    // 利用二分查找求最小的T
    public static long findMinT(int[] time, int m) {
        long low = 0;
        long high = 0;
        for (int t : time) {
            high += t;
        }
        long ans = high;
        while (low <= high) {
            long mid = low + (high - low) / 2;
            if (canPartition(mid, time, m)) {
                ans = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        return ans;
    }

    // 将输入字符串转换为整数数组,输入格式为 "a,b,c"
    public static int[] parseTime(String s) {
        String[] parts = s.split(",");
        int[] arr = new int[parts.length];
        for (int i = 0; i < parts.length; i++) {
            arr[i] = Integer.parseInt(parts[i].trim());
        }
        return arr;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        // 输入 time 数组
        String timeInput = scanner.nextLine();
        int[] timeArr = parseTime(timeInput);

        // 输入 m 值
        int m = scanner.nextInt();

        // 计算并输出结果
        long result = findMinT(timeArr, m);
        System.out.println(result);

        scanner.close();
    }
}

七、Python算法源码

# 判断是否可以分配任务,返回是否满足时间限制T
def can_partition(T, time, m):
    n = len(time)
    dp = [float('inf')] * (n + 1)  # dp[i]表示前i个任务所需的最少分配组数
    dp[0] = 0  # 初始状态,0个任务需要0组

    # 遍历每个任务
    for i in range(n):
        if dp[i] == float('inf'):
            continue  # 如果当前任务不可达,跳过
        s = 0
        max_val = 0
        # 遍历从任务i到任务n之间的所有任务
        for j in range(i, n):
            s += time[j]  # 累加任务时间
            max_val = max(max_val, time[j])  # 获取当前任务的最大时间
            cost = s - max_val  # 计算当前任务的实际花费时间
            if cost <= T:  # 如果花费时间小于等于T,更新dp数组
                dp[j + 1] = min(dp[j + 1], dp[i] + 1)

    return dp[n] <= m  # 判断最终是否能分配为m组以内

# 查找最小的T,使得任务可以分配成m组
def find_min_T(time, m):
    low = 0
    high = sum(time)  # 任务的总时间
    ans = high
    # 二分法查找最小的T
    while low <= high:
        mid = low + (high - low) // 2
        if can_partition(mid, time, m):  # 如果可以分配,尝试更小的T
            ans = mid
            high = mid - 1
        else:  # 否则增加T
            low = mid + 1
    return ans  # 返回最小的T

# 解析输入的任务时间字符串
time_input = input()
time = list(map(int, time_input.split(',')))  # 转换为列表
m = int(input())  # 输入组数m

result = find_min_T(time, m)  # 调用函数查找最小T
print(result)  # 输出结果

八、JavaScript算法源码

// 判断是否可以分配任务,返回是否满足时间限制T
function canPartition(T, time, m) {
    const n = time.length;
    const dp = new Array(n + 1).fill(Infinity);  // dp[i]表示前i个任务所需的最少分配组数
    dp[0] = 0;  // 初始状态,0个任务需要0组

    // 遍历每个任务
    for (let i = 0; i < n; i++) {
        if (dp[i] === Infinity) continue;  // 如果当前任务不可达,跳过
        let s = 0;
        let maxVal = 0;
        // 遍历从任务i到任务n之间的所有任务
        for (let j = i; j < n; j++) {
            s += time[j];  // 累加任务时间
            maxVal = Math.max(maxVal, time[j]);  // 获取当前任务的最大时间
            const cost = s - maxVal;  // 计算当前任务的实际花费时间
            if (cost <= T) {  // 如果花费时间小于等于T,更新dp数组
                dp[j + 1] = Math.min(dp[j + 1], dp[i] + 1);
            }
        }
    }
    return dp[n] <= m;  // 判断最终是否能分配为m组以内
}

// 查找最小的T,使得任务可以分配成m组
function findMinT(time, m) {
    let low = 0;
    let high = time.reduce((a, b) => a + b, 0);  // 任务的总时间
    let ans = high;
    // 二分法查找最小的T
    while (low <= high) {
        const mid = low + Math.floor((high - low) / 2);
        if (canPartition(mid, time, m)) {  // 如果可以分配,尝试更小的T
            ans = mid;
            high = mid - 1;
        } else {  // 否则增加T
            low = mid + 1;
        }
    }
    return ans;  // 返回最小的T
}

// 解析输入的任务时间字符串
const timeInput = prompt();
const time = timeInput.split(',').map(Number);  // 转换为数组
const m = parseInt(prompt(), 10);  // 输入组数m

const result = findMinT(time, m);  // 调用函数查找最小T
console.log(result);  // 输出结果

九、C算法源码

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

// 判断是否可以分配任务,返回是否满足时间限制T
int canPartition(long T, int *time, int n, int m) {
    int *dp = (int *)malloc((n + 1) * sizeof(int));
    for (int i = 0; i <= n; i++) {
        dp[i] = INT_MAX;  // 初始化为最大值
    }
    dp[0] = 0;  // 初始状态,0个任务需要0组

    // 遍历每个任务
    for (int i = 0; i < n; i++) {
        if (dp[i] == INT_MAX) continue;  // 如果当前任务不可达,跳过
        long sum = 0;
        int maxVal = 0;
        // 遍历从任务i到任务n之间的所有任务
        for (int j = i; j < n; j++) {
            sum += time[j];  // 累加任务时间
            if (time[j] > maxVal)
                maxVal = time[j];  // 获取当前任务的最大时间
            long cost = sum - maxVal;  // 计算当前任务的实际花费时间
            if (cost <= T && dp[i] + 1 < dp[j + 1]) {
                dp[j + 1] = dp[i] + 1;  // 更新dp数组
            }
        }
    }
    int feasible = (dp[n] <= m);  // 判断最终是否能分配为m组以内
    free(dp);  // 释放内存
    return feasible;
}

// 查找最小的T,使得任务可以分配成m组
long findMinT(int *time, int n, int m) {
    long low = 0;
    long high = 0;
    for (int i = 0; i < n; i++) {
        high += time[i];  // 任务的总时间
    }
    long ans = high;
    // 二分法查找最小的T
    while (low <= high) {
        long mid = low + (high - low) / 2;
        if (canPartition(mid, time, n, m)) {  // 如果可以分配,尝试更小的T
            ans = mid;
            high = mid - 1;
        } else {  // 否则增加T
            low = mid + 1;
        }
    }
    return ans;  // 返回最小的T
}

int main() {
    int n, m;
    scanf("%d", &n);  // 输入任务数量
    int *time = (int *)malloc(n * sizeof(int));
    for (int i = 0; i < n; i++) {
        scanf("%d", &time[i]);  // 输入每个任务的时间
    }
    scanf("%d", &m);  // 输入组数m

    long result = findMinT(time, n, m);  // 调用函数查找最小T
    printf("%ld\n", result);  // 输出结果

    free(time);  // 释放内存
    return 0;
}

十、C++算法源码

#include <iostream>
#include <vector>
#include <climits>
#include <sstream>
using namespace std;

// 判断是否可以分配任务,返回是否满足时间限制T
bool canPartition(long T, const vector<int>& time, int m) {
    int n = time.size();
    vector<int> dp(n + 1, INT_MAX);  // dp[i]表示前i个任务所需的最少分配组数
    dp[0] = 0;  // 初始状态,0个任务需要0组

    // 遍历每个任务
    for (int i = 0; i < n; i++) {
        if (dp[i] == INT_MAX) continue;  // 如果当前任务不可达,跳过
        long sum = 0;
        int maxVal = 0;
        // 遍历从任务i到任务n之间的所有任务
        for (int j = i; j < n; j++) {
            sum += time[j];  // 累加任务时间
            maxVal = max(maxVal, time[j]);  // 获取当前任务的最大时间
            long cost = sum - maxVal;  // 计算当前任务的实际花费时间
            if (cost <= T) {  // 如果花费时间小于等于T,更新dp数组
                dp[j + 1] = min(dp[j + 1], dp[i] + 1);
            }
        }
    }
    return dp[n] <= m;  // 判断最终是否能分配为m组以内
}

// 查找最小的T,使得任务可以分配成m组
long findMinT(const vector<int>& time, int m) {
    long low = 0;
    long high = 0;
    for (int t : time) {
        high += t;  // 任务的总时间
    }
    long ans = high;
    // 二分法查找最小的T
    while (low <= high) {
        long mid = low + (high - low) / 2;
        if (canPartition(mid, time, m)) {  // 如果可以分配,尝试更小的T
            ans = mid;
            high = mid - 1;
        } else {  // 否则增加T
            low = mid + 1;
        }
    }
    return ans;  // 返回最小的T
}

// 主函数
int main() {
    string line;
    getline(cin, line);  // 读取输入
    stringstream ss(line);
    vector<int> time;
    string temp;
    while (getline(ss, temp, ',')) {
        time.push_back(stoi(temp));  // 转换为整数数组
    }

    int m;
    cin >> m;  // 输入组数m

    long result = findMinT(time, m);  // 调用函数查找最小T
    cout << result << endl;  // 输出结果

    return 0;
}

### 华为 OD 真题文档获取方式 对于准备参加华为 OD 的技术人员来说,获取高质量的真题资料是非常重要的。以下是关于如何下载或查看华为 OD 真题的相关信息。 #### 文档下载地址 可以通过以下链接访问并下载一份名为“华为OD真题.pdf”的资源文件[^1]: - **项目地址**: [https://gitcode.com/Open-source-documentation-tutorial/ee1fb](https://gitcode.com/Open-source-documentation-tutorial/ee1fb) 此仓库提供了与华为 OD 相关的题集合,适合用于备考和技术练习。 #### 题目解析与语言支持 除了直接下载真题外,还可以通过一些博客文章获得针对不同编程语言的具体题解和指导。这些资源涵盖了多种主流开发语言,包括但不限于 PythonC++JavaJavaScript 等[^2]: - **Python** 解析: [华为 OD Python](https://blog.youkuaiyun.com/hihell/category_12199275.html) - **C++** 解析: [华为 OD C++](https://blog.youkuaiyun.com/hihell/category_12199283.html) - **C 语言** 解析: [华为 OD 考 True C](https://blog.youkuaiyun.com/hihell/category_12225286.html) - **Java** 解析: [华为 OD Java](https://blog.youkuaiyun.com/hihell/category_12201821.html) - **JavaScript** 解析: [华为 OD 考 Js](https://blog.youkuaiyun.com/hihell/category_12201825.html) - **Golang** 解析: [华为 OD 考 Golang](https://blog.youkuaiyun.com/hihell/category_12231589.html) 以上链接不仅包含了具体的题目描述,还附带了解决方案以及代码实现示例[^3]。 #### 输入验证的重要性 值得注意的是,在实际编写解决方案时应特别关注输入数据的有效性和合法性检查。例如,当处理用户数量 `n` 的情况下,需确认其是否为正整数;而对于其他参数,则要确保它们均为有效数值类型[^4]。这一步骤能够显著提升程序运行稳定性及准确性。 ```python def validate_input(n, values): """ Validate the input parameters. Args: n (int): Number of users. values (list[int]): List of system consumption values. Returns: bool: Whether all inputs are valid or not. """ if isinstance(n, int) and n > 0 and all(isinstance(x, int) for x in values): return True return False ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值