【Leetcode】1665. Minimum Initial Energy to Finish Tasks(配数学证明)

题目地址:

https://leetcode.com/problems/minimum-initial-energy-to-finish-tasks/

给定若干任务 A A A,每个任务有两个性质,一个是其消耗的能量,另一个是开始做它的时候必须具备的初始能量(门槛能量)。这些任务可以按任何顺序一个接着一个做。问初始至少要多少能量才能将所有任务都完成。题目保证门槛能量大于等于消耗能量。

思路是贪心。我们逆过来想, 如果我们初始有 0 0 0能量,然后经过一个个任务,回到初始状态,会是什么样的情况。我们考虑正在做任务 t t t,其消耗的能量是 t x t_x tx,门槛是 t y t_y ty,假设做完这个任务之后的能量是 z z z,那么”回滚“任务之后的能量就是 z + t x z+t_x z+tx,但是,回滚之后的能量还必须至少是 t y t_y ty,所以完成该任务之后的能量应当满足 z + t x ≥ t y z+t_x\ge t_y z+txty,即 z ≥ t y − t x z\ge t_y-t_x ztytx,所以做该任务之前的能量应该至少是 max ⁡ { t x + z , t y } \max\{t_x+z,t_y\} max{tx+z,ty}。由于 t y ≥ t x t_y\ge t_x tytx,所以我们不但要把消耗的能量 t x t_x tx补回来,还有可能需要额外补 t y − t x − z t_y-t_x-z tytxz。那么我们将所有任务按照门槛能量减去消耗能量(即可能要额外补充的能量)进行从小到大排序,然后依次回滚任务,这样就能达到额外补足的能量都尽量仅仅用于达到门槛,而不会有多余的浪费。我们猜测,按这样的顺序回滚所得的初始能量应该是最少的。

算法正确性证明:
A A A已经按照差从小到大排序,然后考虑回滚任务。如果初始能量是 w w w,然后我们考虑回滚两个任务 ( a , a + u ) (a,a+u) (a,a+u) ( b , b + v ) (b,b+v) (b,b+v),其中 u < v u<v u<v。如果先回滚任务 1 1 1,得到的必须的最少能量是 max ⁡ { a + w , a + u } \max\{a+w,a+u\} max{a+w,a+u},再回滚任务 2 2 2,得 max ⁡ { max ⁡ { a + w , a + u } + b , b + v } = max ⁡ { max ⁡ { w , u } + a + b , b + v } \max\{\max\{a+w,a+u\}+b,b+v\}=\max\{\max\{w,u\}+a+b,b+v\} max{max{a+w,a+u}+b,b+v}=max{max{w,u}+a+b,b+v};如果先回滚任务 2 2 2再任务 1 1 1,则得 max ⁡ { max ⁡ { w , v } + a + b , b + u } \max\{\max\{w,v\}+a+b,b+u\} max{max{w,v}+a+b,b+u},由于 max ⁡ { max ⁡ { w , u } + a + b , b + v } < max ⁡ { max ⁡ { w , v } + a + b , b + u } \max\{\max\{w,u\}+a+b,b+v\}<\max\{\max\{w,v\}+a+b,b+u\} max{max{w,u}+a+b,b+v}<max{max{w,v}+a+b,b+u}所以先回滚任务 1 1 1能得到更少的能量。所以按照门槛能量减去消耗能量从小到大排列来回滚,最后能得到最少的能量。所以对于任务数小于等于 2 2 2的时候,算法正确。接下来数学归纳法。假设任务数小于 n n n的时候都是对的,当任务数等于 n n n的时候,如果最优解里任务 A [ 0 ] A[0] A[0]不是第一个回滚,那么我们可以将 A [ 0 ] A[0] A[0]向前对换若干次换到首先回滚,由此所得的解一定也是最优解(因为每次对换的时候都得到了更优解,但是当前解已经最优了,所以每次对换得到的还是最优解)。接着由归纳假设,后面的 n − 1 n-1 n1个任务按照差从小到大回滚也是最优的。再由数学归纳法,所以算法正确。

代码如下:

import java.util.Arrays;

public class Solution {
    public int minimumEffort(int[][] tasks) {
        Arrays.sort(tasks, (t1, t2) -> Integer.compare(t1[1] - t1[0], t2[1] - t2[0]));
        
        int res = 0;
        // 按次序回滚任务
        for (int i = 0; i < tasks.length; i++) {
            int[] task = tasks[i];
            res = Math.max(res + task[0], task[1]);
        }
        
        return res;
    }    
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn) n n n是任务数,空间 O ( n ) O(n) O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值