leetcode----JavaScript 详情题解(1)

news/2024/11/19 0:52:59/

目录

2618. 检查是否是类的对象实例

2619. 数组原型对象的最后一个元素

2620. 计数器

2621. 睡眠函数

2622. 有时间限制的缓存 

2623. 记忆函数

2625. 扁平化嵌套数组

2626. 数组归约运算

2627. 函数防抖


2618. 检查是否是类的对象实例

请你编写一个函数,检查给定的值是否是给定类或超类的实例。

可以传递给函数的数据类型没有限制。例如,值或类可能是  undefined 。

示例 :

输入:func = () => checkIfInstance(new Date(), Date)
输出:true
解释:根据定义,Date 构造函数返回的对象是 Date 的一个实例。
题解
var checkIfInstanceOf = function(obj, classFunction) {if(obj === null || classFunction === null || obj === undefined || classFunction === undefined) {return false;}let proto = Object.getPrototypeOf(obj);while (proto !== null) {if (proto.constructor === classFunction) {return true;}proto = Object.getPrototypeOf(proto);}return false;
};

这段代码定义了一个名为checkIfInstanceOf的函数,该函数的作用是判断一个对象是否是指定类的实例。

函数接受两个参数:obj和classFunction,分别表示待判断的对象和指定类的构造函数。

首先,函数会检查obj和classFunction是否为null或undefined,如果是的话,函数直接返回false,表示对象不是指定类的实例。

接下来,函数会通过Object.getPrototypeOf(obj)获取obj的原型。然后,进入一个while循环,不断获取原型的原型,直到原型为null为止。

在每一次循环中,函数会判断当前原型的构造函数是否等于传入的classFunction。如果是的话,表示obj是classFunction的实例,函数会返回true。

如果循环结束后仍未找到符合条件的原型,函数会返回false,表示obj不是指定类的实例。

最后,整个函数的定义结束。

2619. 数组原型对象的最后一个元素

请你编写一段代码实现一个数组方法,使任何数组都可以调用 array.last() 方法,这个方法将返回数组最后一个元素。如果数组中没有元素,则返回 -1 。

你可以假设数组是 JSON.parse 的输出结果。

示例 :

输入:nums = [null, {}, 3]
输出:3
解释:调用 nums.last() 后返回最后一个元素: 3。

题解:

Array.prototype.last = function() {let res=this[this.length-1]return res===undefined?-1:res
};

这段代码定义了一个名为last的函数,该函数是Array原型的一个方法。该方法用于获取数组中的最后一个元素。

函数内部首先通过this关键字获取调用该方法的数组对象。然后通过this.length - 1获取数组中最后一个元素的索引,并将其赋值给变量res。

接下来使用三元运算符判断变量res的值是否为undefined。如果是undefined,则说明数组为空,函数返回-1;否则,函数返回变量res的值,即数组中的最后一个元素。

这段代码的作用是为数组对象添加一个方法,方便获取数组的最后一个元素。如果数组为空,则返回-1。

2620. 计数器

请你编写并返回一个 计数器 函数,它接收一个整型参数 n 。这个 计数器 函数最初返回 n,每次调用它时返回前一个值加 1 的值 ( n ,  n + 1 ,  n + 2 ,等等)。

示例 :

输入:
n = 10 
["call","call","call"]
输出:[10,11,12]
解释:
counter() = 10 // 第一次调用 counter(),返回 n。
counter() = 11 // 返回上次调用的值加 1。
counter() = 12 // 返回上次调用的值加 1。

题解:

var createCounter = function (n) {return function () {return n++;};
};

  • var createCounter 定义了一个变量 createCounter,它将引用这个函数。
  • function (n) 是一个匿名函数,它接受一个参数 n
  • return function () { ... } 是匿名函数的返回值,它也是一个函数。
  • return n++ 是返回了变量 n 的值,并将 n 自增 1。

因此,当调用 createCounter 函数时,它会返回一个新的函数。每次调用这个新函数时,它会返回变量 n 的当前值,并将 n 自增 1。这样就创建了一个简单的计数器,每次调用计数器函数时,计数器的值都会增加。

2621. 睡眠函数

请你编写一个异步函数,它接收一个正整数参数 millis ,并休眠这么多毫秒。要求此函数可以解析任何值。

示例

输入:millis = 100
输出:100
解释:
在 100ms 后此异步函数执行完时返回一个 Promise 对象
let t = Date.now();
sleep(100).then(() => {console.log(Date.now() - t); // 100
});

题解

async function sleep(millis) {return new Promise((reslove, reject) => {setTimeout(() => {reslove()}, millis)})
}

这是一个异步 JavaScript 函数,名称为 sleep。这个函数接受一个参数 millis,用来标明延迟的毫秒数。

这个函数的功能是创建一个新的 Promise 对象,这个 Promise 对象在经过指定的毫秒数 millis 后解决(即执行 resolve 方法)。由于 JavaScript 的 Timer 函数(例如 setTimeout)是非阻塞的,sleep 函数使用 Promise 和 setTimeout 一起来实现一个"暂停"功能。

当你在一个 async 函数中使用 await sleep(millis) 形式调用此函数时,该函数会“暂停”或者说“睡眠”指定的毫秒数,然后继续执行。这样的函数在需要延迟一段时间然后执行的场景中特别有用。

2622. 有时间限制的缓存 

编写一个类,它允许获取和设置键-值对,并且每个键都有一个 过期时间 。

该类有三个公共方法:

set(key, value, duration) :接收参数为整型键 key 、整型值 value 和以毫秒为单位的持续时间 duration 。一旦 duration 到期后,这个键就无法访问。如果相同的未过期键已经存在,该方法将返回 true ,否则返回 false 。如果该键已经存在,则它的值和持续时间都应该被覆盖。

get(key) :如果存在一个未过期的键,它应该返回这个键相关的值。否则返回 -1 。

count() :返回未过期键的总数。

示例

["TimeLimitedCache", "set", "get", "count", "get"]
[[], [1, 42, 100], [1], [], [1]]
[0, 0, 50, 50, 150]
输出: [null, false, 42, 1, -1]
解释:
在 t=0 时,缓存被构造。
在 t=0 时,添加一个键值对 (1: 42) ,过期时间为 100ms 。因为该值不存在,因此返回false。
在 t=50 时,请求 key=1 并返回值 42。
在 t=50 时,调用 count() ,缓存中有一个未过期的键。
在 t=100 时,key=1 到期。
在 t=150 时,调用 get(1) ,返回 -1,因为缓存是空的。

var TimeLimitedCache = function () {this.map = new Map();this.timeoutMap = new Map();
};TimeLimitedCache.prototype.set = function (key, value, duration) {if (this.timeoutMap.has(key)) {clearTimeout(this.timeoutMap.get(key));}let isKeyExists = this.map.has(key);this.map.set(key, value);this.timeoutMap.set(key, setTimeout(() => {this.map.delete(key);this.timeoutMap.delete(key);}, duration));return isKeyExists;
};TimeLimitedCache.prototype.get = function (key) {if (this.map.has(key)) {return this.map.get(key);} else {return -1;}
};TimeLimitedCache.prototype.count = function () {return this.map.size;
};

这段代码定义了一个名为TimeLimitedCache的构造函数。构造函数内部有两个实例属性,map和timeoutMap,分别使用JavaScript内置的Map类来存储数据。

构造函数之后定义了三个方法。

  1. set方法用于向缓存中设置一个键值对,并指定过期时间。如果指定键已存在,且仍未过期,set方法会清除之前的过期计时器。然后,它会将键值对存储到map中,并使用setTimeout方法设置过期计时器,计时器到期后会从map和timeoutMap中删除该键值对。返回值表示之前是否已存在未过期的键。

  2. get方法用于根据键获取对应的值。如果键存在于map中,则返回对应的值;否则,返回-1。

  3. count方法用于返回当前未过期的键的数量,即map的大小。

这段代码实现了一个有时限的缓存机制,可以设置过期时间,并能够根据键获取对应的值以及获取未过期键的数量。

2623. 记忆函数

请你编写一个函数,它接收另一个函数作为输入,并返回该函数的 记忆化 后的结果。

记忆函数 是一个对于相同的输入永远不会被调用两次的函数。相反,它将返回一个缓存值。

你可以假设有 3 个可能的输入函数:sum 、fib 和 factorial 。

  •  sum 接收两个整型参数 a 和 b ,并返回 a + b 。
  •  fib 接收一个整型参数 n ,如果 n <= 1 则返回 1,否则返回 fib (n - 1) + fib (n - 2)
  •  factorial 接收一个整型参数 n ,如果 n <= 1 则返回  1 ,否则返回 factorial(n - 1) * n 。

示例

输入:
"sum"
["call","call","getCallCount","call","getCallCount"]
[[2,2],[2,2],[],[1,2],[]]
输出:
[4,4,1,3,2]解释:
const sum = (a, b) => a + b;
const memoizedSum = memoize(sum);
memoizedSum (2, 2);// 返回 4。sum() 被调用,因为之前没有使用参数 (2, 2) 调用过。
memoizedSum (2, 2);// 返回 4。没有调用 sum(),因为前面有相同的输入。
//总调用数: 1
memoizedSum(1、2);// 返回 3。sum() 被调用,因为之前没有使用参数 (1, 2) 调用过。
//总调用数: 2

题解 

function memoize(func) {var cache = {};return function(...args) {var key = JSON.stringify(args);if (cache.hasOwnProperty(key)) {return cache[key];}var result = func(...args);cache[key] = result;return result;};
}

这段代码定义了一个名为memoize的函数,它接受一个参数func。memoize函数返回一个新的函数,并利用闭包在返回的函数中创建一个缓存对象cache。

返回的函数接受任意数量的参数,并将这些参数使用JSON.stringify方法转换成一个字符串作为缓存字典cache的键。如果缓存对象已经存在该键,则直接返回缓存中的值。

如果缓存对象中不存在该键,那么调用传入的原始函数func,将其返回值存储在result变量中。并将结果存储在缓存对象的对应键中。最后,返回结果。

这段代码的作用是:在调用原始函数之前,先检查是否已经存在相同参数的结果。如果存在,则直接返回缓存中的结果,避免重复计算。如果不存在,则计算参数对应的结果,并将结果存储在缓存中,以备将来使用。

2625. 扁平化嵌套数组

请你编写一个函数,它接收一个 多维数组 arr 和它的深度 n ,并返回该数组的 扁平化 后的结果。

多维数组 是一种包含整数或其他 多维数组 的递归数据结构。

数组 扁平化 是对数组的一种操作,定义是将原数组部分或全部子数组删除,并替换为该子数组中的实际元素。只有当嵌套的数组深度大于 n 时,才应该执行扁平化操作。第一层数组中元素的深度被认为是 0。

请在没有使用内置方法 Array.flat 的前提下解决这个问题。

示例

输入
arr = [1, 2, 3, [4, 5, 6], [7, 8, [9, 10, 11], 12], [13, 14, 15]]
n = 0
输出
[1, 2, 3, [4, 5, 6], [7, 8, [9, 10, 11], 12], [13, 14, 15]]解释
传递深度 n=0 的多维数组将始终得到原始数组。这是因为 子数组(0) 的最小可能的深度不小于 n=0 。因此,任何子数组都不应该被平面化。

题解


var flat = function (arr, n) {if (n === 0) {return arr;}const res = flat(arr, n - 1);return [].concat(...res);
};

这段代码的作用是将一个嵌套的数组(arr)展开成一个一维数组,展开的层数由参数n决定。

代码的流程是:

  1. 定义一个名为flat的函数,接受两个参数,一个是要展开的数组arr,另一个是展开的层数n。

  2. 如果n等于0,表示已经展开完毕,直接返回原始数组arr。

  3. 如果n不等于0,则递归调用flat函数,将展开的层数减1,得到一个新的数组res。

  4. 使用数组的concat方法将新的数组res拼接成一个一维数组,并返回该数组。

这个函数的实现原理是通过递归的方式,每次递归都将展开的层数减1,直到达到指定的展开层数,然后通过concat方法将递归得到的中间展开结果合并成最终结果。

2626. 数组归约运算

归约

在计算机科学中,归约(reduction)通常指的是将一个问题或数据集合转化为较小的、等价的形式的过程。归约可以被用于解决算法问题、优化计算和简化复杂性。

在算法问题中,归约通常用于将一个复杂的问题转化为一个更简单的问题。这个过程通常通过分解问题、提取共性和重复性的步骤来实现。通过将复杂问题分解为更小的子问题,然后将结果合并,最终解决整个问题。

归约的目标是通过将问题拆分成更小的、可处理的部分来提高求解的效率。它可以用于各种算法和数据结构问题,如排序、搜索、图形算法和动态规划等。通过归约,我们可以将复杂度较高的问题转化为具有更低复杂度的子问题,并通过递归或迭代的方式求解最终答案。

总的来说,归约是将一个问题或数据集合转化为更小、更简单、等价的形式的过程,以便更高效地解决问题。它是计算机科学中一种常见的问题求解方法和算法设计技巧。


你编写一个函数,它的参数为一个整数数组 nums 、一个计算函数 fn 和初始值 init 。返回一个数组 归约后 的值。

你可以定义一个数组 归约后 的值,然后应用以下操作: val = fn(init, nums[0]) , val = fn(val, nums[1]) , val = fn(val, nums[2]) ,... 直到数组中的每个元素都被处理完毕。返回 val 的最终值。

如果数组的长度为 0,它应该返回 init 的值。

请你在不使用内置数组方法的 Array.reduce 前提下解决这个问题。

示例

输入:
nums = [1,2,3,4]
fn = function sum(accum, curr) { return accum + curr; }
init = 0
输出:10
解释:
初始值为 init=0 。
(0) + nums[0] = 1
(1) + nums[1] = 3
(3) + nums[2] = 6
(6) + nums[3] = 10
Val 最终值为 10。

题解 

var reduce = function (nums, fn, init) {if (nums.length === 0) { return init; }let val = init;for (let i = 0; i < nums.length; i++) {val = fn(val, nums[i]);}return val;
};

这段代码定义了一个名为reduce的函数,该函数接受三个参数:nums(数组)、fn(回调函数)和init(初始值)。

函数的作用是将数组中的每个元素都传递给回调函数进行处理,并返回最终的计算结果。

首先,函数会判断数组的长度是否为0,若是则直接返回初始值。

接下来,定义一个变量val并将其初始化为初始值。

然后,通过一个for循环遍历数组中的每个元素,每次循环都将当前元素和val作为参数传递给回调函数fn进行处理,得到的结果赋值给val。

最后,返回最终计算得到的val。

2627. 函数防抖

请你编写一个函数,接收参数为另一个函数和一个以毫秒为单位的时间 t ,并返回该函数的 函数防抖 后的结果。

函数防抖 方法是一个函数,它的执行被延迟了 t 毫秒,如果在这个时间窗口内再次调用它,它的执行将被取消。你编写的防抖函数也应该接收传递的参数。

例如,假设 t = 50ms ,函数分别在 30ms 、 60ms 和 100ms 时调用。前两个函数调用将被取消,第三个函数调用将在 150ms 执行。如果改为 t = 35ms ,则第一个调用将被取消,第二个调用将在 95ms 执行,第三个调用将在 135ms 执行。

上图展示了了防抖函数是如何转换事件的。其中,每个矩形表示 100ms,反弹时间为 400ms。每种颜色代表一组不同的输入。

请在不使用 lodash 的 _.debounce() 函数的前提下解决该问题。

示例

输入:
t = 50
calls = [{"t": 50, inputs: [1]},{"t": 75, inputs: [2]}
]
输出:[{"t": 125, inputs: [2]}]
解释:
let start = Date.now();
function log(...inputs) { console.log([Date.now() - start, inputs ])
}
const dlog = debounce(log, 50);
setTimeout(() => dlog(1), 50);
setTimeout(() => dlog(2), 75);第一次调用被第二次调用取消,因为第二次调用发生在 100ms 之前
第二次调用延迟 50ms,在 125ms 执行。输入为 (2)。

题解

function debounce(func, t) {let timeout;return function (...args) {clearTimeout(timeout);timeout = setTimeout(() => {func.apply(this, args);}, t);};
}

这个函数接受两个参数:func 表示要进行函数防抖的函数,t 表示延迟的时间窗口。

在内部,我们定义了一个变量 timeout 用于存储定时器的标识。然后,返回一个立即执行函数,这个函数接受参数 args 作为传递给被防抖的函数 func 的参数。

每当调用该函数时,我们首先清除之前的定时器,然后设置一个新的定时器,在延迟时间 t 后调用函数 func。这样,如果在延迟时间窗口内再次调用该函数,之前的定时器将被清除,然后重新设置一个新的定时器。

这样就实现了函数防抖:只有当在延迟时间窗口内没有再次调用该函数时,才会真正执行函数 func。如果在延迟时间窗口内再次调用该函数,上一个定时器会被取消,因此函数不会被执行。

❤❤❤❤❤❤------this------❤❤❤❤❤❤

在函数防抖的实现中,使用func.apply(this, args)来调用被防抖的函数func,其中this的值是由调用防抖函数的上下文确定的。

当使用箭头函数创建防抖函数时,箭头函数没有独立的执行上下文,它会继承上一级作用域的this值,因此在防抖函数中,this的值将与上一级作用域中的this相同。

例如,在全局作用域中调用防抖函数时,防抖函数中的this将指向全局对象(浏览器中是window对象):

function debounce(func, t) {let timeout;return function (...args) {clearTimeout(timeout);timeout = setTimeout(() => {func.apply(this, args);}, t);};
}function example() {console.log(this); // global object (e.g. window)
}const debouncedExample = debounce(example, 500);
debouncedExample();

而当在对象的方法中调用防抖函数时,防抖函数中的this将指向该对象:

const obj = {name: 'example',debouncedMethod: debounce(function () {console.log(this.name); // example}, 500)
};obj.debouncedMethod();

总的来说,防抖函数内部的this指向是由调用防抖函数的上下文决定的,可以通过箭头函数继承上一级作用域的this值,或者使用applycall等方法来显式指定this的值。


http://www.ppmy.cn/news/1000071.html

相关文章

企业优化效率,进行数据在线管理是不二选择

如今商业环境的竞争是愈发激烈了起来&#xff0c;企业优化效率成为了提高竞争力和发展壮大的关键。数据与图文档管理是企业运营中不可或缺的一环&#xff0c;传统管理方式已不适应快速变化的市场需求和多样化的业务流程。而在线图文档管理结合BOM系统作为企业数字化管理的不二选…

【WiFi】国产WiFi芯片

目录 1.概述 2.WiFi芯片的市场格局 3.中国的WiFi芯片公司 3.1.华为海思 3.2.乐鑫科技 3.3.博通集成 3.4.紫光展锐 3.5.康希通信 3.6.南方硅谷 4.国产WiFi芯片竞争格局 4.1.内卷WiFi 4 4.2.缺席WiFi 5 4.3.发力WiFi 6 4.4.逐鹿WiFi 7 5.不得不提的WiFi FEM 1.概述…

聊聊工程化 Docker 的最新趋势以及最佳实践

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

JavaScript学习 -- AES加密算法

引言 在当今数字化时代&#xff0c;前端应用程序扮演着重要角色&#xff0c;用户的敏感数据经常在前端进行加密和解密操作。然而&#xff0c;这样的操作在网络传输和存储中可能会受到恶意攻击的威胁。为了确保数据的安全性&#xff0c;AES&#xff08;Advanced Encryption Sta…

【更新】119所院校考研重点勾画更新预告!

截至目前&#xff0c;我已经发布了47篇不同院校的择校分析。发布了87套名校信号考研真题以及119所不同院校的考研知识点重点勾画。 另外为了更好服务已经报名的同学&#xff0c;24梦马全程班也到了收尾的阶段。即将封班&#xff01;需要报名的同学抓紧啦&#xff01; 去年开始…

[高通SM6225][Android13][Kernel5.15]user版本默认获取root权限

需求描述&#xff1a; user版本默认是不会开启root权限的&#xff0c;但是一般性能版本需要设置CPU GPU DDR performance或者监听节点信息等debug手段去验证当前问题是否与CPU GPU DDR有关系。 基线代码判断逻辑&#xff1a; 1.adb代码会检测相关属性 ro.secure ro.debugga…

【vue】 vue2 监听滚动条滚动事件

代码 直接上代码&#xff0c;vue单文件 index.vue <template><div class"content" scroll"onScroll"><p>内容</p><p>内容</p><p>内容</p><p>内容</p><p>内容</p><p>内容…

YAPI接口自动鉴权功能部署详解

目录 安装准备 在线安装 离线安装 配置使用 安装准备 以下操作&#xff0c;默认要求自己部署过yapi&#xff0c;最好是部署过yapi二次开发环境。 无论是选择在线安装或者是本地安装&#xff0c;都需要安装client工具。 1、yapi-cli&#xff1a;npm install yapi-cli –g…