数组去重进阶:一次遍历实现最多保留指定个数重复元素(O(n)时间+O(1)空间)

在数组操作场景中,"去重"是高频需求,而基础去重(完全保留不重复元素)之外,更常见的是"最多保留k个重复元素"的进阶需求。本文将详细讲解一种高效的原地去重思路,仅需一次遍历即可完成,时间复杂度O(n)、空间复杂度O(1),且能灵活扩展至任意保留个数k。

一、问题背景

给定一个有序/无序数组(注:该算法对数组是否有序无要求,核心靠"有效区域"判断重复),要求原地删除多余的重复元素,使得每个元素最多出现2次(可扩展至k次),返回处理后数组的长度,且处理后的元素需保持原数组的相对顺序。

核心约束:不使用额外辅助数组,仅在原数组上操作,追求最优时间和空间效率。

二、核心思路

该算法的核心是**"原地筛选+有效区域标记"**,通过一个变量标记已处理完成的有效区域,再通过简单规则判断当前元素是否能加入有效区域,全程无冗余操作。

1. 核心变量定义

用变量 k 标记"已处理完成的有效区域"的长度,本质是一个尾指针:

  • 初始时 k=0,表示有效区域为空(无任何处理完成的元素);

  • 遍历结束后,数组前 k 个元素即为符合要求的结果,k 就是结果数组的长度。

2. 遍历判断规则

从左到右遍历数组的每个元素 x,判断 x 是否能加入有效区域,规则如下:

  • 情况1:k < 2(有效区域长度不足2)

  • 直接将 x 放入 nums[k] 位置,然后 k++ 扩大有效区域。原因是"最多保留2个重复元素",前2个元素无论是否重复,都不会违反规则,无需额外判断。

  • 情况2:k ≥ 2(有效区域长度≥2)

  • 对比 x 与有效区域的"倒数第2个元素"(即 nums[k-2]):

    • 若 x ≠ nums[k-2]:说明有效区域的最后两个元素中,没有和 x 连续重复超过2次的情况,可加入有效区域(nums[k] = x,k++);

    • 若 x = nums[k-2]:说明有效区域的最后两个元素已与 x 相同(如有效区域是 1,1,x 也是1),再加入会出现3个连续重复,直接跳过 x,k 保持不变。

3. 实例演示

以原数组 [1,1,1,2,2,3] 为例,一步步演示执行过程:

  1. 遍历第1个元素 1:k=0 < 2,放入 nums[0],k=1;有效区域:1

  2. 遍历第2个元素 1:k=1 < 2,放入 nums[1],k=2;有效区域:1,1

  3. 遍历第3个元素 1:k=2 ≥ 2,对比 nums[0] = 1,x=1 相等,跳过;有效区域不变,k=2

  4. 遍历第4个元素 2:k=2 ≥ 2,对比 nums[0] = 1,x=2 不相等,放入 nums[2],k=3;有效区域:1,1,2

  5. 遍历第5个元素 2:k=3 ≥ 2,对比 nums[1] = 1,x=2 不相等,放入 nums[3],k=4;有效区域:1,1,2,2

  6. 遍历第6个元素 3:k=4 ≥ 2,对比 nums[2] = 2,x=3 不相等,放入 nums[4],k=5;有效区域:1,1,2,2,3

遍历结束,结果数组为前5个元素 [1,1,2,2,3],长度 k=5,完全符合"最多保留2个重复元素"的要求。

三、扩展通用版:最多保留k个重复元素

基础版的思路可直接扩展至"最多保留任意k个重复元素",核心逻辑不变,仅需调整判断规则,通用性极强。

1. 通用核心逻辑

  • 前k个元素:直接保留,无需判断。因为"最多保留k个重复元素",前k个元素哪怕全重复,也不会违反规则;

  • 第k+1个元素及以后:判断当前元素 x 与"有效区域倒数第k个元素"(即 nums[k-1 - (k-1)] = nums[有效长度 - k])是否相同:

    • 不同:加入有效区域,有效长度(k)加1;

    • 相同:跳过,不加入有效区域。

2. 通用规则验证

以"最多保留3个重复元素"(k=3)为例,原数组 [2,2,2,2,3,3,3]:

  • 前3个2:直接保留,有效长度k=3,有效区域 2,2,2;

  • 第4个2:对比有效区域倒数第3个元素(nums0=2),相等,跳过;

  • 第1个3:对比 nums0=2,不相等,加入,k=4,有效区域 2,2,2,3;

  • 第2个3:对比 nums1=2,不相等,加入,k=5,有效区域 2,2,2,3,3;

  • 第3个3:对比 nums2=2,不相等,加入,k=6,有效区域 2,2,2,3,3,3;

结果符合"最多保留3个重复元素"的要求,验证了通用规则的正确性。

四、复杂度分析

  • 时间复杂度:O(n),其中n为数组长度。仅需从左到右遍历一次数组,每个元素的判断和操作都是O(1)级别的,无嵌套循环;

  • 空间复杂度:O(1)。仅使用一个变量k标记有效区域,无其他额外辅助空间,完全原地操作,符合空间最优要求。

相关推荐
yi0113 分钟前
DAY17: LeetCode 139|单词拆分:从“把单词删掉”到用 DP 记录合法切口
人工智能·笔记·python·算法·leetcode·动态规划
陈希瑞16 分钟前
LongCat-2.5-Preview 的web逆向能力实测
人工智能·算法·wasm
tangguofeng2 小时前
基于分治策略的循环赛日程表问题的思路讲解
算法
hnjzsyjyj2 小时前
洛谷 P1339:[USACO09OCT] Heat Wave G ← Bellman-Ford 算法
数据结构·bellman-ford 算法
起个名字费劲死了2 小时前
VisionMaster集成深度学习算法(基础狗)
人工智能·深度学习·算法
lengxuenong2 小时前
枚举例题分析
c++·算法·青少年编程
Navigator_Z2 小时前
LeetCode //C - 1269. Number of Ways to Stay in the Same Place After Some Steps
c语言·算法·leetcode
2601_965742222 小时前
短视频脚本创作方法分享:本地生活类账号的起步思路
大数据·人工智能·算法·ai·新媒体运营·生活
55873生态系统手记3 小时前
读完 55873 资产钱包的技术栈,我重新理解了 "合规钱包" 应该长什么样
算法·架构
旋生万物3 小时前
素数螺旋映射 $z_n=n^{1+i}$ 的角分布统计检验与零模型对比
大数据·前端·人工智能·算法·云原生·螺旋生成论·螺旋相位