【Leetcode】630. Course Schedule III(配数学证明)

题目地址:

https://leetcode.com/problems/course-schedule-iii/

n n n门课 A A A,每门课有个持续时间和截止时间,以数组 ( t , d ) (t,d) (t,d)来表示。每门课必须在截止时间 d d d或者之前上完。问最多能上多少门课。同一时刻不能上两门课以上。

先将所有课按照截止日期排序。设 f [ i ] f[i] f[i]是只考虑前 i i i门课的情况下的所有合法方案中,选课个数最多并且耗时最少的那个方案的选课个数(这里合法方案是指上课没有超过截止日期,并且同一时刻只上了一门课的方案。是先从合法方案里找到选课数最多的那些,然后在从这些中找到总耗时最少的,当然满足这个条件的方案仍然可能不唯一,任选一个即可。但是我们可以证明,无论是哪个,它们含哪些课程耗时,是完全相同的)。我们考虑 f [ i + 1 ] f[i+1] f[i+1],也就是再考虑 A [ i + 1 ] A[i+1] A[i+1]这门课,首先容易知道 f [ i ] ≤ f [ i + 1 ] ≤ f [ i ] + 1 f[i]\le f[i+1]\le f[i]+1 f[i]f[i+1]f[i]+1。如果 A [ i + 1 ] A[i+1] A[i+1]这门课可以接到 f [ i ] f[i] f[i]这个方案的最后来上,并且不超过 A [ i + 1 ] A[i+1] A[i+1]的截止的话,那么就存在一个选课个数是 f [ i ] + 1 f[i]+1 f[i]+1的解了,显然这个就是最优解,并且时长也是最短的,所以此时 f [ i + 1 ] = f [ i ] + 1 f[i+1]=f[i]+1 f[i+1]=f[i]+1;如果 A [ i + 1 ] A[i+1] A[i+1]这门课接到 f [ i ] f[i] f[i]这个方案的最后来上,但是超过 A [ i + 1 ] A[i+1] A[i+1]的截止时间的话,那么 f [ i + 1 ] = f [ i ] f[i+1]=f[i] f[i+1]=f[i],由于我们想找耗时最少的方案,所以可以把之前 i i i门课再并上 A [ i + 1 ] A[i+1] A[i+1] i + 1 i+1 i+1门课里耗时最长的那个给踢掉,再把 A [ i + 1 ] A[i+1] A[i+1]这门课拼在后面(当然也有可能是 A [ i + 1 ] A[i+1] A[i+1]自己被踢掉了),这样仍然是个合法方案,并且耗时也是最小的。最后返回 f [ n ] f[n] f[n]即可。

具体算法可以这样来做:
1、对所有课程按截止日期从小到大排序,开个最大堆,存每门课的耗时;
2、遍历课程,并维护一个变量,记录总耗时;
3、先将当前课程接在方案后面(即入堆),并累加总耗时,如果总耗时超过了当前课程截止日期,那么就把堆中耗时最长的那个课程踢掉,并将其从总耗时中删除;
4、遍历完所有课程后返回堆的size。

代码如下:

import java.util.Arrays;
import java.util.PriorityQueue;

public class Solution {
    public int scheduleCourse(int[][] courses) {
        Arrays.sort(courses, (c1, c2) -> Integer.compare(c1[1], c2[1]));
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>((c1, c2) -> -Integer.compare(c1, c2));
    
        int total = 0;
        for (int[] course : courses) {
            total += course[0];
            maxHeap.offer(course[0]);
            if (total > course[1]) {
                total -= maxHeap.poll();
            }
        }
        
        return maxHeap.size();
    }
}

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值