【力扣26&80】删除有序数组中的重复项

1. 力扣题目链接


2. 解题思路(统一以80题进行讲解)

两道题的核心思想一致:利用数组已排序的特性 + 双指针原地去重

共同前提

  • 输入数组 nums 升序排列
  • 要求 原地修改,不能使用额外数组
  • 返回新长度 k,前 k 个元素为有效结果

差异点

题目 保留次数 判断条件
LeetCode 26 每个元素最多出现 1 次 nums[r] != nums[l - 1]
LeetCode 80 每个元素最多出现 2 次 nums[r] != nums[l - 2]

因为数组是排好序的 !这意味着相同的数字一定是挨在一起的,比如:

复制代码
[1, 1, 1, 2, 2, 3]

我们不用到处找重复,只要盯着"连续的一串"就行。

我们的目标不是真的"删掉"元素(数组长度不能变),而是把合法的元素挪到前面,然后告诉别人:"前 k 个是我整理好的,后面的不用管"。

这就引出了一个超好用的技巧:双指针

  • 快指针(r):负责"看"每一个元素;
  • 慢指针(l):负责"记"下一个该放哪里。

3. 代码思路(双指针通用模板)

① 同向双指针法(通用解法)

  • 前 x 个数字肯定能留(比如 x=2,那前两个 1 肯定没问题);
  • 从第 x+1 个开始,每次看看:当前这个数,和"已经保留的倒数第 x 个"是不是一样?
    • 如果一样 → 说明已经有 x 个了,不能再要;
    • 如果不一样 → 可以放心收下!
java 复制代码
// 保留至多 x 次(x = 1 → LeetCode 26;x = 2 → LeetCode 80)
class Solution {
    public int removeDuplicates(int[] nums) {
        int x = 2; // 改为 1 即可解决 LeetCode 26
        if (nums.length <= x) return nums.length;

        int l = x; // 慢指针,指向下一个可写入的位置
        for (int r = x; r < nums.length; r++) {
            // 只有当 nums[r] 与 nums[l - x] 不同时,才允许保留
            if (nums[r] != nums[l - x]) {
                nums[l++] = nums[r];
            }
        }
        return l;
    }
}

💡 为什么是 l - x

因为我们最多保留 x 个相同元素。若 nums[r] == nums[l - x],说明前面已经有 x 个相同值了,不能再加!


② 模拟栈法(灵茶山艾府 思路)

你可以把数组的前半部分想象成一个小盒子(栈),里面装的是我们认可的元素。

  • 盒子一开始就有前两个元素(x=2);
  • 新来的元素想进盒子?先看看盒子里倒数第二个 是不是和它一样:
    • 一样 → 盒子里已经有俩了,不能再进;
    • 不一样 → 欢迎加入!

把数组前部当作"栈",用 stackSize 表示当前有效长度。

java 复制代码
class Solution {
    public int removeDuplicates(int[] nums) {
        int stackSize = 2; // 前两个元素默认保留
        for (int i = 2; i < nums.length; i++) {
            // 如果当前元素 ≠ 栈顶下方第 2 个(即倒数第 2 个),说明可以入栈
            if (nums[i] != nums[stackSize - 2]) {
                nums[stackSize++] = nums[i]; // 入栈
            }
        }
        return Math.min(stackSize, nums.length); // 兼容长度 < 2 的情况
    }
}

🌟 优点:思维直观,易于推广到"保留至多 k 次"的通用问题。


4. 知识点总结

核心技巧

  • 同向双指针(快慢指针):快指针遍历,慢指针维护有效区域。
  • 原地操作:直接在输入数组上修改,节省空间。
  • 利用有序性:相同元素连续,只需比较固定偏移位置。

时间 & 空间复杂度

  • 时间复杂度:O(n),仅一次遍历
  • 空间复杂度:O(1),仅用常数额外变量

可扩展性

  • 此方法可轻松推广到 "保留至多 k 次" 的通用问题:

    java 复制代码
    if (nums[r] != nums[l - k]) { ... }

感兴趣的宝子可以关注一波,后续会更新更多有用的知识!!!

相关推荐
小O的算法实验室14 小时前
2026年ASOC,基于深度强化学习的无人机三维复杂环境分层自适应导航规划方法,深度解析+性能实测
算法·无人机·论文复现·智能算法·智能算法改进
郭涤生15 小时前
STL vector 扩容机制与自定义内存分配器设计分析
c++·算法
༾冬瓜大侠༿15 小时前
vector
c语言·开发语言·数据结构·c++·算法
Ricky111zzz15 小时前
leetcode学python记录1
python·算法·leetcode·职场和发展
汀、人工智能15 小时前
[特殊字符] 第58课:两个正序数组的中位数
数据结构·算法·数据库架构··数据流·两个正序数组的中位数
liu****15 小时前
第16届省赛蓝桥杯大赛C/C++大学B组(京津冀)
开发语言·数据结构·c++·算法·蓝桥杯
汀、人工智能15 小时前
[特殊字符] 第79课:分割等和子集
数据结构·算法·数据库架构·位运算·哈希表·分割等和子集
汀、人工智能16 小时前
[特殊字符] 第74课:完全平方数
数据结构·算法·数据库架构·图论·bfs·完全平方数
CoderCodingNo16 小时前
【GESP】C++四、五级练习题 luogu-P1177 【模板】排序
数据结构·c++·算法
Proxy_ZZ016 小时前
从零实现LDPC比特翻转译码器:C语言实战与底层逻辑解析
c语言·算法