Back to blog
Dec 15, 2024
4 min read

LeetCode 630: Course Schedule III

Leetcode 630: Course Schedule III solution in Python

Problem Description

LeetCode Problem 630

There are n different online courses numbered from 1 to n. You are given an array courses where courses[i] = [durationi, lastDayi] indicate that the ith course should be taken continuously for durationi days and must be finished before or on lastDayi.

You will start on the 1st day and you cannot take two or more courses simultaneously.

Return the maximum number of courses that you can take.

 

Example 1:

Input: courses = [[100,200],[200,1300],[1000,1250],[2000,3200]] Output: 3 Explanation: There are totally 4 courses, but you can take 3 courses at most: First, take the 1st course, it costs 100 days so you will finish it on the 100th day, and ready to take the next course on the 101st day. Second, take the 3rd course, it costs 1000 days so you will finish it on the 1100th day, and ready to take the next course on the 1101st day. Third, take the 2nd course, it costs 200 days so you will finish it on the 1300th day. The 4th course cannot be taken now, since you will finish it on the 3300th day, which exceeds the closed date.

Example 2:

Input: courses = [[1,2]] Output: 1

Example 3:

Input: courses = [[3,2],[4,3]] Output: 0

 

Constraints:

  • 1 <= courses.length <= 104
  • 1 <= durationi, lastDayi <= 104

Difficulty: Hard

Tags: array, greedy, sorting, heap (priority queue)

Rating: 97.43%

Intuition

This problem can be solved using a greedy approach combined with a max heap. The key insights are:

  1. Sort courses by their deadlines (lastDay) to process them in order of urgency
  2. Keep track of total time spent on courses
  3. Use a max heap to store the durations of taken courses
  4. When we can’t fit a new course, try replacing the longest course we’ve taken if it would help

Solution

Here’s my Python solution to this problem:

class Solution:
    def scheduleCourse(self, courses: List[List[int]]) -> int:
        # Sort courses by deadline
        courses.sort(key=lambda x:x[1])

        total_time = 0
        taken = [] # max heap to store durations of taken courses

        for duration, lastDay in courses:
            # Check if we can take this course within the deadline
            if total_time + duration <= lastDay:
                total_time += duration
                heappush(taken, -duration)  # negative for max heap
            # If we can't take it direclty, try replacing the longest course
            elif taken and -taken[0] > duration:
                longest = -heappop(taken)
                total_time = total_time - longest + duration
                heappush(taken, -duration)
        
        return len(taken)

Detailed Example Walkthrough

Let’s walk through the example: courses = [[100,200],[200,1300],[1000,1250],[2000,3200]]

  1. First, sort by deadline:

    [[100,200], [1000,1250], [200,1300], [2000,3200]]
    
  2. Process each course:

    • Course 1: [100,200]

      • Time: 0 + 100 = 100 ≤ 200
      • Heap: [-100]
      • Can take it ✅
    • Course 2: [1000,1250]

      • Time: 100 + 1000 = 1100 ≤ 1250
      • Heap: [-1000, -100]
      • Can take it ✅
    • Course 3: [200,1300]

      • Time: 1100 + 200 = 1300 ≤ 1300
      • Heap: [-1000, -200, -100]
      • Can take it ✅
    • Course 4: [2000,3200]

      • Time: 1300 + 2000 = 3300 > 3200
      • Current longest course: 1000
      • Even replacing won’t help: 2300 + 2000 > 3200
      • Cannot take it ❌

Final result: 3 courses can be taken.

Complexity Analysis

  • Time Complexity: O(nlogn)O(n logn)

    • Sorting takes O(nlogn)O(n log n)
    • Heap operations take O(logk)O(log k) where k is heap size
  • Space Complexity: O(n)O(n)

    • We store at most n courses in the heap

Key Insights

  1. Sorting by deadline is crucial as it ensures we process courses in order of urgency
  2. Using a max heap allows us to efficiently track and replace the longest course when needed
  3. The greedy approach works because:
    • We always try to take courses if possible
    • When we can’t take a course, we only replace if it improves our situation
    • We always replace the longest course if needed

Practice Similar Problems