Custom Interval
Problem
**Function **customInterval
Given a function fn, a number delay and a number period, return a number
id.
customInterval is a function that should execute the provided function fn
at intervals based on a linear pattern defined by the formula `delay + period
- count`.
The count in the formula represents the number of times the interval has been executed starting from an initial value of 0.
FunctioncustomClearInterval
Given the id. id is the returned value from the function customInterval.
customClearInterval should stop executing provided function fn at intervals.
Note: The setTimeout and setInterval functions in Node.js return an object, not a number.
Examples
Example 1:
Input: delay = 50, period = 20, cancelTime = 225
Output: [50,120,210]
Explanation:
const t = performance.now()
const result = []
const fn = () => {
result.push(Math.floor(performance.now() - t))
}
const id = customInterval(fn, delay, period)
setTimeout(() => {
customClearInterval(id)
}, 225)
50 + 20 * 0 = 50 // 50ms - 1st function call
50 + 20 * 1 = 70 // 50ms + 70ms = 120ms - 2nd function call
50 + 20 * 2 = 90 // 50ms + 70ms + 90ms = 210ms - 3rd function call
Example 2:
Input: delay = 20, period = 20, cancelTime = 150
Output: [20,60,120]
Explanation:
20 + 20 * 0 = 20 // 20ms - 1st function call
20 + 20 * 1 = 40 // 20ms + 40ms = 60ms - 2nd function call
20 + 20 * 2 = 60 // 20ms + 40ms + 60ms = 120ms - 3rd function call
Example 3:
Input: delay = 100, period = 200, cancelTime = 500
Output: [100,400]
Explanation:
100 + 200 * 0 = 100 // 100ms - 1st function call
100 + 200 * 1 = 300 // 100ms + 300ms = 400ms - 2nd function call
Constraints:
20 <= delay, period <= 25020 <= cancelTime <= 1000
Solution
Method 1 – Recursive setTimeout with Linear Interval
Intuition
The key idea is to use setTimeout recursively to schedule the next call with a delay that increases linearly according to the formula delay + period * count. We keep track of the timer and count, and provide a way to clear the interval using a map.
Approach
- Use a map to store active intervals by id (object or number).
- In
customInterval(fn, delay, period), schedule the first call withsetTimeoutafterdelayms. - After each call, increment the count and schedule the next call with
delay + period * countms. - Store the timer id and a flag in the map to allow cancellation.
- In
customClearInterval(id), clear the timer and set the flag to stop further scheduling.
Code
JavaScript
const customIntervalMap = new Map();
function customInterval(fn, delay, period) {
let count = 0;
let active = { stopped: false };
function tick() {
if (active.stopped) return;
fn();
count++;
const t = setTimeout(tick, delay + period * count);
active.timer = t;
}
const t = setTimeout(tick, delay);
active.timer = t;
customIntervalMap.set(active, active);
return active;
}
function customClearInterval(id) {
if (id && id.timer) {
clearTimeout(id.timer);
id.stopped = true;
customIntervalMap.delete(id);
}
}
TypeScript
const customIntervalMap = new Map<object, object>();
function customInterval(fn: () => void, delay: number, period: number): object {
let count = 0;
const active: { stopped: boolean; timer?: ReturnType<typeof setTimeout> } = { stopped: false };
function tick() {
if (active.stopped) return;
fn();
count++;
const t = setTimeout(tick, delay + period * count);
active.timer = t;
}
const t = setTimeout(tick, delay);
active.timer = t;
customIntervalMap.set(active, active);
return active;
}
function customClearInterval(id: { stopped: boolean; timer?: ReturnType<typeof setTimeout> }) {
if (id && id.timer) {
clearTimeout(id.timer);
id.stopped = true;
customIntervalMap.delete(id);
}
}
Complexity
- ⏰ Time complexity:
O(1)per scheduling/cancel operation. - 🧺 Space complexity:
O(1)per interval, for the map and timer references.