- 博客(429)
- 收藏
- 关注
原创 Leetcode 148 最长递增子序列 | 三角形最小路径和
dp [i] = 以 nums [i] 这个数字结尾的最长递增子序列长度必须以第 i 个数结尾!
2026-03-28 15:36:07
239
原创 Lexical依赖版本冲突与标题渲染
修复了因 Lexical 依赖版本冲突导致的 PDF/Doc 导出崩溃问题,以及文档标题更新后的 UI 同步问题。总结依赖管理、错误定位及 Hook 与工具函数选型的经验。
2026-03-28 13:52:11
754
原创 万字长文:从零实现 JWT 鉴权
本文系统回顾JWT鉴权实现,详解Express中间件校验、MongoDB用户模型设计,覆盖前后端交互、状态管理与安全实践,完整呈现一套可落地的身份认证方案。
2026-03-26 16:34:03
568
原创 Leetcode 146 爬楼梯 | 打家劫舍
把大问题拆成小问题 → 找到小问题的规律(递推公式)→ 用小问题的答案算出大问题的答案它的核心就是不重复计算,把之前算过的结果存起来,直接用。爬楼梯本质就是斐波那契数列动态规划三步:定义dp[i]写递推公式初始化 + 循环计算代码优先用优化迭代版,效率最高dp[i]= 偷到第 i 间房子时,能偷到的最大金额偷 = 前前一个 + 当前钱不偷 = 前一个的钱选最大的那个!dp [i] = 到第 i 个位置时的答案永远只有2 种选择(99% 的题)
2026-03-25 23:57:52
444
原创 Leetcode 145 回文数 | 加一
给你一个整数x,如果x是一个回文整数,返回true;否则,返回false。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。121123x = 121truex = -121false从左向右读, 为 -121。从右向左读, 为 121-。因此它不是一个回文数。x = 10false从右向左读, 为 01。因此它不是一个回文数。你能不将整数转为字符串来解决这个问题吗?
2026-03-24 23:45:08
469
原创 AJAX vs Fetch API:Promise 与异步 JavaScript 怎么用?
从 AJAX 到 Fetch,详解 Promise 用法、链式调用与 async/await,掌握现代 JS 异步编程。
2026-03-24 12:02:42
533
原创 Leetcode 144 位1的个数 | 只出现一次的数字
核心思路:遍历 32 位整数的每一位,用1 << i定位第i位,再用运算判断该位是否为 1,统计总数。位运算关键1 << i生成 “掩码”,n & 掩码仅保留第i位的数值,非 0 则说明该位是 1。边界处理:循环固定 32 次,确保覆盖 32 位整数的所有位(包括最高位的符号位)。
2026-03-22 23:51:13
381
原创 万字长文:编辑器集成Vercel AI SDK
本文复盘块级编辑器集成AI SDK全过程,涵盖前端UI插槽注入、后端工具调用、ID约束守卫及流式协议对接等核心机制与问题解决方案。
2026-03-22 20:49:16
595
原创 Leetcode 143 搜索插入位置 | 搜索二维矩阵
这道题的核心是二分查找,必须保证时间复杂度 O (log n),因此不能用遍历(遍历的时间复杂度是 O (n))。二分查找的关键:正确计算mid避免溢出,通过调整leftright缩小查找范围,循环结束后left就是插入位置。无需单独处理 “数组为空”“目标值在开头 / 结尾” 的边界情况,核心逻辑已覆盖所有场景(比如target比所有元素大时,left最终等于数组长度,正好是插入末尾的位置)。核心错误。
2026-03-21 12:36:24
348
原创 高并发下的列表乱序与文档同步
删除一个看似多余的useEffect,不仅修复了高并发下的列表乱序,也让我重新思考了全栈开发中那些“简单粗暴”的实现与后续优化空间。
2026-03-20 11:38:02
1021
原创 Leetcode 142 将有序数组转换为二叉搜索树 | 排序链表
核心逻辑:利用升序数组的中点作为根节点,递归构建左右子树,既满足 BST 的中序遍历特性,又保证平衡(左右子树高度差≤1)。关键细节:选择中点时用避免溢出,递归终止条件是区间无元素(l > r)。灵活性:中点也可选择(右中点),最终结果不同但仍满足 “平衡 BST” 要求(如示例中两种答案均正确)。核心逻辑:JS 版本和 C++ 版本思路完全一致,通过递归选数组中点作为根节点,分别构建左右子树。JS 特有细节:需手动定义TreeNode类,除法后用Math.floor取整,避免浮点数问题。
2026-03-19 23:30:10
378
原创 Leetcode 141 最长公共前缀 | 罗马数字转整数
以第一个字符串为基准,逐字符串对比、逐步缩短公共前缀,是解决该问题最直观且高效的方法。优化点:提前终止循环(前缀为空时直接退出),避免无效遍历,提升实际运行效率。边界处理:必须考虑数组为空、字符串长度为 0 的情况,确保代码鲁棒性。注意substr substring 方法截取公共长度。核心规则:遍历每个字符,若当前值 < 下一个值则减,否则加,最后一个字符直接加。关键工具:用哈希表()存储字符 - 数值映射,实现 O (1) 时间查找。复杂度。
2026-03-18 21:51:16
363
原创 前后端对接: ESM配置与React Router
开发者复盘全栈项目踩坑经历:从ESM模块配置、TS导入后缀到React Router数据流,梳理了架构设计、请求规范和分层逻辑,强调“复盘>有思考地敲代码>盲目CV”的成长理念。
2026-03-18 20:51:53
507
原创 Leetcode 140 括号生成 | 单词搜索
核心规则:生成有效括号的关键是「左括号不超 n,右括号不超左括号」,在生成过程中直接保证有效性,无需事后验证。回溯逻辑:先尝试加左括号(满足条件时),递归到底后回溯;再尝试加右括号(满足条件时),递归到底后回溯。效率优势:这种做法不会生成无效组合,比「生成所有组合再验证」的方式效率高得多(n=8 时尤为明显)。行号x:向上走行号减 1(x-1),向下走行号加 1(x+1列号y:向左走列号减 1(y-1),向右走列号加 1(y+1数组{行偏移, 列偏移}刚好对应这个规则,是行业通用写法。
2026-03-16 23:32:06
372
原创 react-i18next 国际化支持
本文记录基于 React + react-i18next + BlockNote 实现项目国际化过程,解决编辑器语言切换、白屏及内容丢失问题,总结实战踩坑与优化思路。
2026-03-16 22:52:21
553
原创 订阅模式实现字符数统计
本文基于订阅模式实现实时字符统计,通过监听编辑器内容变更,结合防抖处理分离计算与渲染,提升前端性能,避免页面卡顿,最终通过自定义 Hook 完成逻辑封装与状态传递。
2026-03-13 23:34:41
514
原创 前端性能优化之首屏提速
本文记录前端首屏优化实践,从包体积分析、Rollup 配置、拆包原则到性能测评踩坑,反思自身技术不足,总结优化经验与误区。
2026-03-12 23:14:24
598
原创 Leetcode 138 全排列 | 组合总和
/ 最终保存所有全排列的结果// 临时保存当前正在构建的排列(比如[1,2])// 标记数字是否被使用(比如used[0]=true表示nums[0]已选)result:最终要返回的答案,是二维数组(每个元素是一个排列)path:记录当前选了哪些数字,比如选了 1 之后 path=[1],再选 2 之后 path=[1,2]used:避免重复选择同一个数字(比如选了 1 之后,不能再选 1)全排列的核心是回溯:通过「选择 - 递归 - 回溯」的流程枚举所有可能的排列,used。
2026-03-12 22:35:42
404
原创 编辑器项目开发复盘:主题切换
本文记录编辑器项目开发复盘,完成主题切换,重新规划本地存储与后端架构,与 UI 布局,深入理解 React Context、工程化主题方案及组件架构,反思学习与成长。
2026-03-11 23:53:25
1207
原创 Leetcode 137 组合 | 电话号码的字母组合
路径(已选数字)+ 选择列表(可选数字)+ 结束条件(选够 k 个数);关键优化点:通过start参数避免重复组合,通过剪枝减少无效遍历;做出选择 → 递归 → 撤销选择,这是所有回溯问题的通用框架。这个框架可以套用到所有组合、排列、子集类的回溯问题中,掌握后就能解决大部分同类题目。变量作用域res和path定义在内部,导致每次递归都会重置,无法累积结果;语法错误:箭头函数少写了,正确是;递归参数错误应该是i+1。
2026-03-11 23:22:12
440
原创 从0到1实现块级编辑器的文件导入
BlockNote导入功能开发复盘:从Markdown有损转换、React useRef脱围操作DOM,到TypeScript扩展接口解决非标准属性冲突,完整记录一个功能背后的思考与踩坑。
2026-03-10 23:10:11
1075
原创 Leetcode 136 最小栈 | 逆波兰表达式求值
/ 主栈:存储所有元素// 辅助栈:存储最小值C++ 的stack是 STL 容器,默认提供push()pop()top()empty()方法,无需自己实现基础栈功能。核心方案:用「主栈 + 辅助栈」实现,辅助栈始终存储当前主栈的最小值,保证getMin()是 O (1) 时间。关键逻辑push时辅助栈仅压入更小 / 相等的元素,pop时仅当弹出的是最小值才同步弹出辅助栈。复杂度。
2026-03-10 21:34:07
379
原创 从0到1实现多格式浏览器文档导出
开发者基于BlockNote生态,通过模块化重构实现了多格式文件导出功能,核心围绕数据转换、Hook封装及细节优化展开。
2026-03-09 23:25:18
490
原创 Leetcode 135 有效的括号 | 简化路径
栈(利用后进先出特性匹配括号顺序);核心逻辑:右括号必须与「最近未匹配」的左括号类型一致;关键细节:遍历中遇到不匹配 / 栈空的右括号直接返回false,遍历结束后栈必须为空才有效。JS 中用数组模拟栈是最常用的方式,push/pop操作时间复杂度都是 O (1),和 C++ 栈效率一致;核心逻辑完全复用 C++ 的思路:右括号匹配最近的左括号,不匹配直接返回 false,最终栈空则有效;关键差异:JS 用对象代替哈希表、用数组代替栈,语法更简洁但逻辑完全等价。核心思路。
2026-03-09 20:39:39
391
原创 今日开发反思:编辑器大纲跳转与数据持久化实践
本文复盘编辑器项目大纲跳转与数据持久化开发过程,记录踩坑经历与解决方案,梳理Hook理解与数据流,见证新手前端成长。
2026-03-08 23:38:24
1023
原创 Leetcode 134 存在重复元素 II | 最长连续序列
核心思路:用哈希集合去重 + 只从「连续序列起点」开始统计长度,保证 O (n) 时间复杂度。关键优化!避免重复遍历,是实现 O (n) 的核心。复杂度:时间 O (n)(每个元素最多访问两次),空间 O (n)(哈希集合存储所有元素)。
2026-03-08 20:13:59
388
原创 Leetcode 133 快乐数 | 字母异位词分组
核心逻辑:通过哈希集合检测平方和计算过程中的循环,避免无限迭代。关键步骤:拆分数字计算平方和 + 哈希集合判重。时间 / 空间复杂度:时间复杂度 O (log n)(每次计算平方和,数字位数减少),空间复杂度 O (log n)(集合存储的数的个数)。如果想优化空间复杂度,还可以用「快慢指针法」(不用哈希集合),原理类似检测链表环:慢指针每次算 1 次平方和,快指针每次算 2 次平方和,若相遇则说明有循环,不是快乐数;若快指针先到 1,则是快乐数。核心逻辑不变。
2026-03-07 21:31:36
380
原创 Vercel部署: Vite Monorepo踩坑与原理小记
本文记录 Vercel 部署前端项目因找不到 dist 报错的排查过程,理清构建、部署逻辑与浏览器原理,掌握 Vercel 配置优先级与前端工程化核心流程。
2026-03-06 23:04:22
621
原创 Leetcode 132 同构字符串 | 有效的字母异位词
必须同时维护双向映射,只检查单向映射会漏掉「不同字符映射到同一个字符」的错误情况;实现关键:用两个分别存储s→t和t→s,遍历过程中验证映射的一致性;时间 / 空间复杂度:O (n)(n 为字符串长度),每个字符遍历一次,哈希表操作是 O (1) 平均时间复杂度。的核心作用是判断哈希表中是否存在指定的键;这是 C++ 哈希表 / 映射容器的标准查找方式,适用于map等;等价写法更简洁,新手可以优先用这个,逻辑更直观。JS 中用普通对象替代 C++ 的,核心键值对逻辑完全复用;
2026-03-06 20:17:05
380
原创 Leetcode 131 用最少数量的箭引爆气球 | 赎金信
你的错误核心:把 “合并区间(求并集)” 当成了 “找重叠区间(求交集)”,导致区间越合越大,结果错误;正确思路:贪心算法,按气球右边界排序,每支箭射在当前气球的右边界,尽可能覆盖更多后续气球;关键操作:遍历过程中判断当前气球的左边界是否超过上一支箭的位置,超过则新增箭,并更新箭的位置。这个思路的时间复杂度是 O (n log n)(主要是排序的时间),空间复杂度 O (1)(忽略排序的系统空间),符合题目中10^5数据量的要求。统计字符频率 + 校验频率是否满足需求。
2026-03-05 11:20:46
350
原创 Leetcode 130 合并区间 | 插入区间
解决合并区间问题的核心是先排序,后合并,排序保证了相邻区间的可比较性,合并只需遍历一次即可完成;合并的关键判断条件是:当前区间的起始值 ≤ 结果数组最后一个区间的结束值,满足则合并,否则直接加入;时间复杂度主要由排序决定(O(n log n)),遍历合并是O(n),整体为O(n log n),空间复杂度为O(log n)(排序的栈空间)或O(n)(存储结果),符合题目要求。先按起始值升序排序,再遍历合并重叠区间;语法差异主要在:排序回调规则(JS 用数值差,C++ 用布尔值)、数组操作(
2026-03-02 22:58:50
646
原创 Leetcode 129 移除元素 | 轮转数组
核心错误:旋转公式写错(而非),且未处理 k 大于数组长度的情况;原地修改关键:不能直接赋值数组,需逐个把临时数组的值写回原数组;优化思路:三次反转法可实现 O (1) 空间复杂度的原地旋转。不能直接替换数组引用(比如 JS 中nums = res),必须通过索引逐个赋值(C++ 中vector的assign函数是例外(会直接替换原数组内容),但本质也是底层重新赋值。移除元素:双指针,快指针找有效元素,慢指针存有效元素;轮转数组:临时数组 + 取模算索引,或三次反转实现原地轮转。
2026-03-01 18:27:10
835
原创 cpp 10 vector 容器的初始化方式 | static_cast<int>(x) | assign 函数
核心是创建长度为 k、每个元素都是空指针的链表节点指针数组;这种写法适配题目需求:提前预留 k 个位置,不足的部分用nullptr填充,符合「分割成 k 个部分,不足则为 null」的要求;显式指定nullptr比只写(k)更易读,是新手推荐的写法。是 C++ 的静态强制类型转换语法,用于将兼容的类型(如 char)转换为 int,比 C 语言的强制转换更安全,是推荐用法。abs()是标准库的绝对值函数,用于获取数值的非负值,需要包含<cmath>头文件。这行代码的核心目的是。
2026-03-01 18:19:18
631
原创 Leetcode 128 汇总区间
核心逻辑:用start标记区间起点,遍历数组判断连续(),不连续则闭合当前区间,最后处理末尾区间。格式规则:区间起点和终点相同输出"a",不同则输出"a->b"。模板要点:初始化起点→遍历判断连续性→闭合区间→处理最后区间,这个框架可复用解决多数有序数组的区间合并问题。核心错误修正:JS 里结果要初始化为空数组[],不是null;遍历结束必须处理最后一个区间。JS 语法要点:用===做严格相等判断,字符串拼接用模板字符串${}更简洁,数组用push添加元素。解题逻辑不变。
2026-02-26 23:50:52
601
原创 Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
核心解法是双指针法,利用数组 “有序” 的特性,通过慢指针标记唯一元素位置、快指针遍历找新元素,实现原地去重。边界条件要处理:数组为空时直接返回 0。最终返回值是slow + 1(因为慢指针是索引,从 0 开始),数组前slow + 1个元素就是去重后的结果。这个解法完全满足题目 “原地修改、保持相对顺序、返回唯一元素个数” 的所有要求,也是这道题的最优解。核心解法:双指针法,核心判断条件从 “和慢指针当前位置不同” 升级为 “和慢指针前一位位置不同”,实现 “最多保留 2 次” 的逻辑。
2026-02-25 22:04:53
657
原创 Leetcode 126 两数之和 II - 输入有序数组 | 盛最多水的容器
核心优化是找到结果后立即返回,避免无效循环,这是提升执行效率的关键。减少重复的和计算、简化返回逻辑,让代码更简洁且性能更好。双指针法本身已是该问题的最优解法(时间 O (n)、空间 O (1)),优化后保持了最优复杂度,仅提升代码的执行效率和可读性。双指针法的核心是移动较矮的指针,因为盛水量由矮边决定,移动高边无法提升有效高度,只会减少宽度;该解法将时间复杂度从暴力法的 O (n²) 优化到 O (n),是本题的最优解;代码逻辑简洁,关键是理解 “宽度最大优先,逐步优化高度” 的思路。
2026-02-21 23:45:15
685
原创 Leetcode 125 验证回文串 | 判断子序列
核心步骤是预处理字符串(过滤非字母数字 + 转小写)和双指针对比,两步结合即可验证回文串。利用isalnum和tolower函数可以高效完成字符预处理,避免手动判断字符范围的繁琐。双指针法的时间复杂度为 O (n)(n 为原字符串长度),空间复杂度为 O (n)(存储预处理后的字符串),在题目数据范围(2*10^5)内效率足够。如果想优化空间复杂度,可以不单独存储预处理后的字符串,而是在原字符串上直接用双指针跳过非字母数字字符,不过代码可读性会稍低,新手先掌握上述实现方式即可。
2026-02-20 23:37:04
644
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅