Implement course scheduling and rate limiter analysis
Company: Snowflake
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: hard
Interview Round: Technical Screen
You are given two independent coding problems.
---
### Problem 1: Course Scheduling
You are planning to take a set of courses and are given prerequisite relationships between them.
- There are `n` courses labeled from `0` to `n - 1`.
- You are given a list of prerequisite pairs `prerequisites`, where each pair `[a, b]` means you must complete course `b` before you can take course `a`.
#### Task A
Determine whether it is possible to finish all `n` courses.
- Return `true` if you can complete all courses (i.e., the prerequisite graph has no cycle); otherwise return `false`.
You should specify the time and space complexity of your algorithm.
#### Task B (Follow-up)
Assume:
- Each course takes exactly one semester to complete.
- In any given semester, you may take any number of courses, as long as you have completed all of their prerequisites in earlier semesters.
If it is possible to finish all courses, compute the **minimum number of semesters** required to complete all `n` courses. If it is impossible (due to cycles), indicate that it cannot be done.
Describe an efficient algorithm for this and its time and space complexity.
You may assume:
- `1 <= n <= 10^5`.
- `0 <= len(prerequisites) <= 2 * 10^5`.
---
### Problem 2: Analyze Dropped Requests Under a Rate Limiter
You are running a social media website that suddenly went viral. To protect your backend, you added a rate limiter. Now you want to analyze logs to determine which requests would be dropped by this limiter.
You are given:
- An array `requests`, where the **index** is the request ID (0-based), and the **value** `requests[i]` is the time in seconds when the `i`-th request arrived.
- The array `requests` is non-decreasing (requests are logged in arrival order; multiple requests can have the same timestamp if they arrive in the same second).
Your rate limiter enforces the following rules:
1. At most **3 requests per second** can be processed.
2. At most **20 requests per any sliding 10-second window** can be processed.
Formally:
- For rule (1): For any timestamp `t`, among all requests with arrival time exactly `t`, at most 3 can be processed; any additional requests arriving at time `t` must be dropped.
- For rule (2): For any request arriving at time `t`, consider all requests with arrival times in the interval `[t - 9, t]` (inclusive). If processing this request would cause the **total number of processed requests** in that interval to exceed 20, then this request must be dropped.
Rules are applied in arrival order:
- For each request in index order, first consider whether it is dropped due to rule (1) or rule (2), taking into account only previously processed requests (not the dropped ones).
- If a request is dropped by **either** rule, it is not counted as processed for any future checks.
#### Task
Given the array `requests`, **return a list of the times of all dropped requests**, in the order they appear in the input.
You should:
- Clearly define the algorithm you use to determine dropped requests.
- Aim for an efficient solution that can handle up to `10^5` requests.
- State the time and space complexity of your approach.
You may assume:
- `1 <= len(requests) <= 10^5`.
- `0 <= requests[i] <= 10^9`.
- `requests` is non-decreasing.
Quick Answer: This combined question evaluates proficiency in graph-based dependency reasoning (cycle detection and course scheduling) and time-series request processing (rate-limiter behavior and sliding-window request counting) within the Coding & Algorithms domain.
Part 1: Course Scheduling - Can Finish All Courses
You are given n courses labeled from 0 to n - 1 and a list of prerequisite pairs. Each pair [a, b] means course b must be completed before course a. Determine whether it is possible to finish all courses. This is possible exactly when the prerequisite graph contains no directed cycle.
Constraints
- 1 <= n <= 100000
- 0 <= len(prerequisites) <= 200000
- Each prerequisite is a pair [a, b]
- 0 <= a, b < n
Examples
Input: (1, [])
Expected Output: True
Explanation: There is only one course and no prerequisites, so it can be completed.
Input: (2, [[1, 0]])
Expected Output: True
Explanation: Take course 0 first, then course 1.
Hints
- Model courses as nodes in a directed graph, with an edge b -> a for each prerequisite [a, b].
- A directed graph can be fully topologically sorted if and only if it has no cycle.
Part 2: Course Scheduling Follow-up - Minimum Number of Semesters
You are given n courses labeled from 0 to n - 1 and prerequisite pairs [a, b], meaning course b must be completed before course a. Each course takes exactly one semester. In a semester, you may take any number of courses as long as all their prerequisites were completed in earlier semesters. Return the minimum number of semesters needed to finish all courses, or -1 if it is impossible due to a cycle.
Constraints
- 1 <= n <= 100000
- 0 <= len(prerequisites) <= 200000
- Each prerequisite is a pair [a, b]
- 0 <= a, b < n
- Any number of available courses may be taken in the same semester
Examples
Input: (1, [])
Expected Output: 1
Explanation: A single course with no prerequisites takes one semester.
Input: (3, [[1, 0], [2, 0]])
Expected Output: 2
Explanation: Take course 0 in semester 1, then courses 1 and 2 together in semester 2.
Hints
- Use topological sorting. All courses with indegree 0 can be taken in the first semester.
- The semester for a course is one more than the maximum semester among its prerequisites.
Part 3: Analyze Dropped Requests Under a Rate Limiter
You are given a non-decreasing array requests, where requests[i] is the arrival time in seconds of request i. A rate limiter processes requests in input order and drops a request if either rule would be violated: at most 3 processed requests may have the exact same timestamp, and at most 20 processed requests may fall inside any inclusive 10-second sliding window [t - 9, t] for a request arriving at time t. Dropped requests are not counted for future checks. Return the times of all dropped requests in input order.
Constraints
- 1 <= len(requests) <= 100000
- 0 <= requests[i] <= 1000000000
- requests is non-decreasing
- Only processed requests count toward future rate-limit checks
Examples
Input: ([0],)
Expected Output: []
Explanation: A single request does not violate either rate limit.
Input: ([5, 5, 5, 5, 5],)
Expected Output: [5, 5]
Explanation: Only the first 3 requests at time 5 are processed; the 4th and 5th are dropped by the per-second rule.
Hints
- Keep a queue of processed request times that are still inside the current 10-second window.
- Because requests are processed in sorted arrival order, a single counter is enough to track how many processed requests have the current timestamp.