LeetCode JS专栏刷题笔记(二)

news/发布时间2024/5/15 1:49:48

一、前言

LeetCode - JavaScript 专栏刷题笔记第二篇。

第一篇刷题笔记详见:LeetCode JS专栏刷题笔记(一)

二、算法题目

1. 复合函数

LeetCode地址:2629. 复合函数

请你编写一个函数,它接收一个函数数组 [f1, f2, f3,…, fn] ,并返回一个新的函数 fn ,它是函数数组的 复合函数

[f(x), g(x), h(x)]复合函数fn(x) = f(g(h(x)))

一个空函数列表的 复合函数恒等函数 f(x) = x

你可以假设数组中的每个函数接受一个整型参数作为输入,并返回一个整型作为输出。

Pasted image 20230709114449.png

思路

这道题并不难,但是有一个用的比较少的 API 可以直接实现,所以拿出来讲一讲。

这道题乍一看有点难以理解,实际就是给你一个初始值 x, 然后从右至左依次执行。

那么我们从数组末尾往前遍历,每次将最新的值更新到 x ,用于下次执行传入即可。

类似 Array#reduce 的 API 是 Array#reduceRight 。与 reduce 的遍历顺序相反,是从右至左累计和 的一个 API ,这道题可以直接使用 reduceRight 解决。

具体实现

方法一:遍历
/*** @param {Function[]} functions* @return {Function}*/
var compose = function(functions) {return function(x) {for(let i = functions.length - 1; i >= 0; i--) {x = functions[i](x)}return x;}
};
方法二:reduceRight
/*** @param {Function[]} functions* @return {Function}*/
var compose = function(functions) {return function(x) {return functions.reduceRight((total, fn) => fn(total), x);}
};

2. 分组

LeetCode地址:2631. 分组

请你编写一段可应用于所有数组的代码,使任何数组调用 array.groupBy(fn) 方法时,它返回对该数组 分组后 的结果。

数组 分组 是一个对象,其中的每个键都是 fn(arr[i]) 的输出的一个数组,该数组中含有原数组中具有该键的所有项。

提供的回调函数 fn 将接受数组中的项并返回一个字符串类型的键。

每个值列表的顺序应该与元素在数组中出现的顺序相同。任何顺序的键都是可以接受的。

请在不使用 lodash 的 _.groupBy 函数的前提下解决这个问题。

Pasted image 20230709115302.png

思路

比较初级的题,实际开发中会遇到类似功能比较多,仅仅考察了一下哈希表的使用。

这道题的要求是,根据传入的 fn 函数的结果进行分组,图中示例给的已经很清楚了,不在多解释。

我们直接根据 fn(item) 的不同结果的存入数组就可以了。

具体实现

/*** @param {Function} fn* @return {Array}*/
Array.prototype.groupBy = function(fn) {const map = {};this.forEach( item =>{const key = fn(item);if(!map[key]) {map[key] = [item];}else{map[key].push(item)}})return map
};/*** [1,2,3].groupBy(String) // {"1":[1],"2":[2],"3":[3]}*/

3. 柯里化

LeetCode地址:2632. 柯里化

请你编写一个函数,它接收一个其他的函数,并返回该函数的 柯里化 后的形式。

柯里化 函数的定义是接受与原函数相同数量或更少数量的参数,并返回另一个 柯里化 后的函数或与原函数相同的值。

实际上,当你调用原函数,如 sum(1,2,3) 时,它将调用 柯里化 函数的某个形式,如 csum(1)(2)(3)csum(1)(2,3)csum(1,2)(3),或 csum(1,2,3) 。所有调用 柯里化 函数的方法都应该返回与原始函数相同的值。

Pasted image 20230709115514.png

思路

柯里化是一种关于函数的高阶技术,他不仅被用于 Javascript,还被用于其他编程语言。

柯里化可以将一个函数从可调用的 sum(1,2,3) 转换成可调用的 f(1)(2)(3)

也就是说:柯里化将原本一个一次性接受多参数的函数,转换为多次接受部分参数的函数,这种转换过程涉及到将原始函数的参数拆分为多个部分,并返回一个新的函数,每次接受一些参数,直到接受完所有参数并执行原始函数。

实现该方法的关键点是一个不常用的属性:fn.length , 在 JS 中 函数自带的 length 属性返回的该函数的参数个数。

解释完 柯里化 的作用及关键的 fn.length 属性,想实现就不难了。

既然柯里化是需要等到接受完所有的参数再返回结果,那么我们维护一个数组,将每次传入的参数存入数组中,直到 参数各数 === fn.length 再将 fn(参数列表) 的执行结果返回即可。

具体实现

/*** @param {Function} fn* @return {Function}*/
var curry = function(fn) {// 缓存已经传入的参数列表const argList = [];return function curried(...args) {argList.push(...args);// 判断参数个数是否满足要求if(argList.length === fn.length) {return fn(...argList);}// 不满足要求再次返回柯里化函数return curried;};
};/*** function sum(a, b) { return a + b; }* const csum = curry(sum);* csum(1)(2) // 3*/

4. 将对象转换为 JSON 字符串

LeetCode地址:2633. 将对象转换为 JSON 字符串

现给定一个对象,返回该对象的有效 JSON 字符串。你可以假设这个对象只包括字符串、整数、数组、对象、布尔值和 null。返回的字符串不能包含额外的空格。键的返回顺序应该与 Object.keys() 的顺序相同。

请你在不使用内置方法 JSON.stringify 的前提下解决这个问题。

Pasted image 20230709115720.png

思路

前端基本功:手写 JSON.stringify

手写简化版的 JSON.stringify 并不难,只要将题目要求中的几个不同类型的数据考虑到,分类处理好即可。

根据题目要求,转换成 JSON 字符串有主要有 5 类不同的数据需要分别判断

  • null 值: 需要手动转换成 null 字符串,否则会在处理数组或对象中遇到会直接成为空,同时 null 会被判定为 object 类型。
  • 字符串类型:字符串需要手动拼接 \", 否则在拼接字符串时不会保留双引号
  • 基本类型:如 boolean, number 直接保持原值即可。
  • 数组:考虑到数组中可能包含对象、数组,所以需要递归遍历每一项处理好后进行拼接
  • 对象:同样,也需要考虑对象中包含数组及对象,也需要进行递归处理

为了简化拼接字符串的代码量,我们直接通过模板字符串进行拼接即可。

具体实现

/*** @param {any} object* @return {string}*/
var jsonStringify = function(object) {// 处理 null 值if(object === null) return "null"// 处理基本类型if(typeof object !== 'object') {return typeof object === 'string' ?  `\"${object}\"` : object;}// 处理数组类型if(Array.isArray(object)) {return `[${object.map(jsonStringify)}]`}// 处理对象类型return `{${Object.keys(object).map((key)=> `\"${key}\":${jsonStringify(object[key])}`)}}`
};

5. 两个对象之间的差异

LeetCode地址:2700. 两个对象之间的差异

请你编写一个函数,它接收两个深度嵌套的对象或数组 obj1obj2 ,并返回一个新对象表示它们之间差异。

该函数应该比较这两个对象的属性,并识别任何变化。返回的对象应仅包含从 obj1obj2 的值不同的键。对于每个变化的键,值应表示为一个数组 [obj1 value, obj2 value] 。不存在于一个对象中但存在于另一个对象中的键不应包含在返回的对象中。在比较两个数组时,数组的索引被视为它们的键。最终结果应是一个深度嵌套的对象,其中每个叶子的值都是一个差异数组。

你可以假设这两个对象都是 JSON.parse 的输出结果。

Pasted image 20230712211445.png

思路

该题要求比对两个对象,并将原值与修改后的值作为一个数组返回,如果是新增或者删除的属性,直接忽略不做处理。

假设有以下两个对象:

o1 = { a: 1, b: 2}
o2 = { a: 3, b: 2}

我们根据上面两个对象可以比对出属性 a 发生了变化,那么我们返回 {a:[1, 3]} 即可。

处理 JSON 的题,基本类似,无非考察递归的掌握与数据类型的控制,我们根据一下几个特征进行判断即可。

  • 如果 obj1 和 obj2 不是同一类型,直接返回 [obj1,obj2]
  • 如果 obj1 和 obj2 是都是基本类型时,直接判断结果,如果不一致则返回[obj1, obj2]
  • 如果 二者都是引用类型,则调用 objDiff(obj1[key], obj2[key]) 递归校验。

具体实现

/*** @param {object} obj1* @param {object} obj2* @return {object}*/
function objDiff(obj1, obj2) {// 如果 key 已经被删除,不做处理if(obj2 === void 0) return void 0;// 如果是基本类型,或者两个对象的类型不一样,则直接返回比对后的结果// 注:对象类型不一样,值一定不一样if(typeof obj1 !== 'object' || obj1 === null || isNotEqualsType(obj1, obj2)) {return obj1 === obj2 ? void 0 : [ obj1, obj2 ];}// 保存比对后的结果const diffMap = {};for(const key of Object.keys(obj1)){// 递归比对当前 key 是否一致const diff = objDiff(obj1[key], obj2[key]);// 如果是 undefined 或者 对象是空的,则说明对象是一致的if(diff !== void 0 && Object.keys(diff).length) {diffMap[key] = diff;}}return diffMap;
};
const getType = (val) => Object.prototype.toString.apply(val);
const isNotEqualsType = (val1 , val2) => getType(val1) !== getType(val2); 

三、结语

由于算法讲解本身就很难通过 少量的语言就能表述清除,让文字通俗易懂更是难上加难,为了避免篇幅太长而导致放弃或者直接丢到收藏夹中吃灰,所以本篇只提取了 5 道题进行讲解。

算法的实现本身就多种多样的,我的个人见解未必是最优解,我非常欢迎读者对我在文章中提出的观点、方法或示例进行评价和反馈。这对于我个人的成长和进步非常重要,也有助于确保我传达的信息准确无误。所以,请不要犹豫,如果你有任何想法或建议,请在阅读文章后留下你的评论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/tVUx/3235.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

SQL-FEFT JOIN (拼接表)

语法 SELECT column_name(s) FROM table1 LEFT JOIN table2 ON table1.column_nametable2.column_name; 按照一定规则,将表table1和表table2拼接起来。 例: Employees 表: ------------------------ | Column Name | Type | ------…

挑战!贪吃蛇小游戏的实现(3)

经过(1)(2)两篇文章的介绍,相信大家对该游戏的实现已经有了具体的思路,废话不多说,让我们开始实现相关的代码吧! 1.游戏主逻辑 void test() {int ch 0;srand((unsigned int)time(NU…

【Linux系统化学习】动静态库 | 软硬链接

目录 硬链接和软链接 硬链接 软链接 动态库和静态库 静态库 静态库的生成 静态库的使用 将库打包和使用 动态库 动态库的生成 动态库的使用 库搜索路径 硬链接和软链接 硬链接 上篇文章我们说到真正找到磁盘上的文件并不是文件名,而是inode。其实在…

【Appium UI自动化】pytest运行常见错误解决办法

通过Appium工具录制代码在pycharm上运行报错: 错误一: 1.提示 setup() 方法运行 error failed 解决办法:未创建 init __ 方法,创建一个空的__init.py文件就解决了。 原因: 错误二: 2.运行代码&#xff…

解决SpringAMQP工作队列模型程序报错:WARN 48068:Failed to declare queue: simple.queue

这里写目录标题 1.运行环境2.报错信息3.解决方案4.查看解决之后的效果 1.运行环境 使用docker运行了RabbitMQ的服务器: 在idea中导入springAMQP的jar包,分别编写了子模块生产者publisher,消费者consumer: 1.在publisher中运行测试…

PostgreSQL 的实体化视图介绍

PostgreSQL 实体化视图提供一个强大的机制,通过预先计算并将查询结果集存储为物理表来提高查询性能。本教程将使用 DVD Rental Database 数据库作为演示例子,指导你在 PostgreSQL中创建实体化视图。 了解实体化视图 实体化视图是查询结果集的快照&…

【ECharts】调用接口获取后端数据的四种方法

使用eacharts做大屏,需要使用后端数据,下面的方法是自己试过有效的,有什么不对的,望各位大佬指点。 目录 方法一:在mounted中使用定时器调用eacharts方法(定时器可以获取到data中的数据) 方法…

【C++精简版回顾】7.析构函数

1.析构函数 class MM { public:MM() {}MM(const char* a) {name new char[strlen(a)1];strcpy(name, a);cout << name << endl;}~MM() {delete[] name;name nullptr;cout << "调用析构函数" << endl;} private:char* name; }; int main(…

设计模式——工厂模式

定义: ​ 工厂顾名思义就是创建产品&#xff0c;根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式&#xff0c;根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。该模式用于封装和管理对象的创建&#xff0c;是一种创建型模式。 本章代码:小麻雀icknn/设…

Qt应用-录音机实例

本文讲解Qt录音机应用实例。 实现的功能 录音开始暂停停止、已录时间显示。 录音文件输出。 可用录音设备查找。 录音信息显示。 界面设计 UI文件 <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"><class>…

error: src refspec master does not match any

当git报这个错的时候&#xff0c;证明我们执行了git push命令&#xff0c;但是我们会发现代码提交不上去 git push -u origin main 执行这个命令就可以解决&#xff08;注释&#xff1a;现在master改成了main&#xff09;

C语言之mkdtemp()特定占位符:XXXXXX 用法实例(八十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

普中51单片机学习(十四)

中断系统 中断的概念 CPU在处理某一事件A时&#xff0c;发生了另一事件B请求CPU迅速去处理&#xff08;中断发生&#xff09;,CPU暂时中断当前的工作&#xff0c;转去处理事件B&#xff08;中断响应和中断服务)&#xff0c;待CPU将事件B处理完毕后&#xff0c;再回到原来事件…

10.vue学习笔记(组件数据传递-props回调函数子传父+透传Attributes+插槽slot)

文章目录 1.组件数据传递2.透传Attributes&#xff08;了解&#xff09;禁用Attributes继承 3.插槽slot 1.组件数据传递 我们之前讲解过了组件之间的数据传递&#xff0c;props 和 自定义事件 两种方式 props&#xff1a;父传子 自定义事件&#xff1a;子传父 props通过额外方…

nginx服务

“欢唱吧&#xff0c;呼唤它&#xff0c;回来啊~” Web服务器简介 Web服务器&#xff0c;一般是指“网站服务器”&#xff0c;其本质就是驻留于互联网中&#xff0c;某一台机器(计算机)上的进程(程序)。Web服务器通常就是为用户提供信息浏览服务&#xff0c;更可以放置数据文件…

强化学习入门(Matlab2021b)-创建环境【2】

目录 1 前言2 利用step和reset函数创建自定义环境2.1 对象描述2.2 reset函数2.3 step函数2.3 构建自定义环境3 使用匿名函数传递额外的参数4 可视化检查自定义函数的输出参考链接1 前言 本文介绍如何基于MATLAB编写step、reset函数,创建自己的强化学习环境(Environment)。 使…

Java面试题:volatile专题

王有志,一个分享硬核Java技术的互金摸鱼侠 加入Java人的提桶跑路群:共同富裕的Java人 今天是《面霸的自我修养》第4篇文章,我们一起来看看面试中会问到哪些关于volatile的问题吧。数据来源: 大部分来自于各机构(Java之父,Java继父,某灵,某泡,某客)以及各博主整理文档…

【C语言经典100题#4】判断三角形

题目名称&#xff1a; 输入三个整数a,b,c&#xff0c;判断由a,b,c作为三条边组成的三角形&#xff0c;如果不能组成三角形则输出&#xff1a;非三角形&#xff1b;如果是三角形&#xff0c;再继续判断&#xff0c;如果是等边三角形&#xff0c;则输出&#xff1a;等边三角形&a…

NLP_GPT生成式自回归模型

文章目录 介绍完整代码小结 介绍 自回归(Autoregressive)是自然语言处理模型的一种训练方法&#xff0c;其核心思想是基于已有的序列(词或字符)来预测下一个元素。在GPT中&#xff0c;这意味着模型会根据给定的上文来生成下一个词&#xff0c;如图所示。 在GPT模型的训练和推…

网络原理-TCP/IP(7)

目录 网络层 路由选择 数据链路层 认识以太网 以太网帧格式 认识MAC地址 对比理解MAC地址和IP地址 认识MTU ARP协议 ARP协议的作用 ARP协议工作流程 重要应用层协议DNS(Domain Name System) DNS背景 NAT技术 NAT IP转换过程 NAPT NAT技术的优缺点 网络层 路由…
推荐文章