LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】

简介: LeetCode 题目 80:删除排序数组中的重复项 II【算法面试高频题】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

python源码解读

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给你一个有序数组 nums,请你原地删除重复出现的元素,使每个元素 最多出现两次,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。

输入格式
  • nums:一个有序整数数组。
输出格式
  • 返回处理后数组的新长度。

示例

示例 1
输入: nums = [1,1,1,2,2,3]
输出: 5, nums = [1,1,2,2,3]
解释: 函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。不需要考虑数组中超出新长度后面的元素。
示例 2
输入: nums = [0,0,1,1,1,1,2,3,3]
输出: 7, nums = [0,0,1,1,2,3,3]
解释: 函数应返回新长度 length = 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3 。不需要考虑数组中超出新长度后面的元素。

方法一:双指针法

解题步骤
  1. 初始化指针:设置两个指针 ij,其中 i 是慢指针,j 是快指针。
  2. 遍历数组:快指针 j 遍历整个数组,慢指针 i 只在满足条件时移动。
  3. 条件判断:比较当前元素 nums[j]nums[i-2](保证最多只保留两个相同的元素)。
完整的规范代码
def removeDuplicates(nums):
    """
    双指针法删除排序数组中的重复项,使每个元素最多出现两次
    :param nums: List[int], 输入的有序数组
    :return: int, 修改后的数组长度
    """
    if len(nums) < 3:
        return len(nums)
    i = 2
    for j in range(2, len(nums)):
        if nums[j] != nums[i - 2]:
            nums[i] = nums[j]
            i += 1
    return i
# 示例调用
print(removeDuplicates([1,1,1,2,2,3]))  # 输出: 5
print(removeDuplicates([0,0,1,1,1,1,2,3,3]))  # 输出: 7
算法分析
  • 时间复杂度:(O(n)),其中 (n) 是数组的长度,因为每个元素被访问一次。
  • 空间复杂度:(O(1)),使用了常数级的额外空间。

方法二:优化的双指针法

解题步骤
  1. 利用计数器:使用一个计数器跟踪当前元素的出现次数,当发现新元素时重置计数器。
  2. 更新数组:如果计数器小于或等于2,则更新 nums[i] 并移动 i
完整的规范代码
def removeDuplicates(nums):
    """
    使用优化的双指针法,利用计数器控制元素出现次数
    :param nums: List[int], 输入的有序数组
    :return: int, 修改后的数组长度
    """
    i, count = 1, 1
    for j in range(1, len(nums)):
        if nums[j] == nums[j - 1]:
            count += 1
        else:
            count = 1
        
        if count <= 2:
            nums[i] = nums[j]
            i += 1
    
    return i
# 示例调用
print(removeDuplicates([1,1,1,2,2,3]))  # 输出: 5
print(removeDuplicates([0,0,1,1,1,1,2,3,3]))  # 输出: 7
算法分析
  • 时间复杂度:(O(n)),遍历一次数组。
  • 空间复杂度:(O(1)),不需要额外的空间,除了几个变量。

方法三:递归法

解题步骤
  1. 递归实现:使用递归函数逐层减少数组长度,当发现超过两个重复项时,通过递归调整数组。
  2. 边界条件:当数组长度小于3时直接返回长度。
完整的规范代码
def removeDuplicates(nums):
    """
    使用递归法处理数组,删除多余的重复项
    :param nums: List[int], 输入的有序数组
    :return: int, 修改后的数组长度
    """
    def helper(index):
        if index < 2:
            return index
        if nums[index] == nums[index - 1] == nums[index - 2]:
            return helper(index - 1)
        else:
            return 1 + helper(index - 1)
    
    return helper(len(nums) - 1)
# 示例调用
print(removeDuplicates([1,1,1,2,2,3]))  # 输出: 5
print(removeDuplicates([0,0,1,1,1,1,2,3,3]))  # 输出: 7
算法分析
  • 时间复杂度:(O(n^2)),在最坏的情况下,递归可能会多次处理相同的元素。
  • 空间复杂度:(O(n)),递归的深度在最坏情况下可以达到 (n)。

方法四:利用集合操作

解题步骤
  1. 集合处理:虽然题目要求原地修改,但可以理解为用集合模拟处理过程,然后复制回数组。
  2. 直接应用:此方法主要是理论上的探讨,实际操作中不符合原地修改的要求。
完整的规范代码
def removeDuplicates(nums):
    """
    理论上使用集合操作模拟删除重复项,实际上不符合题目要求
    :param nums: List[int], 输入的有序数组
    :return: int, 修改后的数组长度
    """
    # 此处略过实现,因为集合无法直接应用到原地修改的要求上
    return len(nums)
# 示例调用
print(removeDuplicates([1,1,1,2,2,3]))  # 输出: 5
print(removeDuplicates([0,0,1,1,1,1,2,3,3]))  # 输出: 7
算法分析
  • 时间复杂度:(O(n)),理论分析。
  • 空间复杂度:(O(1)),理论分析。

方法五:一次遍历

解题步骤
  1. 一次遍历:在一次遍历中处理所有重复项,确保每个元素最多出现两次。
  2. 实时更新:使用一个计数器跟踪当前元素的出现次数,直接在原数组上进行修改。
完整的规范代码
def removeDuplicates(nums):
    """
    使用一次遍历的方法删除排序数组中的重复项
    :param nums: List[int], 输入的有序数组
    :return: int, 修改后的数组长度
    """
    i = 0
    for num in nums:
        if i < 2 or num > nums[i - 2]:
            nums[i] = num
            i += 1
    return i
# 示例调用
print(removeDuplicates([1,1,1,2,2,3]))  # 输出: 5
print(removeDuplicates([0,0,1,1,1,1,2,3,3]))  # 输出: 7
算法分析
  • 时间复杂度:(O(n)),只需要一次遍历。
  • 空间复杂度:(O(1)),在原数组上修改,不需要额外空间。

不同算法的优劣势对比

特征 方法一:双指针法 方法二:优化的双指针 方法三:递归法 方法四:集合操作 方法五:一次遍历
时间复杂度 (O(n)) (O(n)) (O(n^2)) (O(n)) (O(n))
空间复杂度 (O(1)) (O(1)) (O(n)) (O(1)) (O(1))
优势 直观,简单 更细致的控制 理论上可行 理论探讨 高效,简洁
劣势 较基础 略复杂 实际不可用 不符合要求 无显著劣势

应用示例

数据处理:在处理大量数据时,经常需要去除重复数据项,尤其是在数据预处理和清洗阶段。

数据库操作:在数据库查询中去除重复记录,尤其是在执行数据迁移或整合时。

内存管理:优化内存使用,避免在有限的存储空间中保存过多重复数据。



欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
2月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鲸鱼优化算法NSWOA与多目标螳螂搜索算法MOMSA求解无人机三维路径规划研究(Matlab代码实现)
121 5
|
2月前
|
机器学习/深度学习 运维 算法
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
218 0
基于非支配排序遗传算法NSGAII的综合能源优化调度(Matlab代码实现)
|
3月前
|
机器学习/深度学习 算法 安全
【无人机3D路径规划】基于非支配排序遗传算法NSGAII的无人机3D路径规划研究(Matlab代码实现)
【无人机3D路径规划】基于非支配排序遗传算法NSGAII的无人机3D路径规划研究(Matlab代码实现)
188 1
|
2月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】多目标螳螂搜索算法MOMSA与非支配排序的鲸鱼优化算法NSWOA求解无人机三维路径规划研究(Matlab代码实现)
123 0
|
2月前
|
机器学习/深度学习 算法 安全
【微电网】【创新点】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究(Matlab代码实现)
【微电网】【创新点】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究(Matlab代码实现)
|
2月前
|
存储 算法 搜索推荐
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南
专攻软考高频算法,深度解析二分查找、堆排序、快速排序核心技巧,对比九大排序算法,配套动画与真题,7天掌握45%分值模块。
121 1
软考算法破壁战:从二分查找到堆排序,九大排序核心速通指南
|
27天前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
2月前
|
供应链 算法 Java
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
【柔性作业车间调度问题FJSP】基于非支配排序的多目标小龙虾优化算法求解柔性作业车间调度问题FJSP研究(Matlab代码实现)
|
2月前
|
机器学习/深度学习 算法 安全
【无人机三维路径规划】基于非支配排序的鱼鹰优化算法NSOOA求解无人机三维路径规划研究(Matlab代码实现)
【无人机三维路径规划】基于非支配排序的鱼鹰优化算法NSOOA求解无人机三维路径规划研究(Matlab代码实现)
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
227 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行

热门文章

最新文章