数组去重进阶:一次遍历实现最多保留指定个数重复元素(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] = xk++);

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

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] = 1x=1 相等,跳过;有效区域不变,k=2

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

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

  6. 遍历第6个元素 3:k=4 ≥ 2,对比 nums[2] = 2x=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个元素(nums[0]=2),相等,跳过;

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

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

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

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

四、复杂度分析

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

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

相关推荐
星火开发设计3 小时前
二维数组:矩阵存储与多维数组的内存布局
开发语言·c++·人工智能·算法·矩阵·函数·知识
Fcy6484 小时前
⽤哈希表封装unordered_map和unordered_set(C++模拟实现)
数据结构·c++·散列表
丨康有为丨4 小时前
算法时间复杂度和空间复杂度
算法
HarmonLTS4 小时前
Python人工智能深度开发:技术体系、核心实践与工程化落地
开发语言·人工智能·python·算法
a程序小傲4 小时前
京东Java面试被问:RPC调用的熔断降级和自适应限流
java·开发语言·算法·面试·职场和发展·rpc·边缘计算
一分之二~4 小时前
二叉树--层序遍历(迭代和递归)
数据结构·c++·算法·leetcode
zl_vslam4 小时前
SLAM中的非线性优-3D图优化之绝对位姿SE3约束右扰动(十七)
人工智能·算法·计算机视觉·3d
Cestb0n4 小时前
某果app 加密校验算法逆向分析
python·算法·逆向安全
机器学习之心4 小时前
MATLAB基于近红外光谱检测的菠萝含水率预测(多种预处理+PLS)
人工智能·算法·matlab·近红外光谱检测