LeetCode 中的位运算
No136只出现1次的数字给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗? 使用计数器比较朴素的解法是对每个元素进行计数,最后统计出数量为1的那个数,这种算法比较通用,可以解决任意多元素出现任意次,因为可以解决的问题比较多,所以往往不是最好的算法,需要维护一个HashMap,占用O(N)的空间: 123456789101112var singleNumber = function (nums) { const counter = new Map(); for (const num of nums) { let count = counter.get(num) || 0; counter.set(num, ++count); } for (const [k, v] of counter) { if (v === 1) { return k; } ...
LeetCode No.55 跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例 1:输入: [2,3,1,1,4]输出: true解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。 示例 2:输入: [3,2,1,0,4]输出: false解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置。 回溯法首先想到的是暴力法,针对每个位置可能走的步数一个个进行测试,如果这个步数能到达或者超过最后一个位置说明就可以到达,写代码的过程中注意将已经计算过的缓存起来,使用记忆化搜索防止重复计算。还可以从最大可能走的步数开始减少代替自增这样的小技巧来优化: 123456789101112131415161718192021222324252627282930313233var canJump = function (nums) { const cache = {}; /** *...
LeetCode No.542 寻找 0-1 矩阵中的最小距离
给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1:输入: 1230 0 00 1 00 0 0 输出: 1230 0 00 1 00 0 0 示例 2:输入: 1230 0 00 1 01 1 1 输出: 1230 0 00 1 01 2 1 注意: 给定矩阵的元素个数不超过 10000。给定矩阵中至少有一个元素是 0。矩阵中的元素只在四个方向上相邻: 上、下、左、右。 方法一:多源广度优先搜索 对于矩阵中的每一个元素,如果它的值为0,那么离它最近的0就是它自己。如果它的值为1,那么我们就需要找出离它最近的0,并且返回这个距离值。那么我们如何对于矩阵中的每一个1,都快速地找到离它最近的0呢? 我们不妨从一个简化版本的问题开始考虑起。假设这个矩阵中恰好只有一个0,我们应该怎么做?由于矩阵中只有一个0,那么对于每一个1,离它最近的0就是那个唯一的0。如何求出这个距离呢?我们可以想到两种做法: 如果0在矩阵中的位置是(i0, j0),1在矩阵中的位置是 (i1,...
LeetCode No.234 回文链表
请判断一个链表是否为回文链表。 示例 1: 输入: 1->2输出: false示例 2: 输入: 1->2->2->1输出: true进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题? 转化成数组后使用双指针首先想到的方法是遍历链表,将链表中的元素添加进数组,然后使用双指针解法,一个指针从前向后扫描,另一个指针从后向前扫描,一旦发现两个指针所指向的元素不同则不是回文,否则两个指针向中间靠拢,如果两个指针相遇,则是回文。这种思路其实是判断回文字符串。 1234567891011121314151617var isPalindrome = function (head) { let arr = []; let cur = head; while (cur) { arr.push(cur.val); cur = cur.next; } let i = 0, j = arr.length - 1; while (i < j) { if (arr[i] !==...
LeetCode No.19 删除链表中的倒数第 k 个元素
很容易想到的是先求出链表中元素的总个数,然后删除正数第n-k个元素,代码如下(下面的代码使用了虚拟头结点优化判断删除头结点的情况) 1234567891011121314151617181920var removeNthFromEnd = function (head, n) { let count = 0; let cur = head; while (cur) { cur = cur.next; count++; } const dummyHead = new ListNode(-1); dummyHead.next = head; let prev = dummyHead; cur = head; let cnt = 0; while (cnt < count - n) { prev = cur; cur = cur.next; cnt++; } prev.next = cur.next; return...
LeetCode No22.括号生成
题目描述如下: 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例: 12345678输入:n = 3输出:[ "((()))", "(()())", "(())()", "()(())", "()()()" ] 暴力破解初看这一题,首先想到的是n个左括号和n个右括号的数组进行全排列得到所有的序列,然后从序列中过滤出合法的括号序列和重复序列(因为字符是有重复的,可能导致全排列本身中出现序列重复), 代码如下: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647var generateParenthesis = function (n) { // 方案1:获取数组全排列,判断全排列中合法的括号 const arr = []; ...
如何实现 async/await
基于 Promise 的异步处理虽然解决了基于 callback 的过多嵌套的问题,但是可读性也并没有强多少,流程控制也不是特别方便,所以 ES7 提出了 async 函数完美解决了上述问题。async/await实际上是对Generator 的封装,是生成器函数的语法糖。 async函数是AsyncFunction构造函数的实例,并且在函数体中允许使用 await 关键字。await 操作符用于等待 Promise 兑现并获取它兑现之后的值,智能在 async 函数或者顶层模块中使用。async 和 await 关键字让我们可以用一种更简洁的方式写出基于 Promise 的异步行为,而无需刻意地链式调用 Promise ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流程挂起,通过next()方法可以切换到下一个状态,为改变执行流程提供了可能,从而为异步编程提供解决方案。 yield 表达式本身没有返回值(或者总是返回 undefined),next 方法可以带一个参数,该参数就会被当作上一个 yield...
如何实现 Promise
先来看下 Promise 的常见应用: 观察者模式观察上面的这个例子,我们来分析 Promise 的调用流程: 构造方法接受一个 executor 函数,在 new Promise 的时候这个 executor 立即执行 executor 内部的异步任务被放入微任务队列等待执行 then 被执行,收集成功/失败回调,放入成功/失败队列 executor 的异步任务被执行,触发resolve/reject,从成功/失败队列中取出回调依次执行 由上面的分析得知这是一种典型的观察者模式。这是典型的“收集依赖->触发依赖->取出依赖执行”的方式,在 Promise 中执行顺序是 “then收集依赖->异步触发resolve->resolve执行依赖”。由此我们可以勾勒出 Promise 的大致形状: 123456789101112131415161718192021222324252627282930class Promise{ constructor(executor){ ...
一些好用的轮子和工具
canvas绘图阿里的数据可视化的底层框架g2,无需从头到尾操作原生canvas api了,画线、矩形、圆形、贴图等非常便利。 提高效率的chrome拓展 双向修改CSS的工具livestyle 常见的网关 Openresty:基于 Nginx 的高性能 Web 平台,集成了大量模块,用来处理 HTTP 请求,被许多企业作为内部网关的基础框架 Kong:构建在 OpenResty 上的网关平台,有丰富的插件体系,支持身份认证、限流、日志记录、监控等功能 大模型 从 0 开始写大模型 基于 AI 的浏览器自动化 githubgithub 文件加速: https://ghproxy.link/ https://ghfast.top/ 优秀的开源项目 https://github.com/leaper-one/MultiPost-Extension https://github.com/dgtlmoon/changedetection.io
一些生活技能
我当然不喜欢贫穷,人穷志短,成天为衣食住行操心是很毁人的。但我从不梦想着大富大贵,因为人一旦把赚钱当作目的,就永远也不会觉得够。富了终归可以更富,走上这条路的人,很少能够自己停下来。有大量触目惊心的权钱交易的案例已经证明,对金钱的贪欲会使人不顾一切,甚至不要性命。千万不要以为,这些一失足成千古恨的人是天生的坏人。事实上,他们与我们中间许多人的区别只在于,他们恰好处在一个直接面对巨大诱惑的位置上。赚多少钱是个够?永远也没够!不管是谁,赚钱的目的,不过是为了更幸福。但有时候,我们走得太远,慢慢忘记了为什么出发。 健身食材香蕉 燕麦 鸡胸 鸡蛋...