LeetCode JS专栏刷题笔记(二)

news2025/1/19 17:12:05

一、前言

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.coloradmin.cn/o/1458207.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mac清理系统垃圾软件CleanMyMac X2025免费版本下载

嘿,Mac用户们,你是否经常感觉你的Mac就像是在背着一个沉重的包袱在跑步?是的,我在说那些堆积如山的系统垃圾。清理这些垃圾不仅可以让你的Mac跑得更快,还能让它“呼吸”更畅快。今天,让我们一起来探索如何M…

【医学大模型】MEDDM LLM-Executable CGT 结构化医学知识: 将临床指导树结构化,便于LLM理解和应用

MEDDM LLM-Executable CGT 结构化医学知识: 将临床指导树结构化,便于LLM理解和应用 提出背景对比传统医学大模型流程步骤临床指导树流程图识别临床决策支持系统 总结解决方案设计数据收集与处理系统实施临床决策支持 提出背景 论文:https://arxiv.org/p…

代码智能生成插件‘通义灵码‘使用指南

介绍 通义灵码,通义灵码,是阿里云出品的一款基于通义大模型的智能编码辅助工具,提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力,并针对阿里云的云服…

相机图像质量研究(36)常见问题总结:编解码对成像的影响--块效应

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结:光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结:光学结构对成…

Leo赠书活动-16期 名校毕业生教材

Leo赠书活动-16期 名校毕业生教材 ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 赠…

STM32的SDIO

一.SDIO简介 SDIO,全称Secure Digital Input/Output,是一种用于在移动设备和嵌入式系统中实现输入/输出功能的接口标准。它结合了SD卡的存储功能和I/O功能,允许设备通过SD卡槽进行数据输入输出和外围设备连接。 SDIO接口通常被用于连接各种…

基于SSM的在线教学质量评价系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的在线教学质量评价系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spri…

java中容易被忽视的toString()方法

之前一直认为toString就是将数据转换成字符类型,直到最近写出了一个bug才对toString有了新的认识 不同数据类型,toString() 有不同的操作 定义一个student类,包含姓名 String类型、性别 String类型、年龄 int 类型、分数列表 String类型的li…

网络安全工程师必知的WEB知识

作为一名网络安全工程师,尤其是WEB渗透测试工程师,必须掌握一些WEB相关的基础知识,下面重点从WEB服务架构、浏览器请求过程、服务器操作系统、WEB应用服务器、数据库系统、动态网站脚本语言、WEB前端框架等。 1. Web服务架构 Web服务主要分…

sensitive-word v0.13 特性版本发布 支持英文单词全词匹配

拓展阅读 sensitive-word-admin v1.3.0 发布 如何支持分布式部署? sensitive-word-admin 敏感词控台 v1.2.0 版本开源 sensitive-word 基于 DFA 算法实现的高性能敏感词工具介绍 更多技术交流 业务背景 对于英文单词 Disburse 之类的,其中的 sb 字母会被…

【Qt学习】QWidget的windowOpacity属性介绍与实例使用(双重检查的引入)

文章目录 1. windowOpacity 介绍2. 使用实例3. 题外话 - 双重检查(doubleCheck)代码资源 1. windowOpacity 介绍 我们可以查阅qt的官方文档,进行总结: windowOpacity() 表示窗口的不透明度级别。有效的范围是从1.0(完…

学习总结19

# 奶牛的耳语 ## 题目描述 在你的养牛场&#xff0c;所有的奶牛都养在一排呈直线的牛栏中。一共有 n 头奶牛&#xff0c;其中第 i 头牛在直线上所处的位置可以用一个整数坐标 pi(0< pi < 10^8) 来表示。在无聊的日子里&#xff0c;奶牛们常常在自己的牛栏里与其它奶牛交…

【天衍系列 05】Flink集成KafkaSink组件:实现流式数据的可靠传输 高效协同

文章目录 01 KafkaSink 版本&导言02 KafkaSink 基本概念03 KafkaSink 工作原理1.初始化连接2.定义序列化模式3.创建KafkaSink算子4.创建数据源5.将数据流添加到KafkaSink6.内部工作机制 04 KafkaSink参数配置05 KafkaSink 应用依赖06 KafkaSink 快速入门6.1 包结构6.2 项目…

《Solidity 简易速速上手小册》第5章:智能合约的安全性(2024 最新版)

文章目录 5.1 安全性的重要性5.1.1 基础知识解析深入理解安全性的多维度影响智能合约安全的关键要素 5.1.2 重点案例&#xff1a;防止重入攻击案例 Demo&#xff1a;构建一个防重入的提款合约案例代码WithdrawContract.sol 测试和验证拓展功能 5.1.3 拓展案例 1&#xff1a;预防…

设计模式二:代理模式

1、什么是动态代理 可能很多小伙伴首次接触动态代理这个名词的时候&#xff0c;或者是在面试过程中被问到动态代理的时候&#xff0c;不能很好的描述出来&#xff0c;动态代理到底是个什么高大上的技术。不方&#xff0c;其实动态代理的使用非常广泛&#xff0c;例如我们平常使…

【网站项目】059课程答疑系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

网络原理 - HTTP/HTTPS(3)

HTTP请求 认识请求"报头" header的整体的格式也是"键值对"的结构. 每个键值对占一行,键和值之间使用分号进行分割. 报头的种类有很多,此处仅介绍几个常见的. Host 表示服务器主机的地址和端口.(Host和URL中的ip地址端口啥的,绝大部分情况下都是一样的,少…

【力扣每日一题】力扣105从前序与中序遍历序列构造二叉树

题目来源 力扣105从前序与中序遍历序列构造二叉树 题目概述 给定两个整数数组 preorder 和 inorder &#xff0c;其中 preorder 是二叉树的先序遍历&#xff0c; inorder 是同一棵树的中序遍历&#xff0c;请构造二叉树并返回其根节点。 思路分析 前序遍历的顺序是&#x…

BERT架构简介

一、BERT模型架构 BERT沿用原始Transformer模型中的编码器层&#xff0c;具有编码器的堆叠。但BERT没有使用解码器层&#xff0c;因此没有掩码多头注意力子层。&#xff08;BERT的设计者认为&#xff0c;对序列后续部分进行掩码会阻碍注意力过程&#xff09;。于是&#xff0c;…

Java安全实现微信消息提醒女友喝水(自动化消息定时 + 间隔重复发送)

注意 本文基于Window系统来进行讲解&#xff0c;该程序要求当前PC端微信处于运行状态 前提准备 配置PC端微信的快捷键 保持默认就好&#xff0c;这一步主要是为了避免出现微信快捷键与其他软件冲突时&#xff0c;修改快捷键后要针对性修改代码内容 Robot 类 该功能实现主要利…