2071. 你可以安排的最多任务数目

题目链接

2071. 你可以安排的最多任务数目 - 力扣(LeetCode)

题目描述

给你 n 个任务和 m 个工人。每个任务需要一定的力量值才能完成,需要的力量值保存在下标从 0 开始的整数数组 tasks 中,第 i 个任务需要 tasks[i] 的力量才能完成。每个工人的力量值保存在下标从 0 开始的整数数组 workers 中,第 j 个工人的力量值为 workers[j] 。每个工人只能完成 一个 任务,且力量值需要 大于等于 该任务的力量要求值(即 workers[j] >= tasks[i] )。

除此以外,你还有 pills 个神奇药丸,可以给 一个工人的力量值 增加 strength 。你可以决定给哪些工人使用药丸,但每个工人 最多 只能使用 一片 药丸。

给你下标从 0 开始的整数数组tasksworkers 以及两个整数 pillsstrength ,请你返回 最多 有多少个任务可以被完成。

题目示例

示例 1 :

plain 复制代码
输入:tasks = [3,2,1], workers = [0,3,3], pills = 1, strength = 1
输出:3
解释:
我们可以按照如下方案安排药丸:
- 给 0 号工人药丸。
- 0 号工人完成任务 2(0 + 1 >= 1)
- 1 号工人完成任务 1(3 >= 2)
- 2 号工人完成任务 0(3 >= 3)

示例 2 :

plain 复制代码
输入:tasks = [5,4], workers = [0,0,0], pills = 1, strength = 5
输出:1
解释:
我们可以按照如下方案安排药丸:
- 给 0 号工人药丸。
- 0 号工人完成任务 0(0 + 5 >= 5)

解题思路

  1. 问题描述
    • 给定两个数组 tasksworkers,分别表示任务难度和工人能力值。
    • 工人可以吃药,吃药后能力值增加 strength
    • 目标是在最多使用 pills 颗药的情况下,分配任务给工人,使得完成的任务数最大。
  2. 关键观察
    • 为了最大化完成任务数,应该让最强的工人完成最难的任务(贪心策略)。
    • 吃药的使用应该尽量用在最需要的时候,即工人不吃药无法完成任务时。
    • 可以通过二分查找来确定最多能完成的任务数。
  3. 算法选择
    • 排序 :首先对 tasksworkers 进行排序,方便后续处理。
    • 二分查找:在可能的最大任务数范围内进行二分查找,确定最多能完成的任务数。
    • 贪心策略 :在 check 方法中,使用双端队列记录当前可以完成的任务,优先让工人不吃药完成最简单的任务,必须时才吃药完成最难的任务。

题解代码

java 复制代码
class Solution {
    public int maxTaskAssign(int[] tasks, int[] workers, int pills, int strength) {
        // 对任务和工人数组进行排序,方便后续处理
        Arrays.sort(tasks);
        Arrays.sort(workers);

        // 使用二分查找确定最多能完成的任务数
        int left = 0; // 最小可能完成的任务数
        int right = Math.min(tasks.length, workers.length) + 1; // 最大可能完成的任务数 + 1
        while (left + 1 < right) {
            int mid = (left + right) >>> 1; // 无符号右移,相当于 (left + right) / 2
            // 检查是否能完成 mid 个任务
            if (check(tasks, workers, pills, strength, mid)) {
                left = mid; // 可以完成 mid 个任务,尝试更大的值
            } else {
                right = mid; // 不能完成 mid 个任务,尝试更小的值
            }
        }
        return left; // 返回最大能完成的任务数
    }

    private boolean check(int[] tasks, int[] workers, int pills, int strength, int k) {
        // 使用双端队列记录当前可以完成的任务
        Deque<Integer> validTasks = new ArrayDeque<>();
        int i = 0; // 指向 tasks 的指针
        // 遍历最强的 k 个工人
        for (int j = workers.length - k; j < workers.length; j++) {
            int w = workers[j]; // 当前工人的能力值
            // 将当前工人吃药后能完成的任务加入队列
            while (i < k && tasks[i] <= w + strength) {
                validTasks.addLast(tasks[i]);
                i++;
            }
            // 如果没有任务可以完成,直接返回 false
            if (validTasks.isEmpty()) {
                return false;
            }
            // 如果当前工人不吃药就能完成最简单的任务
            if (w >= validTasks.peekFirst()) {
                validTasks.pollFirst(); // 完成最简单的任务
                continue;
            }
            // 必须吃药才能完成任务
            if (pills == 0) { // 没有药了,无法完成任务
                return false;
            }
            pills--; // 消耗一颗药
            validTasks.pollLast(); // 完成最难的任务(贪心策略)
        }
        return true; // 所有工人都能完成任务
    }
}

复杂度分析

  1. 时间复杂度
    • 排序Arrays.sort 的时间复杂度为 O(n log n)O(m log m),其中 nm 分别是 tasksworkers 的长度。
    • 二分查找 :最多进行 O(log(min(n, m))) 次查找。
    • 每次 ** ****check**O(k),其中 k 是当前尝试的任务数。
    • 总时间复杂度O((n log n) + (m log m) + (min(n, m) * log(min(n, m)))),可以简化为 O((n + m) log (n + m))
  2. 空间复杂度
    • 排序Arrays.sort 使用 O(log n)O(log m) 的栈空间(取决于具体实现)。
    • 双端队列 :最多存储 O(k) 个元素,其中 k 是最大可能完成的任务数。
    • 总空间复杂度O(min(n, m))
相关推荐
晓觉儿2 小时前
【GPLT】2026年第十一届团队程序设计天梯赛赛后题解(已写2h,存档中)
数据结构·c++·算法·深度优先·图论
流年如夢3 小时前
自定义类型进阶:联合与枚举
java·c语言·开发语言·数据结构·数据库·c++·算法
葳_人生_蕤3 小时前
hot100——图
数据结构·算法
图码5 小时前
递归入门:从n到1的优雅打印之旅
数据结构·c++·算法·青少年编程·java-ee·逻辑回归·python3.11
大肥羊学校懒羊羊5 小时前
题解:计算约数个数
数据结构·c++·算法
良木生香5 小时前
【C++初阶】:STL——String从入门到应用完全指南(3)
c语言·开发语言·数据结构·c++·算法
qyzm5 小时前
Educational Codeforces Round 189 (Rated for Div. 2)
数据结构·python·算法
北顾笙9806 小时前
day28-数据结构力扣
数据结构·算法·leetcode
我是无敌小恐龙6 小时前
Java SE 零基础入门Day03 数组核心详解(定义+内存+遍历+算法+实战案例)
java·开发语言·数据结构·人工智能·算法·aigc·动态规划