news 2026/5/23 12:53:13

双指针专题(一):其实是“覆盖”元素——「移除元素」

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
双指针专题(一):其实是“覆盖”元素——「移除元素」

欢迎来到双指针专题第一篇!

场景想象:你手里有一叠扑克牌(数组),里面混进去了几张“鬼牌”(需要移除的元素val)。

  • 暴力做法:每看到一张鬼牌,把它抽出来,然后把后面所有的牌往前挪一格填补空缺。

  • 双指针做法:如果不想要鬼牌,我们根本不用“抽”它。我们只需要把好牌一张张地往前挪,把鬼牌的位置给覆盖掉就行了。

力扣 27. 移除元素

https://leetcode.cn/problems/remove-element/

题目分析:

  • 输入:数组nums,值val

  • 目标原地移除所有数值等于val的元素。

  • 输出:返回移除后数组的新长度k

  • 要求:空间复杂度必须是 O(1)。

例子:nums = [3, 2, 2, 3], val = 3

  • 结果:k = 2,nums的前两个元素应该是[2, 2]。后面剩啥无所谓。

核心思维:快慢指针 (Fast & Slow Pointers)

我们定义两个指针:

  1. 快指针 (fast)探路者。它的任务是遍历数组,寻找新数组里需要的元素(即不等于val的元素)。

  2. 慢指针 (slow)建筑师。它指向下一个新元素应该存放的位置

操作逻辑:

  • fast指针在前面跑,如果nums[fast]是“鬼牌”(等于val):

    • fast继续往前跑,忽略它(相当于直接跳过)。

  • 如果nums[fast]是“好牌”(不等于val):

    • 把这张好牌拿过来,覆盖到slow指向的位置:nums[slow] = nums[fast]

    • 然后slow向前走一步,准备接下一张好牌。

  • 最后,slow的数值就是新数组的长度。

为什么不用splice

作为前端,我们太熟悉nums.splice(i, 1)了。 但是,splice的底层实现是把删除位置后面的所有元素都往前挪一位。这是一个 O(N) 的操作。 如果你在for循环里用splice,那就是 O(N2) 的复杂度。 而双指针法只需要遍历一次,复杂度是O(N)

代码实现 (JavaScript)

JavaScript

/** * @param {number[]} nums * @param {number} val * @return {number} */ var removeElement = function(nums, val) { // 慢指针:指向下一个“好元素”应该存放的位置 let slow = 0; // 快指针:负责遍历数组,寻找“好元素” for (let fast = 0; fast < nums.length; fast++) { // 如果快指针找到的不是目标值(是好元素) if (nums[fast] !== val) { // 把它挪到慢指针的位置(覆盖旧数据) nums[slow] = nums[fast]; // 慢指针向前一步,准备接下一个 slow++; } // 如果 nums[fast] === val,那就什么都不做 // 快指针会自动 fast++ 跳过它,慢指针原地不动 } // 此时 slow 的值,刚好就是新数组的长度 return slow; };

深度模拟

nums = [0, 1, 2, 2, 3, 0, 4, 2],val = 2

  1. fast=0(0): 不是2。填入nums[0],slow变 1。 ([0...])

  2. fast=1(1): 不是2。填入nums[1],slow变 2。 ([0, 1...])

  3. fast=2(2): 是2!跳过。slow还是 2。

  4. fast=3(2): 是2!跳过。slow还是 2。

  5. fast=4(3): 不是2。填入nums[2],slow变 3。 ([0, 1, 3...])

    • 注意:原来的23覆盖了。

  6. ...以此类推。

总结

这道题是双指针最基础的应用——原地操作数组。 记住这个口诀:快指针找,慢指针填。

这种“覆盖”的思想在后面很多题目(比如“移动零”、“删除有序数组重复项”)中都会用到,是必须掌握的肌肉记忆。


下一题预告:有序数组的平方

好了,热身结束。下一题我们稍微加点难度。

  • 给你一个按非递减顺序排序的整数数组[-4, -1, 0, 3, 10]

  • 要求返回每个数字的平方组成的新数组,也要按非递减顺序排序。

  • 输出:[0, 1, 9, 16, 100]

难点在于:负数平方后可能变得很大。最大的数可能在最左边(负数),也可能在最右边(正数)。 这时候,如果还在用快慢指针从一头往另一头跑,肯定不行。我们需要两个指针,分别站在数组的两头,像决斗一样向中间逼近。

准备好迎接**“左右指针”**的挑战了吗?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 5:11:29

BNB/GPTQ/AWQ量化全面支持:低成本部署大模型的关键路径

BNB/GPTQ/AWQ量化全面支持&#xff1a;低成本部署大模型的关键路径 在一台24GB显存的RTX 3090上运行Llama-3-8B&#xff0c;曾经是遥不可及的梦想。如今&#xff0c;借助成熟的量化技术&#xff0c;这已成为常态。当大模型参数规模突破千亿、万亿量级&#xff0c;推理与训练的硬…

作者头像 李华
网站建设 2026/5/14 10:37:45

UnSloth加速微调原理剖析:为什么它能快十倍?

UnSloth加速微调原理剖析&#xff1a;为什么它能快十倍&#xff1f; 在大模型时代&#xff0c;训练效率早已不再是“锦上添花”的优化项&#xff0c;而是决定项目能否落地的核心瓶颈。一个原本需要三天才能完成的微调任务&#xff0c;若能压缩到几小时甚至几十分钟&#xff0c;…

作者头像 李华
网站建设 2026/5/6 0:11:04

无头浏览器测试的威力与应用场景

无头浏览器测试的定义与背景 无头浏览器&#xff08;Headless Browser&#xff09;测试是一种在无图形用户界面&#xff08;GUI&#xff09;环境下运行的浏览器自动化测试技术。它通过命令行或脚本控制浏览器内核&#xff08;如Chromium或WebKit&#xff09;&#xff0c;模拟用…

作者头像 李华
网站建设 2026/5/14 1:05:40

网盘直链助手防封策略:动态更换User-Agent绕过限制

网盘直链助手防封策略&#xff1a;动态更换User-Agent绕过限制 在AI模型快速迭代的今天&#xff0c;研究人员和工程师经常面临一个看似简单却令人头疼的问题——下载公开模型权重时遭遇403禁止访问。明明链接是公开的&#xff0c;浏览器点开能看&#xff0c;但用脚本一拉就失败…

作者头像 李华
网站建设 2026/5/22 15:38:19

ms-swift框架深度解析:从预训练到人类对齐的一站式解决方案

ms-swift框架深度解析&#xff1a;从预训练到人类对齐的一站式解决方案 在大模型技术飞速演进的今天&#xff0c;开发者面临的已不再是“有没有模型可用”&#xff0c;而是“如何高效地用好模型”。开源社区每天涌现新的架构、新的权重、新的训练范式&#xff0c;但随之而来的是…

作者头像 李华
网站建设 2026/5/6 23:41:45

评测数据集全覆盖:MMLU、CEval、GSM8K等权威榜单支持

评测数据集全覆盖&#xff1a;MMLU、CEval、GSM8K等权威榜单支持 在大模型研发日益工业化的今天&#xff0c;一个常被忽视却至关重要的环节正逐渐浮出水面——标准化评测。我们见过太多团队投入大量资源训练出参数惊人的模型&#xff0c;却因缺乏系统性评估而无法准确判断其真…

作者头像 李华