题目链接
Leetcode.1665 完成所有任务的最少初始能量 Rating : 1901
题目描述
给你一个任务数组 tasks
,其中 tasks[i] = [actuali, minimumi]
:
actuali
是完成第 i 个任务 需要耗费 的实际能量。minimumi
是开始第 i 个任务前需要达到的最低能量。
比方说,如果任务为 ````[10, 12]```且你当前的能量为 11 ,那么你不能开始这个任务。如果你当前的能量为 13 ,你可以完成这个任务,且完成它后剩余能量为 3 。
你可以按照 任意顺序 完成任务。
请你返回完成所有任务的 最少 初始能量。
示例 1:
输入:tasks = [[1,2],[2,4],[4,8]]
输出:8
解释:
一开始有 8 能量,我们按照如下顺序完成任务:
- 完成第 3 个任务,剩余能量为 8 - 4 = 4 。
- 完成第 2 个任务,剩余能量为 4 - 2 = 2 。
- 完成第 1 个任务,剩余能量为 2 - 1 = 1 。
注意到尽管我们有能量剩余,但是如果一开始只有 7 能量是不能完成所有任务的,因为我们无法开始第 3 个任务。
示例 2:
输入:tasks = [[1,3],[2,4],[10,11],[10,12],[8,9]]
输出:32
解释:
一开始有 32 能量,我们按照如下顺序完成任务:
- 完成第 1 个任务,剩余能量为 32 - 1 = 31 。
- 完成第 2 个任务,剩余能量为 31 - 2 = 29 。
- 完成第 3 个任务,剩余能量为 29 - 10 = 19 。
- 完成第 4 个任务,剩余能量为 19 - 10 = 9 。
- 完成第 5 个任务,剩余能量为 9 - 8 = 1 。
示例 3:
输入:tasks = [[1,7],[2,8],[3,9],[4,10],[5,11],[6,12]]
输出:27
解释:
一开始有 27 能量,我们按照如下顺序完成任务:
- 完成第 5 个任务,剩余能量为 27 - 5 = 22 。
- 完成第 2 个任务,剩余能量为 22 - 2 = 20 。
- 完成第 3 个任务,剩余能量为 20 - 3 = 17 。
- 完成第 1 个任务,剩余能量为 17 - 1 = 16 。
- 完成第 4 个任务,剩余能量为 16 - 4 = 12 。
- 完成第 6 个任务,剩余能量为 12 - 6 = 6 。
提示:
- 1 < = t a s k s . l e n g t h < = 1 0 5 1 <= tasks.length <= 10^5 1<=tasks.length<=105
- 1 < = a c t u a l i < = m i n i m u m i < = 1 0 4 1 <= actuali <= minimumi <= 10^4 1<=actuali<=minimumi<=104
解法:贪心 + 排序
我们假设 p p p 为能够完成所有任务的能量。有 ( a 0 , m 0 ) , ( a 1 , m 1 ) , ( a 2 , m 2 ) , ( a 3 , m 3 ) , . . . . , ( a n − 1 , m n − 1 ) (a_0,m_0),(a_1,m_1) ,(a_2,m_2),(a_3,m_3),....,(a_{n-1},m_{n-1}) (a0,m0),(a1,m1),(a2,m2),(a3,m3),....,(an−1,mn−1),共 n n n 个任务。
按照题目的要求,如下不等式成立:
- p ≥ m 0 p \geq m_0 p≥m0
- p − a 0 ≥ m 1 p - a_0 \geq m_1 p−a0≥m1
- p − a 0 − a 1 ≥ m 2 p - a_0 - a_1 \geq m_2 p−a0−a1≥m2
- p − a 0 − a 1 − a 2 ≥ m 3 p - a_0 - a_1 - a_2 \geq m_3 p−a0−a1−a2≥m3
- …
- p − a 0 − a 1 − a 2 − a 3 − . . . − a n − 2 ≥ m n − 1 p - a_0 - a_1 - a_2 - a_3 - ...-a_{n-2} \geq m_{n-1} p−a0−a1−a2−a3−...−an−2≥mn−1
将其整理一下,得:
- p ≥ m 0 p \geq m_0 p≥m0
- p ≥ a 0 + m 1 p \geq a_0 + m_1 p≥a0+m1
- p ≥ a 0 + a 1 + m 2 p \geq a_0 +a_1 + m_2 p≥a0+a1+m2
- p ≥ a 0 + a 1 + a 2 + m 3 p \geq a_0 +a_1 + a_2 + m_3 p≥a0+a1+a2+m3
- …
- p ≥ a 0 + a 1 + a 2 + a 3 + . . . . + a n − 2 + m n − 1 p \geq a_0 +a_1 + a_2 + a_3 + .... +a_{n-2} + m_{n-1} p≥a0+a1+a2+a3+....+an−2+mn−1
由于我们要求的是最少的能量,即我们要使 p p p 的最大值 最小化。
我们现在考虑,是否能让上面 n 个不等式右侧的最大值 变小。
我们可以尝试交换相连的两项,看看会发生什么。交换 ( a i , m i ) (a_i,m_i) (ai,mi) 和 ( a i + 1 , m i + 1 ) (a_{i+1},m_{i+1}) (ai+1,mi+1)两项。
交换之前:
- p ≥ a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + m i = P ( i ) p \geq a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + m_i = P(i) p≥a0+a1+a2+a3+....+ai−1+mi=P(i)
- p ≥ a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + a i + m i + 1 = P ( i + 1 ) p \geq a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + a_i + m_{i+1} = P(i+1) p≥a0+a1+a2+a3+....+ai−1+ai+mi+1=P(i+1)
交换之后:
- p ≥ a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + m i + 1 = P ′ ( i ) p \geq a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + m_{i+1} = P'(i) p≥a0+a1+a2+a3+....+ai−1+mi+1=P′(i)
- p ≥ a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + a i + 1 + m i = P ′ ( i + 1 ) p \geq a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + a_{i+1} + m_i = P'(i+1) p≥a0+a1+a2+a3+....+ai−1+ai+1+mi=P′(i+1)
暂时只考虑这两项。交换之前的最大值为: m a x { P ( i ) , P ( i + 1 ) } max\{P(i) , P(i+1)\} max{P(i),P(i+1)};交换之后的最大值为: m a x { P ′ ( i ) , P ′ ( i + 1 ) } max\{P'(i) , P'(i+1)\} max{P′(i),P′(i+1)};
因为 P ′ ( i + 1 ) > P ( i ) P'(i+1) > P(i) P′(i+1)>P(i) , P ( i + 1 ) > P ′ ( i ) P(i+1) > P'(i) P(i+1)>P′(i)。
我们要想让交换之后的最大值变小,即 m a x { P ′ ( i ) , P ′ ( i + 1 ) } < m a x { P ( i ) , P ( i + 1 ) } max\{P'(i) , P'(i+1)\} < max\{P(i) , P(i+1)\} max{P′(i),P′(i+1)}<max{P(i),P(i+1)}。
等价于 P ′ ( i + 1 ) < P ( i + 1 ) P'(i+1) < P(i+1) P′(i+1)<P(i+1),即 a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + a i + 1 + m i < a 0 + a 1 + a 2 + a 3 + . . . . + a i − 1 + a i + m i + 1 a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + a_{i+1} + m_i < a_0 +a_1 + a_2 + a_3 + .... +a_{i-1} + a_i + m_{i+1} a0+a1+a2+a3+....+ai−1+ai+1+mi<a0+a1+a2+a3+....+ai−1+ai+mi+1。
化简得, a i − m i > a i + 1 − m i + 1 a_i - m_i > a_{i+1} - m_{i+1} ai−mi>ai+1−mi+1。
所以我们要做的就是,找出所有的满足这样条件 a i − m i > a i + 1 − m i + 1 a_i - m_i > a_{i+1} - m_{i+1} ai−mi>ai+1−mi+1 的相连两项,并将它们交换位置。这样做不一定会让最大值减小,但是绝对不会让最大值增大。
实际上我们没必要去模拟这个过程。我们只需要让 tasks
按照
a
i
−
m
i
a_i - m_i
ai−mi从小到大的排序,最后再遍历模拟这个求最大值的过程即可。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
C++代码:
class Solution {
public:
int minimumEffort(vector<vector<int>>& tasks) {
sort(tasks.begin(),tasks.end(),[&](auto &a,auto &b){
return a[0] - a[1] < b[0] - b[1];
}) ;
int p = 0 , s = 0;
for(auto &e:tasks){
p = max(p,s + e[1]);
s += e[0];
}
return p;
}
};