Skip to content

Commit 08db92d

Browse files
committed
Added solution to leetcode problem no 1114
1 parent e9d2803 commit 08db92d

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
---
2+
3+
id: print-in-order
4+
title: Print in Order
5+
level: medium
6+
sidebar_label: Print in Order
7+
tags:
8+
- Concurrency
9+
- Threads
10+
- Java
11+
- Python
12+
- C++
13+
description: "This document provides solutions for the Print in Order problem on LeetCode."
14+
15+
---
16+
17+
## Problem Description
18+
19+
Suppose we have a class:
20+
21+
```java
22+
class Foo {
23+
public void first() { print("first"); }
24+
public void second() { print("second"); }
25+
public void third() { print("third"); }
26+
}
27+
```
28+
29+
The same instance of `Foo` will be passed to three different threads. Thread A will call `first()`, thread B will call `second()`, and thread C will call `third()`. Design a mechanism and modify the program to ensure that `second()` is executed after `first()`, and `third()` is executed after `second()`.
30+
31+
### Examples
32+
33+
**Example 1:**
34+
```
35+
Input: [1,2,3]
36+
Output: "firstsecondthird"
37+
```
38+
39+
**Example 2:**
40+
```
41+
Input: [1,3,2]
42+
Output: "firstsecondthird"
43+
```
44+
45+
### Constraints:
46+
47+
- The input array is a permutation of [1, 2, 3].
48+
49+
---
50+
51+
## Approach to Solve the Print in Order Problem
52+
53+
To ensure that the methods are executed in the correct order, we can use synchronization mechanisms such as locks, condition variables, or semaphores.
54+
55+
### Approach
56+
57+
1. **Using Locks and Condition Variables:**
58+
- Use a lock to ensure mutual exclusion.
59+
- Use condition variables to signal when a method can proceed.
60+
61+
2. **Using Semaphores:**
62+
- Use semaphores to control the order of execution.
63+
- Initialize semaphores in such a way that they ensure the correct sequence.
64+
65+
#### Code in Different Languages
66+
67+
### C++
68+
```cpp
69+
#include <iostream>
70+
#include <functional>
71+
#include <mutex>
72+
#include <condition_variable>
73+
74+
class Foo {
75+
private:
76+
std::mutex mtx;
77+
std::condition_variable cv;
78+
int step;
79+
80+
public:
81+
Foo() {
82+
step = 1;
83+
}
84+
85+
void first(std::function<void()> printFirst) {
86+
std::unique_lock<std::mutex> lock(mtx);
87+
printFirst();
88+
step = 2;
89+
cv.notify_all();
90+
}
91+
92+
void second(std::function<void()> printSecond) {
93+
std::unique_lock<std::mutex> lock(mtx);
94+
cv.wait(lock, [&]() { return step == 2; });
95+
printSecond();
96+
step = 3;
97+
cv.notify_all();
98+
}
99+
100+
void third(std::function<void()> printThird) {
101+
std::unique_lock<std::mutex> lock(mtx);
102+
cv.wait(lock, [&]() { return step == 3; });
103+
printThird();
104+
}
105+
};
106+
```
107+
108+
### Java
109+
```java
110+
import java.util.concurrent.Semaphore;
111+
112+
class Foo {
113+
private Semaphore firstDone = new Semaphore(0);
114+
private Semaphore secondDone = new Semaphore(0);
115+
116+
public Foo() {
117+
}
118+
119+
public void first(Runnable printFirst) throws InterruptedException {
120+
printFirst.run();
121+
firstDone.release();
122+
}
123+
124+
public void second(Runnable printSecond) throws InterruptedException {
125+
firstDone.acquire();
126+
printSecond.run();
127+
secondDone.release();
128+
}
129+
130+
public void third(Runnable printThird) throws InterruptedException {
131+
secondDone.acquire();
132+
printThird.run();
133+
}
134+
}
135+
```
136+
137+
### Python
138+
```python
139+
from threading import Lock
140+
141+
class Foo:
142+
def __init__(self):
143+
self.lock1 = Lock()
144+
self.lock2 = Lock()
145+
self.lock1.acquire()
146+
self.lock2.acquire()
147+
148+
def first(self, printFirst: 'Callable[[], None]') -> None:
149+
# printFirst() outputs "first". Do not change or remove this line.
150+
printFirst()
151+
self.lock1.release()
152+
153+
def second(self, printSecond: 'Callable[[], None]') -> None:
154+
with self.lock1:
155+
# printSecond() outputs "second". Do not change or remove this line.
156+
printSecond()
157+
self.lock2.release()
158+
159+
def third(self, printThird: 'Callable[[], None]') -> None:
160+
with self.lock2:
161+
# printThird() outputs "third". Do not change or remove this line.
162+
printThird()
163+
```
164+
165+
### Complexity
166+
167+
- **Time Complexity:** The time complexity is dependent on the time taken by the `first()`, `second()`, and `third()` methods to print their respective strings. The synchronization mechanism adds minimal overhead.
168+
- **Space Complexity:** $O(1)$ - We are using a constant amount of space for locks and semaphores.
169+
170+
### Summary
171+
172+
This approach uses synchronization primitives like locks and semaphores to ensure that the methods are executed in the specified order. The use of these primitives ensures that `second()` waits for `first()` to complete, and `third()` waits for `second()` to complete, thus maintaining the required order of execution.

0 commit comments

Comments
 (0)