Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using core interview patterns strategy.
Design an EventEmitter class. This interface is similar (but with some differences) to the one found in Node.js or the Event Target interface of the DOM. The EventEmitter should allow for subscribing to events and emitting them.
Your EventEmitter class should have the following two methods:
subscribe are referentially identical.subscribe method should also return an object with an unsubscribe method that enables the user to unsubscribe. When it is called, the callback should be removed from the list of subscriptions and undefined should be returned.Example 1:
Input:
actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"],
values = [[], ["firstEvent"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 6; }"], ["firstEvent"]]
Output: [[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]]
Explanation:
const emitter = new EventEmitter();
emitter.emit("firstEvent"); // [], no callback are subscribed yet
emitter.subscribe("firstEvent", function cb1() { return 5; });
emitter.subscribe("firstEvent", function cb2() { return 6; });
emitter.emit("firstEvent"); // [5, 6], returns the output of cb1 and cb2
Example 2:
Input:
actions = ["EventEmitter", "subscribe", "emit", "emit"],
values = [[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["firstEvent", [3,4,6]]]
Output: [[],["subscribed"],["emitted",["1,2,3"]],["emitted",["3,4,6"]]]
Explanation: Note that the emit method should be able to accept an OPTIONAL array of arguments.
const emitter = new EventEmitter();
emitter.subscribe("firstEvent, function cb1(...args) { return args.join(','); });
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
emitter.emit("firstEvent", [3, 4, 6]); // ["3,4,6"]
Example 3:
Input:
actions = ["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"],
values = [[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]]
Output: [[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[]]]
Explanation:
const emitter = new EventEmitter();
const sub = emitter.subscribe("firstEvent", (...args) => args.join(','));
emitter.emit("firstEvent", [1, 2, 3]); // ["1,2,3"]
sub.unsubscribe(); // undefined
emitter.emit("firstEvent", [4, 5, 6]); // [], there are no subscriptions
Example 4:
Input:
actions = ["EventEmitter", "subscribe", "subscribe", "unsubscribe", "emit"],
values = [[], ["firstEvent", "x => x + 1"], ["firstEvent", "x => x + 2"], [0], ["firstEvent", [5]]]
Output: [[],["subscribed"],["subscribed"],["unsubscribed",0],["emitted",[7]]]
Explanation:
const emitter = new EventEmitter();
const sub1 = emitter.subscribe("firstEvent", x => x + 1);
const sub2 = emitter.subscribe("firstEvent", x => x + 2);
sub1.unsubscribe(); // undefined
emitter.emit("firstEvent", [5]); // [7]
Constraints:
1 <= actions.length <= 10values.length === actions.lengthEventEmitter, emit, subscribe, and unsubscribe.EventEmitter action doesn't take any arguments.emit action takes between either 1 or 2 arguments. The first argument is the name of the event we want to emit, and the 2nd argument is passed to the callback functions.subscribe action takes 2 arguments, where the first one is the event name and the second is the callback function.unsubscribe action takes one argument, which is the 0-indexed order of the subscription made before.Problem summary: Design an EventEmitter class. This interface is similar (but with some differences) to the one found in Node.js or the Event Target interface of the DOM. The EventEmitter should allow for subscribing to events and emitting them. Your EventEmitter class should have the following two methods: subscribe - This method takes in two arguments: the name of an event as a string and a callback function. This callback function will later be called when the event is emitted. An event should be able to have multiple listeners for the same event. When emitting an event with multiple callbacks, each should be called in the order in which they were subscribed. An array of results should be returned. You can assume no callbacks passed to subscribe are referentially identical. The subscribe method should also return an object with an unsubscribe method that enables the user to unsubscribe. When it is
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
["EventEmitter", "emit", "subscribe", "subscribe", "emit"]
[[], ["firstEvent"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 6; }"], ["firstEvent"]]["EventEmitter", "subscribe", "emit", "emit"]
[[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["firstEvent", [3,4,6]]]["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"]
[[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]]Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2694: Event Emitter
// Auto-generated Java example from ts.
class Solution {
public void exampleSolution() {
}
}
// Reference (ts):
// // Accepted solution for LeetCode #2694: Event Emitter
// type Callback = (...args: any[]) => any;
// type Subscription = {
// unsubscribe: () => void;
// };
//
// class EventEmitter {
// private d: Map<string, Set<Callback>> = new Map();
//
// subscribe(eventName: string, callback: Callback): Subscription {
// this.d.set(eventName, (this.d.get(eventName) || new Set()).add(callback));
// return {
// unsubscribe: () => {
// this.d.get(eventName)?.delete(callback);
// },
// };
// }
//
// emit(eventName: string, args: any[] = []): any {
// const callbacks = this.d.get(eventName);
// if (!callbacks) {
// return [];
// }
// return [...callbacks].map(callback => callback(...args));
// }
// }
//
// /**
// * const emitter = new EventEmitter();
// *
// * // Subscribe to the onClick event with onClickCallback
// * function onClickCallback() { return 99 }
// * const sub = emitter.subscribe('onClick', onClickCallback);
// *
// * emitter.emit('onClick'); // [99]
// * sub.unsubscribe(); // undefined
// * emitter.emit('onClick'); // []
// */
// Accepted solution for LeetCode #2694: Event Emitter
// Auto-generated Go example from ts.
func exampleSolution() {
}
// Reference (ts):
// // Accepted solution for LeetCode #2694: Event Emitter
// type Callback = (...args: any[]) => any;
// type Subscription = {
// unsubscribe: () => void;
// };
//
// class EventEmitter {
// private d: Map<string, Set<Callback>> = new Map();
//
// subscribe(eventName: string, callback: Callback): Subscription {
// this.d.set(eventName, (this.d.get(eventName) || new Set()).add(callback));
// return {
// unsubscribe: () => {
// this.d.get(eventName)?.delete(callback);
// },
// };
// }
//
// emit(eventName: string, args: any[] = []): any {
// const callbacks = this.d.get(eventName);
// if (!callbacks) {
// return [];
// }
// return [...callbacks].map(callback => callback(...args));
// }
// }
//
// /**
// * const emitter = new EventEmitter();
// *
// * // Subscribe to the onClick event with onClickCallback
// * function onClickCallback() { return 99 }
// * const sub = emitter.subscribe('onClick', onClickCallback);
// *
// * emitter.emit('onClick'); // [99]
// * sub.unsubscribe(); // undefined
// * emitter.emit('onClick'); // []
// */
# Accepted solution for LeetCode #2694: Event Emitter
# Auto-generated Python example from ts.
def example_solution() -> None:
return
# Reference (ts):
# // Accepted solution for LeetCode #2694: Event Emitter
# type Callback = (...args: any[]) => any;
# type Subscription = {
# unsubscribe: () => void;
# };
#
# class EventEmitter {
# private d: Map<string, Set<Callback>> = new Map();
#
# subscribe(eventName: string, callback: Callback): Subscription {
# this.d.set(eventName, (this.d.get(eventName) || new Set()).add(callback));
# return {
# unsubscribe: () => {
# this.d.get(eventName)?.delete(callback);
# },
# };
# }
#
# emit(eventName: string, args: any[] = []): any {
# const callbacks = this.d.get(eventName);
# if (!callbacks) {
# return [];
# }
# return [...callbacks].map(callback => callback(...args));
# }
# }
#
# /**
# * const emitter = new EventEmitter();
# *
# * // Subscribe to the onClick event with onClickCallback
# * function onClickCallback() { return 99 }
# * const sub = emitter.subscribe('onClick', onClickCallback);
# *
# * emitter.emit('onClick'); // [99]
# * sub.unsubscribe(); // undefined
# * emitter.emit('onClick'); // []
# */
// Accepted solution for LeetCode #2694: Event Emitter
// Rust example auto-generated from ts reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (ts):
// // Accepted solution for LeetCode #2694: Event Emitter
// type Callback = (...args: any[]) => any;
// type Subscription = {
// unsubscribe: () => void;
// };
//
// class EventEmitter {
// private d: Map<string, Set<Callback>> = new Map();
//
// subscribe(eventName: string, callback: Callback): Subscription {
// this.d.set(eventName, (this.d.get(eventName) || new Set()).add(callback));
// return {
// unsubscribe: () => {
// this.d.get(eventName)?.delete(callback);
// },
// };
// }
//
// emit(eventName: string, args: any[] = []): any {
// const callbacks = this.d.get(eventName);
// if (!callbacks) {
// return [];
// }
// return [...callbacks].map(callback => callback(...args));
// }
// }
//
// /**
// * const emitter = new EventEmitter();
// *
// * // Subscribe to the onClick event with onClickCallback
// * function onClickCallback() { return 99 }
// * const sub = emitter.subscribe('onClick', onClickCallback);
// *
// * emitter.emit('onClick'); // [99]
// * sub.unsubscribe(); // undefined
// * emitter.emit('onClick'); // []
// */
// Accepted solution for LeetCode #2694: Event Emitter
type Callback = (...args: any[]) => any;
type Subscription = {
unsubscribe: () => void;
};
class EventEmitter {
private d: Map<string, Set<Callback>> = new Map();
subscribe(eventName: string, callback: Callback): Subscription {
this.d.set(eventName, (this.d.get(eventName) || new Set()).add(callback));
return {
unsubscribe: () => {
this.d.get(eventName)?.delete(callback);
},
};
}
emit(eventName: string, args: any[] = []): any {
const callbacks = this.d.get(eventName);
if (!callbacks) {
return [];
}
return [...callbacks].map(callback => callback(...args));
}
}
/**
* const emitter = new EventEmitter();
*
* // Subscribe to the onClick event with onClickCallback
* function onClickCallback() { return 99 }
* const sub = emitter.subscribe('onClick', onClickCallback);
*
* emitter.emit('onClick'); // [99]
* sub.unsubscribe(); // undefined
* emitter.emit('onClick'); // []
*/
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.