当前位置: 首页 > news >正文

【力扣】2725. 间隔取消

【力扣】2725. 间隔取消

文章目录

  • 【力扣】2725. 间隔取消
    • 一、题目
    • 二、解决方案
      • 1、概述
      • 2、用例:
      • 方法 1:使用` setInterval `和` clearInterval`
        • 1、实现:
        • 2、复杂度分析:
      • 方法 2:使用递归
        • 1、思路:
        • 2、算法:
        • 3、实现 1:
        • 4、实现 2:
        • 5、复杂度分析:
      • 3、面试提示

一、题目

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

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

setTimeout(cancelFn, cancelTimeMs)

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

示例 1:

输入:fn = (x) => x * 2, args = [4], t = 35, cancelT = 190
输出:
[{"time": 0, "returned": 8},{"time": 35, "returned": 8},{"time": 70, "returned": 8},{"time": 105, "returned": 8},{"time": 140, "returned": 8},{"time": 175, "returned": 8}
]
解释: 
const cancelTimeMs = 190;
const cancelFn = cancellable((x) => x * 2, [4], 35);
setTimeout(cancelFn, cancelTimeMs);每隔 35ms,调用 fn(4)。直到 t=190ms,然后取消。
第一次调用 fn 是在 0ms。fn(4) 返回 8。
第二次调用 fn 是在 35ms。fn(4) 返回 8。
第三次调用 fn 是在 70ms。fn(4) 返回 8。
第四次调用 fn 是在 105ms。fn(4) 返回 8。
第五次调用 fn 是在 140ms。fn(4) 返回 8。
第六次调用 fn 是在 175ms。fn(4) 返回 8。
在 t=190ms 时取消

示例 2:

输入:fn = (x1, x2) => (x1 * x2), args = [2, 5], t = 30, cancelT = 165
输出: 
[{"time": 0, "returned": 10},{"time": 30, "returned": 10},{"time": 60, "returned": 10},{"time": 90, "returned": 10},{"time": 120, "returned": 10},{"time": 150, "returned": 10}
]
解释:
const cancelTimeMs = 165; 
const cancelFn = cancellable((x1, x2) => (x1 * x2), [2, 5], 30) 
setTimeout(cancelFn, cancelTimeMs)每隔 30ms,调用 fn(2, 5)。直到 t=165ms,然后取消。
第一次调用 fn 是在 0ms
第二次调用 fn 是在 30ms
第三次调用 fn 是在 60ms
第四次调用 fn 是在 90ms
第五次调用 fn 是在 120ms
第六次调用 fn 是在 150ms
在 165ms 取消

示例 3:

输入:fn = (x1, x2, x3) => (x1 + x2 + x3), args = [5, 1, 3], t = 50, cancelT = 180
输出:
[{"time": 0, "returned": 9},{"time": 50, "returned": 9},{"time": 100, "returned": 9},{"time": 150, "returned": 9}
]
解释:
const cancelTimeMs = 180;
const cancelFn = cancellable((x1, x2, x3) => (x1 + x2 + x3), [5, 1, 3], 50)
setTimeout(cancelFn, cancelTimeMs)每隔 50ms,调用 fn(5, 1, 3)。直到 t=180ms,然后取消。
第一次调用 fn 是在 0ms
第二次调用 fn 是在 50ms
第三次调用 fn 是在 100ms
第四次调用 fn 是在 150ms
在 180ms 取消

提示:

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

二、解决方案

1、概述

你将获得一个函数 fn,一个参数数组 args,以及一个时间间隔 t。你需要实现一个函数 cancelFn,它会立即用 args 调用 fn,然后按照每t毫秒的时间间隔安排后续对fn的调用,直到调用 cancelFn

2、用例:

  • 编辑应用中的自动保存: 在使用文本编辑器、文档处理器或其他内容创建工具时,经常需要有一个自动保存功能,以定期保存更改。你可以使用间隔取消来安排定期自动保存。如果用户明确保存文档或退出应用程序,你可以取消间隔以防止不必要的保存操作。
  • 动画和幻灯片播放定时: 在开发过程中,你可能想要创建动画或幻灯片,以自动在不同状态或图像之间进行切换。你可以使用间隔取消来控制这些切换的时间。如果用户与动画或幻灯片进行交互,你可以取消间隔以暂停或停止自动切换。

注意: 对于更复杂或性能关键的动画,建议使用 requestAnimationFrame 方法,而不是 setInterval,因为它提供更好的性能和效率。

  • 基于时间的提醒: 考虑一个任务管理应用程序,用户可以为特定任务设置提醒。你可以使用间隔取消来触发指定间隔的提醒。一旦用户确认了提醒或任务已完成,你可以取消间隔以停止后续的提醒。
    在继续之前,我们需要学习两个概念,即 setInterval clearInterval
  1. setInterval
    setInterval 函数用于重复执行一个函数或代码片段,每次调用之间都有一个固定的时间延迟。它接受两个参数:要执行的函数或代码片段,以及以毫秒为单位指定的时间延迟。
setInterval(function, delay);
  • function 参数表示在每个间隔中将执行的函数或代码片段。
  • delay 参数指定每次执行函数之间的时间延迟(以毫秒为单位)。

当调用 setInterval 时,它会在初始延迟后安排执行指定的函数的第一次执行。随后的执行将根据指定的延迟重复发生。setInterval 返回一个间隔 ID,这是一个唯一的数字值。此 ID 可以在以后用于识别和控制间隔计划。需要注意的是 setInterval 不是完全精确的。

setInterval 实际上是一个可变参数函数,可以接受无限数量的参数。例如,你可以传递多个参数给要执行的函数。

你可以参考MDN文档中的setInterval以获取更多详细信息。

  1. clearInterval

clearInterval 函数用于取消先前通过调用setInterval建立的定时重复操作。它接受由 setInterval 返回的间隔 ID 作为参数。

clearInterval(intervalID);
  • intervalID 参数代表setInterval创建的间隔的唯一 ID。通过使用适当的间隔ID调用 clearInterval,你可以有效地停止指定的函数重复执行。它取消了预定的间隔,并阻止了对指定函数的进一步调用。

方法 1:使用setInterval clearInterval

要设置一个间隔计时器,我们使用setInterval函数。在下面的代码片段中,setInterval 将每隔t毫秒调用 () => fn(...args)。值得注意的是,在设置间隔之前,setInterval 不会立即调用该函数,这就是为什么我们在设置间隔之前手动调用了 fn(...args)

接下来,我们定义了一个名为 cancelFn 的函数,当它被调用时,会清除间隔。我们从主函数返回 cancelFn。值得一提的是,cancelFn 在我们的可取消函数首次定义时不会被调用。然而,每当可取消函数被调用时,它都会返回 cancelFn。然后可以在以后的某个时候调用 cancelFn 以清除间隔。

1、实现:
/**
*@param {Function} fn
*@param {Array} args
*@param {number} t
*@return {Function}
*/
var cancellable = function(fn, args, t) {fn(...args);const timer = setInterval(() => fn(...args), t);const cancelFn = () => clearInterval(timer);return cancelFn;
};
2、复杂度分析:

时间复杂度:O(1)
空间复杂度:O(1)

方法 2:使用递归

1、思路:

我们可以设置一个定时间隔,其中函数将被重复执行。这将提供一种在需要时取消间隔执行的方式。简单来说,只要布尔标志未切换,每个函数都会不断调用自身(经过t毫秒,通过一个超时函数)。

2、算法:

当我们调用可取消函数时,首先使用给定的参数(args)执行提供的函数 (fn),即 fn(...args)。这确保了在启动间隔之前至少会调用一次函数。

接下来,我们定义了一个名为startInterval的内部函数。此函数通过使用 setTimeout 来等待指定的 t,然后再次执行函数(fn)。它重复这个过程,直到我们决定取消间隔,这将由我们在代码开始时声明的布尔变量isCancelled决定。

为了创建这种重复执行,startInterval 使用了一个巧妙的技巧。它在setTimeout回调函数内部递归调用自身。这意味着在每次执行函数后,通过再次调用startInterval来安排下一次执行。这会创建一种循环的行为,其中函数被执行,然后再次调用startInterval以安排下一次执行。

3、实现 1:
/*** @param {Function} fn* @param {Array} args* @param {number} t* @return {Function}
*/
var cancellable = function(fn, args, t) {let isCancelled = false;fn(...args);const startInterval = () => {setTimeout(() => {fn(...args);if (isCancelled) return;startInterval();}, t);}startInterval();const cancelInterval = () => {isCancelled = true;}return cancelInterval;
};
4、实现 2:

实现 1 是可以的,但更高效的方法是使用 clearTimeout 来清除这些递归超时,这种方法可以确保不会不必要地调用回调:

/*** @param {Function} fn* @param {Array} args* @param {number} t* @return {Function}
*/
var cancellable = function(fn, args, t) {let timerId = null;fn(...args);const startInterval = () => {timerId = setTimeout(() => {fn(...args);startInterval();}, t);};startInterval();const cancelInterval = () => {if (timerId !== null) {clearTimeout(timerId);}};return cancelInterval;
};
5、复杂度分析:

在给定的实现中,执行涉及设置一个延迟为 t 毫秒的setTimeout函数。然而,重要的是要注意,函数调用的调度不会引入递归或影响 JavaScript 引擎内存使用方面的复杂性。

让我们深入了解一下:

  1. JavaScript 引擎初始化并为 cancellable 函数创建上下文。
  2. cancellable 函数的语句,包括setTimeout调用,被执行。
  3. setTimeout 函数指示JavaScript引擎在t毫秒延迟后安排函数调用。
  4. cancellable 函数的上下文被销毁,JavaScript 引擎继续进行其他操作。
  5. 此时,从内存使用的角度来看,JavaScript 引擎回到初始状态,没有任何额外的内存分配或递归。唯一剩下的信息是对函数的引用和将来调用的计划时间。
  6. 在指定的延迟之后,JavaScript 引擎执行预定的函数,而不会对内存使用或递归产生影响。
  7. 一旦函数执行完成,与计划调用相关的任何剩余引用或数据都被清除。

考虑到这些事件序列,我们可以得出结论,该代码的复杂性是常数 O(1)。内存利用不会随延迟的持续时间而增加,没有递归或内存堆积,因为JavaScript引擎独立处理函数的调度和执行。

  • 时间复杂度:O(1)
  • 空间复杂度:O(1)

3、面试提示

  1. 在设置后是否可以动态更改间隔时间?

    是的,可以通过使用clearInterval取消现有的间隔,然后使用更新后的时间使用 setInterval 设置新的间隔来动态更改间隔时间。这允许你根据不断变化的需求或用户交互动态调整定时。

注意: 虽然可以创建动态间隔的幻觉,但重要的是要注意,这不会真正动态更改原始的间隔时间。它取消了先前的间隔,并启动了一个新的间隔。

  1. 使用间隔取消时是否需要考虑限制或性能问题?

    当使用间隔取消时,重要的是考虑间隔时间以及对性能的潜在影响。频繁和短暂的间隔可能会占用大量 CPU 资源。此外,如果 fn 函数的执行时间长于间隔时间,那么后续的调用可能会重叠,导致意外行为。确保间隔时间和 fn 的执行时间得到适当的平衡是至关重要的。这就是为什么在某些情况下,强烈建议使用requestAnimationFrame这样的其他方法。

    requestAnimationFrame 接受单个参数,即要执行的函数。当浏览器准备好重新绘制屏幕时,将调用指定的 requestAnimationFrame 函数。当此函数运行时,它取决于执行代码的计算机的 CPU 能力、浏览器打开的显示器的刷新率以及其他一些标准,以确保动画在占用尽可能少的资源的情况下尽可能流畅。

  2. 如果间隔时间(t)设置为负值或零会发生什么?

    它会立即连续执行,并将重复执行 0 或负数次,可能会阻塞主线程,导致浏览器不响应。

  3. 可以在取消后重新启动或重新安排间隔吗?

    尽管你无法直接重新启动已取消的间隔,但你可以通过使用所需的间隔时间和要执行的函数再次调用setInterval来创建一个新的间隔。

http://www.dtcms.com/a/355768.html

相关文章:

  • linux 环境 批量发送get请求
  • 大模型常用术语
  • 机器视觉学习-day10-图像添加水印
  • 帕萨特盘式制动器cad+设计说明书
  • TensorFlow 面试题及详细答案 120道(41-50)-- 数据输入与管道
  • workflow/http_parser源码解密:HTTP解析器的双倍扩容与零拷贝策略
  • 【C#】征服 .NET Framework 4.8 中的“古董”日期格式:/Date(1754548600000)/ 和 ISO 8601
  • 【Nacos】优雅规范的使用和管理yml配置文件
  • 苍穹外卖项目笔记day01
  • 工业级TF卡NAND + 北京君正 + Rk瑞芯微的应用
  • 本地大模型部署(下载) vs. 从头训练大模型
  • APP手游使用游戏盾SDK为何能有效抵御各类攻击?
  • ApiFox高并发测试用例
  • hintcon2025 IMGC0NV
  • 2024中山大学研保研上机真题
  • 多模态融合新纪元:Ovis2.5 本地部署教程,实现文本、图像与代码的深度协同推理
  • 力扣hot100:滑动窗口最大值优化策略及思路讲解(239)
  • MySQL 索引失效全解析与优化指南
  • 【软考】中级网络工程师历年真题合集下载(2015-2024)
  • Java多线程超详学习内容
  • Python 中的反射机制与动态灵活性
  • Spring学习笔记:Spring JDBC(jdbc Template)的深入学习和使用
  • 行业前瞻:在线教育系统源码与网校APP开发的技术进化方向
  • C++学习笔记之异常处理
  • Pruning-Guided Curriculum Learning
  • 机器视觉学习-day06-图像旋转
  • MPPT的基本原理
  • 如何循环同步下载文件
  • Yolov8 pose 推理部署笔记
  • HTML应用指南:利用POST请求获取全国中国工商银行网点位置信息