#1494

Parallel Courses II

Hard
Dynamic ProgrammingBit ManipulationGraph TheoryBitmaskDynamic ProgrammingBit Manipulation
LeetCode ↗

Approaches

Brute ForceOptimal
Complexity Comparison
Brute ForceOptimal Solution
Time
O(n²)
O(n * 2^n)
Space
O(1)
O(2^n)
💡

Intuition

Time O(n * 2^n)Space O(2^n)

The optimal solution leverages dynamic programming and bit manipulation to efficiently track which courses have been taken and which can be taken next, minimizing the number of semesters needed. This approach is more efficient than brute force because it avoids redundant calculations.

⚙️

Algorithm

3 steps
  1. 1Step 1: Create a graph representation of courses and their prerequisites.
  2. 2Step 2: Use a bitmask to represent the set of courses taken.
  3. 3Step 3: Use dynamic programming to calculate the minimum semesters needed by exploring valid combinations of courses that can be taken each semester.
solution.py30 lines
1def minNumberOfSemesters(n, relations, k):
2    from collections import defaultdict
3    graph = defaultdict(list)
4    indegree = [0] * (n + 1)
5    for prev, next in relations:
6        graph[prev].append(next)
7        indegree[next] += 1
8
9    dp = [float('inf')] * (1 << n)
10    dp[0] = 0
11
12    for mask in range(1 << n):
13        available = []
14        for i in range(1, n + 1):
15            if (mask & (1 << (i - 1))) == 0 and indegree[i] == 0:
16                available.append(i)
17        for i in range(1 << len(available)):
18            if bin(i).count('1') <= k:
19                next_mask = mask
20                for j in range(len(available)):
21                    if i & (1 << j):
22                        next_mask |= (1 << (available[j] - 1))
23                        for neighbor in graph[available[j]]:
24                            indegree[neighbor] -= 1
25                dp[next_mask] = min(dp[next_mask], dp[mask] + 1)
26                for j in range(len(available)):
27                    if i & (1 << j):
28                        for neighbor in graph[available[j]]:
29                            indegree[neighbor] += 1
30    return dp[(1 << n) - 1]

Complexity note: The time complexity is O(n * 2^n) because we are iterating through all subsets of courses (2^n) and for each subset, we check the available courses (up to n). The space complexity is O(2^n) for storing the dp array.

  • 1Understanding bit manipulation is crucial for optimizing state representation.
  • 2Dynamic programming can significantly reduce redundant calculations.

Solutions and explanations are original Tejav content. Problem titles © LeetCode — use the LeetCode button above for the full problem statement.