题目描述

✅ 1665. 完成所有任务的最少初始能量

image-20260929090821470

image-20260929090821607

题意分析

每个任务只有在当前能量至少为 minimum 时才能开始,完成后实际扣除 actual。任务可以重排,需要让完成全部任务所需的初始能量尽量小;题目保证 actual <= minimum。

解法:贪心排序

核心思路

[!blue]
排序依据可以从相邻两个任务推出。设任务 $A$ 的消耗、门槛为 $(a,m_A)$,任务 $B$ 为 $(b,m_B)$。先做 $A$ 再做 $B$,开始这两个任务前至少需要 $E_{AB}=\max(m_A,a+m_B)$;反过来需要 $E_{BA}=\max(m_B,b+m_A)$。

如果 $m_A-a\ge m_B-b$,移项得 $b+m_A\ge a+m_B$,同时因为 $b\ge0$,还有 $b+m_A\ge m_A$。因此 $E_{AB}\le b+m_A\le E_{BA}$,把 minimum - actual 更大的任务放在前面,不会提高这两个任务的能量要求。

交换前后,两个任务的总消耗都是 $a+b$,前面的任务和后面的剩余能量都不变。因此可以不断交换差值顺序颠倒的相邻任务,最终得到按 minimum - actual 降序排列的全局最优顺序;差值相同时无需额外规定先后。

顺序确定后,用 spent 记录此前实际消耗。若初始能量为 $E$,当前任务开始前剩余 $E-spent$,必须满足 $E\ge spent+minimum$。取所有任务的这类约束的最大值,就是既必要又足够的初始能量。每轮先记录约束,再把当前 actual 累加到 spent;由于 actual <= minimum,成功启动也保证完成后能量不会为负。

解题步骤

  1. 按门槛与实际消耗之差降序排序。
  2. 初始化已消耗能量与答案。
  3. 先用 spent+minimum 更新答案,再增加 actual。
  4. 返回最大启动约束。

代码实现

class Solution {
    public int minimumEffort(int[][] tasks) {
        // 按启动门槛减实际消耗的差值降序排列。
        Arrays.sort(tasks, (a, b) -> Integer.compare(b[1] - b[0], a[1] - a[0]));
        int answer = 0;
        int spent = 0;

        for (int[] task : tasks) {
            // 当前任务对初始能量的要求,还要加上此前实际消耗。
            answer = Math.max(answer, spent + task[1]);
            spent += task[0];
        }

        return answer;
    }
}
import "sort"

func minimumEffort(tasks [][]int) int {
    // 按启动门槛减实际消耗的差值降序排列。
    sort.Slice(tasks, func(i, j int) bool {
        left := tasks[i][1] - tasks[i][0]
        right := tasks[j][1] - tasks[j][0]
        return left > right
    })

    answer, spent := 0, 0
    for _, task := range tasks {
        // 当前任务对初始能量的要求,还要加上此前实际消耗。
        if need := spent + task[1]; need > answer {
            answer = need
        }
        spent += task[0]
    }
    return answer
}

复杂度分析

  • 时间复杂度:$O(n\log(n+1))$,排序后线性扫描。
  • 空间复杂度:扫描额外 $O(1)$;计入排序后,Java 最坏为 $O(n)$,Go 排序调用栈为 $O(\log n)$。输入会被重排。

关键点总结

[!green]

  • 门槛是启动要求,实际消耗才从能量中扣除。
  • 排序依据来自两任务交换,不是只比较门槛大小。
  • 答案约束在累计当前消耗之前计算。

易错点总结

[!yellow]

  • 差值按升序排列:把更需要保留能量的任务拖到后面。
  • 用 minimum 累加 spent:误把门槛当成真实消耗。
  • 只取所有门槛最大值:漏掉任务前已经消耗的能量。

相似题目

题目 难度 关联与区别
174. 地下城游戏 困难 只看总消耗不足以保证过程中资源不低于门槛,两题都要考虑最坏前缀需求。
1029. 两地调度 中等 同样通过交换论证推导两字段差值作为排序关键量,本题差值是最低门槛与实际消耗之差。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2021/37736577
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!