1. 问题描述:
给你一个任务数组 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 <= tasks.length <= 10^5
1 <= actuali <= minimumi <= 10^4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-initial-energy-to-finish-tasks
2. 思路分析:
①因为数据规模比较大,而且最小范围与最大范围是比较容易确定的,最小的范围应该是task数组中需要达到的最低能量的最大值,最大的范围应该是数组中所有需要达到的最低能量的和,所以比较容易想到的是二分查找模型,我们可以二分查找中间范围mid,其中mid表示的是完成所有任务所需最少的能量,也就是我们最终需要求解的答案,我们通过二分查找来逐步逼近这个答案,二分查找的另外一个关键点是如何判断当前的mid是否满足条件来确定左右范围更新的策略(检测函数的编写),从题目中可以知道完成任务的顺序不同最终所需要的能量也是不一样的,所以关键在于这个完成任务的顺序,一开始的时候没有想到比较好的方法来制定这个策略,后面在力扣中发现可以使用[actuali, minimumi]
两者的差值决定先完成哪一个任务,具体的做法是可以根据actuali - minimumi
差值从小到大进行排序,差值越小说明一开始的时候所需要的能量较大而且完成这项任务消耗的能量较小(类似于贪心的思想),所以我们应该先要完成这些任务,所以可以使用根据上面两者差值的大小排序之后按顺序完成这些任务,这样我们就可以使用一个函数来检测当前的mid是否能够完成所有的任务,然后就可以更新下一次二分查找的范围了
② 除了①中比较好想到的二分查找的思路之外,在力扣的题解中发现一个不错的思路,题解网址,但是感觉比较难想出来
3. 代码如下:
from typing import List
class Solution:
def check(self, tasks: List[List[int]], mid):
for i in range(len(tasks)):
if tasks[i][1] > mid: return False
mid -= tasks[i][0]
return True
def minimumEffort(self, tasks: List[List[int]]) -> int:
# 使用lambda表达式对其排序
tasks.sort(key=lambda x: -(x[1] - x[0]))
l, r = tasks[0][1], 0
for i in range(len(tasks)):
for j in range(len(tasks[0])):
r += tasks[i][j]
res = 0
while l <= r:
mid = (l + r) // 2
if self.check(tasks, mid):
res = mid
r = mid - 1
else:
l = mid + 1
return res
from typing import List
class Solution:
def minimumEffort(self, tasks: List[List[int]]) -> int:
tasks.sort(key=lambda x: x[0] - x[1])
p = suma = 0
for ai, mi in tasks:
p = max(p, suma + mi)
suma += ai
return p