Watch 7 video solutions for Print Zero Even Odd, a medium level problem involving Concurrency. This walkthrough by TheAnalyticGuy has 2,093 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
You have a function printNumber that can be called with an integer parameter and prints it to the console.
printNumber(7) prints 7 to the console.You are given an instance of the class ZeroEvenOdd that has three functions: zero, even, and odd. The same instance of ZeroEvenOdd will be passed to three different threads:
zero() that should only output 0's.even() that should only output even numbers.odd() that should only output odd numbers.Modify the given class to output the series "010203040506..." where the length of the series must be 2n.
Implement the ZeroEvenOdd class:
ZeroEvenOdd(int n) Initializes the object with the number n that represents the numbers that should be printed.void zero(printNumber) Calls printNumber to output one zero.void even(printNumber) Calls printNumber to output one even number.void odd(printNumber) Calls printNumber to output one odd number.
Example 1:
Input: n = 2 Output: "0102" Explanation: There are three threads being fired asynchronously. One of them calls zero(), the other calls even(), and the last one calls odd(). "0102" is the correct output.
Example 2:
Input: n = 5 Output: "0102030405"
Constraints:
1 <= n <= 1000Problem Overview: You control three threads: one prints 0, one prints even numbers, and one prints odd numbers. The output must follow the pattern 0 1 0 2 0 3 ... 0 n. The challenge is coordinating thread execution so the correct thread prints at the correct time without race conditions.
Approach 1: Using Mutex and Condition Variables (O(n) time, O(1) space)
This approach coordinates threads using a shared mutex and condition variables. A shared state variable determines which thread should run next: zero, odd, or even. Each thread acquires the mutex, checks the state, and waits on a condition variable if it is not its turn. When the correct thread prints its value, it updates the state and signals the next waiting thread using notify or signal. The zero thread runs before every number, alternating between odd and even threads depending on the current value. The complexity is O(n) because each number is printed once, and the synchronization overhead is constant. Space complexity is O(1) since only a few shared variables are maintained.
This technique relies on primitives from concurrency such as mutex locks and condition variables. It provides fine-grained control and avoids busy waiting. Systems programming interviews sometimes prefer this method because it demonstrates understanding of thread coordination and lock-based synchronization.
Approach 2: Using Semaphores (O(n) time, O(1) space)
Semaphores simplify the coordination logic by directly controlling which thread is allowed to proceed. Three semaphores are used: one for the zero thread, one for odd numbers, and one for even numbers. The zero semaphore starts with value 1 so the zero thread prints first. After printing 0, the zero thread releases either the odd or even semaphore depending on the next number. The corresponding thread prints its value and then releases the zero semaphore to continue the sequence.
This pattern ensures only one thread runs at a time while preserving the required order. Every print operation corresponds to one semaphore acquire and release, giving O(n) total operations. Space usage remains O(1). Semaphores are a classic tool in concurrency control and often appear in interview problems involving ordered thread execution. If you are comfortable with semaphores, this implementation is typically shorter and easier to reason about than condition variables.
Recommended for interviews: The semaphore solution is usually the cleanest and easiest to explain under time pressure. It clearly expresses which thread runs next using semaphore permits. The mutex + condition variable approach is also valid and demonstrates deeper knowledge of synchronization primitives. Showing the ability to model thread states and prevent race conditions is what interviewers typically look for in concurrency problems.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Mutex and Condition Variables | O(n) | O(1) | When demonstrating low-level thread coordination and lock-based synchronization |
| Semaphores | O(n) | O(1) | Preferred for clarity and simpler ordered thread execution logic |