跳至主要內容

2725. 间隔取消


2725. 间隔取消open in new window

🟢   🔗 力扣open in new window LeetCodeopen in new window

题目

Given a function fn, an array of arguments args, and an interval time t, return a cancel function cancelFn.

After a delay of cancelTimeMs, the returned cancel function cancelFn will be invoked.

setTimeout(cancelFn, cancelTimeMs)

The function fn should be called with args immediately and then called again every t milliseconds until cancelFn is called at cancelTimeMs ms.

Example 1:

Input: fn = (x) => x * 2, args = [4], t = 35

Output:

[

{"time": 0, "returned": 8},

{"time": 35, "returned": 8},

{"time": 70, "returned": 8},

{"time": 105, "returned": 8},

{"time": 140, "returned": 8},

]

Explanation:

const cancelTimeMs = 190;

const cancelFn = cancellable((x) => x * 2, [4], 35);

setTimeout(cancelFn, cancelTimeMs);

Every 35ms, fn(4) is called. Until t=190ms, then it is cancelled.

1st fn call is at 0ms. fn(4) returns 8.

2nd fn call is at 35ms. fn(4) returns 8.

3rd fn call is at 70ms. fn(4) returns 8.

4th fn call is at 105ms. fn(4) returns 8.

5th fn call is at 140ms. fn(4) returns 8.

6th fn call is at 175ms. fn(4) returns 8.

Cancelled at 190ms

Example 2:

Input: fn = (x1, x2) => (x1 * x2), args = [2, 5], t = 30

Output:

[

{"time": 0, "returned": 10},

{"time": 30, "returned": 10},

{"time": 60, "returned": 10},

{"time": 90, "returned": 10},

{"time": 120, "returned": 10},

]

Explanation:

const cancelTimeMs = 165;

const cancelFn = cancellable((x1, x2) => (x1 * x2), [2, 5], 30)

setTimeout(cancelFn, cancelTimeMs)

Every 30ms, fn(2, 5) is called. Until t=165ms, then it is cancelled.

1st fn call is at 0ms

2nd fn call is at 30ms

3rd fn call is at 60ms

4th fn call is at 90ms

5th fn call is at 120ms

6th fn call is at 150ms

Cancelled at 165ms

Example 3:

Input: fn = (x1, x2, x3) => (x1 + x2 + x3), args = [5, 1, 3], t = 50

Output:

[

{"time": 0, "returned": 9},

{"time": 50, "returned": 9},

{"time": 100, "returned": 9},

]

Explanation:

const cancelTimeMs = 180;

const cancelFn = cancellable((x1, x2, x3) => (x1 + x2 + x3), [5, 1, 3], 50)

setTimeout(cancelFn, cancelTimeMs)

Every 50ms, fn(5, 1, 3) is called. Until t=180ms, then it is cancelled.

1st fn call is at 0ms

2nd fn call is at 50ms

3rd fn call is at 100ms

4th fn call is at 150ms

Cancelled at 180ms

Constraints:

  • fn is a function
  • args is a valid JSON array
  • 1 <= args.length <= 10
  • 30 <= t <= 100
  • 10 <= cancelTimeMs <= 500

题目大意

现给定一个函数 fn,一个参数数组 args 和一个时间间隔 t,返回一个取消函数 cancelFn

在经过 cancelTimeMs 毫秒的延迟后,将调用返回的取消函数 cancelFn

setTimeout(cancelFn, cancelTimeMs)

函数 fn 应立即使用参数 args 调用,然后每隔 t 毫秒调用一次,直到在 cancelTimeMs 毫秒时调用 cancelFn

提示:

  • fn 是一个函数
  • args 是一个有效的 JSON 数组
  • 1 <= args.length <= 10
  • 30 <= t <= 100
  • 10 <= cancelT <= 500

解题思路

  1. 题目要求函数 fn 应立即使用参数 args 调用,然后每隔 t 毫秒调用一次,所以立即手动执行 fn 一次。
  2. 使用 setInterval 来启动定时器,每隔 delay 毫秒会执行一次传入的函数 fn,第一次执行发生在 delay 毫秒之后。
  3. setInterval 返回一个 intervalId,这是唯一标识这个定时器的值,可以通过调用 clearInterval(intervalId) 来取消定时器。
  4. 返回取消函数,这个取消函数在被调用时,会停止定时器的继续执行。

复杂度分析

  • 时间复杂度O(1),因为 setIntervalclearInterval 都是常数时间操作。
  • 空间复杂度O(1),只存储了 intervalId 作为唯一的定时器标识。

代码

/**
 * @param {Function} fn
 * @param {Array} args
 * @param {number} t
 * @return {Function}
 */
var cancellable = function (fn, args, t) {
	// 立即调用一次 fn
	fn(...args);

	// 使用 setInterval 启动定时器,每隔 t 毫秒执行一次 fn
	const intervalId = setInterval(() => fn(...args), t);

	// 返回一个取消函数,可以通过调用该函数来清除定时器
	const cancelFn = () => clearInterval(intervalId);
	return cancelFn;
};

/**
 *  const result = [];
 *
 *  const fn = (x) => x * 2;
 *  const args = [4], t = 35, cancelTimeMs = 190;
 *
 *  const start = performance.now();
 *
 *  const log = (...argsArr) => {
 *      const diff = Math.floor(performance.now() - start);
 *      result.push({"time": diff, "returned": fn(...argsArr)});
 *  }
 *
 *  const cancel = cancellable(log, args, t);
 *
 *  setTimeout(cancel, cancelTimeMs);
 *
 *  setTimeout(() => {
 *      console.log(result);
 *      // [
 *      //     {"time":0,"returned":8},
 *      //     {"time":35,"returned":8},
 *      //     {"time":70,"returned":8},
 *      //     {"time":105,"returned":8},
 *      //     {"time":140,"returned":8},
 *      //     {"time":175,"returned":8}
 *      // ]
 *  }, cancelTimeMs + t + 15)
 */