Solving Leetcode Interviews in Seconds with AI: Count Ways to Build Rooms in an Ant Colony
Introduction
In this blog post, we will explore how to solve the LeetCode problem "1916" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like Chatmagic, we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.
Problem Statement
You are an ant tasked with adding n new rooms numbered 0 to n-1 to your colony. You are given the expansion plan as a 0-indexed integer array of length n, prevRoom, where prevRoom[i] indicates that you must build room prevRoom[i] before building room i, and these two rooms must be connected directly. Room 0 is already built, so prevRoom[0] = -1. The expansion plan is given such that once all the rooms are built, every room will be reachable from room 0. You can only build one room at a time, and you can travel freely between rooms you have already built only if they are connected. You can choose to build any room as long as its previous room is already built. Return the number of different orders you can build all the rooms in. Since the answer may be large, return it modulo 109 + 7. Example 1:
Input: prevRoom = [-1,0,1] Output: 1 Explanation: There is only one way to build the additional rooms: 0 → 1 → 2 Example 2:
Input: prevRoom = [-1,0,0,1,2] Output: 6 Explanation: The 6 ways are: 0 → 1 → 3 → 2 → 4 0 → 2 → 4 → 1 → 3 0 → 1 → 2 → 3 → 4 0 → 1 → 2 → 4 → 3 0 → 2 → 1 → 3 → 4 0 → 2 → 1 → 4 → 3 Constraints: n == prevRoom.length 2 <= n <= 105 prevRoom[0] == -1 0 <= prevRoom[i] < n for all 1 <= i < n Every room is reachable from room 0 once all the rooms are built.
Explanation
Here's the breakdown of the solution, followed by the Python code:
- Topological Sort with DFS & Combinatorics: The problem boils down to figuring out the possible building orders given dependencies. We model the dependencies as a tree. Then, we treat each subtree as a "block" to be inserted into the build order. Within each subtree, we need to count the number of possible permutations. This can be solved by considering the size of each subtree and using combinatorics.
- Subtree Size and Factorials: We perform a DFS to calculate the size of each subtree (number of nodes in the subtree). We precompute factorials and their inverses (modulo
10^9 + 7) to efficiently compute binomial coefficients during the DFS traversal. Modular Arithmetic: All calculations are done modulo
10^9 + 7to prevent overflow.Runtime Complexity: O(n log n), primarily due to modular inverse calculations (using exponentiation by squaring).
- Storage Complexity: O(n) for storing factorials, inverse factorials, subtree sizes, and the adjacency list representing the room dependencies.
Code
def countOrders(prevRoom):
n = len(prevRoom)
adj = [[] for _ in range(n)]
for i in range(1, n):
adj[prevRoom[i]].append(i)
subtree_size = [0] * n
fact = [1] * (n + 1)
inv_fact = [1] * (n + 1)
mod = 10**9 + 7
def power(a, b, m):
res = 1
a %= m
while b > 0:
if b % 2 == 1:
res = (res * a) % m
a = (a * a) % m
b //= 2
return res
def modInverse(n, m):
return power(n, m - 2, m)
for i in range(2, n + 1):
fact[i] = (fact[i - 1] * i) % mod
inv_fact[n] = modInverse(fact[n], mod)
for i in range(n - 1, 1, -1):
inv_fact[i] = (inv_fact[i + 1] * (i + 1)) % mod
def combinations(n, k, m):
if k < 0 or k > n:
return 0
num = fact[n]
den = (inv_fact[k] * inv_fact[n - k]) % m
return (num * den) % m
ans = 1
def dfs(node):
nonlocal ans
subtree_size[node] = 1
ways = 1
total_size = 0
for child in adj[node]:
dfs(child)
ways = (ways * subtree_size[child]) % mod
ways = (ways * ans) % mod # Accumulate ans from children
total_size += subtree_size[child]
ans = combinations(total_size, subtree_size[adj[node][0] if adj[node] else 0] , mod) if adj[node] else 1
for i in range (1,len(adj[node])):
ans = (ans * combinations(total_size - sum(subtree_size[adj[node][j]] for j in range(i)), subtree_size[adj[node][i]],mod))%mod
subtree_size[node] = total_size + 1
return
dfs(0)
return ans