Suppose you are given the following code:
class FooBar {
public void foo() {
for (int i = 0; i < n; i++) {
print("foo");
}
}
public void bar() {
for (int i = 0; i < n; i++) {
print("bar");
}
}
}
The same instance of FooBar will be passed to two different threads:
A will call foo(), whileB will call bar().Modify the given program to output "foobar" n times.
Example 1:
Input: n = 1 Output: "foobar" Explanation: There are two threads being fired asynchronously. One of them calls foo(), while the other calls bar(). "foobar" is being output 1 time.
Example 2:
Input: n = 2 Output: "foobarfoobar" Explanation: "foobar" is being output 2 times.
Constraints:
1 <= n <= 1000When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The basic idea is to print 'Foo' and 'Bar' a certain number of times, but always alternating them. A brute force method simply tries printing each word ('Foo' or 'Bar') in order and checks if the sequence has reached the total number of times requested.
Here's how the algorithm would work step-by-step:
def print_foo_bar_alternately(number_of_prints):
foo_bar_counter = 0
print_foo = True
# Keep printing until we've reached the desired number of prints
while foo_bar_counter < number_of_prints:
if print_foo:
print("Foo")
# Set the flag so next time it prints 'Bar'
print_foo = False
else:
print("Bar")
# Set the flag so next time it prints 'Foo'
print_foo = True
# Increment the counter for each print to track total prints
foo_bar_counter += 1The goal is to print 'Foo' and 'Bar' alternately, but only after one has finished printing completely. We'll use a communication system (like flags) to signal when each word is ready to be printed by the other.
Here's how the algorithm would work step-by-step:
import threading
class FooBar:
def __init__(self, n):
self.n = n
self.foo_done = threading.Lock()
self.bar_done = threading.Lock()
self.bar_done.acquire()
def foo(self, printFoo):
for i in range(self.n):
# Bar must finish printing before Foo starts
self.foo_done.acquire()
printFoo()
# Signal that Foo is done printing
self.bar_done.release()
def bar(self, printBar):
for i in range(self.n):
# Wait for Foo to finish printing
self.bar_done.acquire()
printBar()
# Signal that Bar is done printing
self.foo_done.release()| Case | How to Handle |
|---|---|
| n is zero | Print nothing as there are no iterations to perform; return immediately. |
| n is a very large number (potential integer overflow) | Ensure the loop counter variable is of a type that can hold the maximum value of n to prevent integer overflow issues. |
| The program is interrupted or encounters an exception during execution | Use try-finally blocks to ensure any necessary cleanup (e.g., releasing locks) occurs even if an exception is thrown. |
| Multi-threading issues if using threads/processes. | Use synchronization primitives (e.g., locks, semaphores) to prevent race conditions when accessing shared resources. |
| Memory exhaustion if repeatedly printing to a very long output stream | If memory exhaustion is a real concern, flush output stream periodically or use a bounded buffer. |
| Negative input values for n. | Treat negative input as an invalid argument and throw an exception or handle it gracefully. |
| System clock issues could affect timing if implemented with sleep commands | If timing precision is crucial, use monotonic clocks instead of system time. |
| Extreme values close to integer limits for internal calculations | Use appropriate data types (e.g., long) to accommodate potentially large intermediate results and prevent overflows. |