数组去重进阶:一次遍历实现最多保留指定个数重复元素(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标记有效区域,无其他额外辅助空间,完全原地操作,符合空间最优要求。

相关推荐
仟濹1 小时前
算法打卡day2 (2026-02-07 周五) | 算法: DFS | 3_卡码网99_计数孤岛_DFS
算法·深度优先
驭渊的小故事1 小时前
简单模板笔记
数据结构·笔记·算法
YuTaoShao2 小时前
【LeetCode 每日一题】1653. 使字符串平衡的最少删除次数——(解法一)前后缀分解
算法·leetcode·职场和发展
VT.馒头2 小时前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
goodluckyaa2 小时前
LCR 006. 两数之和 II - 输入有序数组
算法
孤狼warrior2 小时前
YOLO目标检测 一千字解析yolo最初的摸样 模型下载,数据集构建及模型训练代码
人工智能·python·深度学习·算法·yolo·目标检测·目标跟踪
Σίσυφος19002 小时前
PCL法向量估计 之 RANSAC 平面估计法向量
算法·机器学习·平面
xhbaitxl2 小时前
算法学习day39-动态规划
学习·算法·动态规划
I_LPL2 小时前
day23 代码随想录算法训练营 回溯专题2
算法·hot100·回溯算法·求职面试
智者知已应修善业2 小时前
【洛谷P9975奶牛被病毒传染最少数量推导,导出多样例】2025-2-26
c语言·c++·经验分享·笔记·算法·推荐算法