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))
优势 直观,简单 更细致的控制 理论上可行 理论探讨 高效,简洁
劣势 较基础 略复杂 实际不可用 不符合要求 无显著劣势

应用示例

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

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

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



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

相关文章
|
9月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
245 0
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
1018 23
|
存储 监控 算法
关于员工上网监控系统中 PHP 关联数组算法的学术解析
在当代企业管理中,员工上网监控系统是维护信息安全和提升工作效率的关键工具。PHP 中的关联数组凭借其灵活的键值对存储方式,在记录员工网络活动、管理访问规则及分析上网行为等方面发挥重要作用。通过关联数组,系统能高效记录每位员工的上网历史,设定网站访问权限,并统计不同类型的网站访问频率,帮助企业洞察员工上网模式,发现潜在问题并采取相应管理措施,从而保障信息安全和提高工作效率。
263 7
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
400 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
470 4
|
算法
测试工程师的技能升级:LeetCode算法挑战与职业成长
这篇文章通过作者亲身体验LeetCode算法题的过程,探讨了测试工程师学习算法的重要性,并强调了算法技能对于测试职业成长的必要性。
443 1
测试工程师的技能升级:LeetCode算法挑战与职业成长
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
369 1
|
存储 算法 定位技术
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
这篇文章主要介绍了稀疏数组和队列的概念、应用实例以及如何使用数组模拟队列和环形队列的实现方法。
275 0
数据结构与算法学习二、稀疏数组与队列,数组模拟队列,模拟环形队列
|
C语言
【Amazon 面试题1】一个数组,里面得数出现的次数是偶数次,只有一个数出现的次数是奇数次,找出那个出现奇数次的数
本文介绍了解决Amazon面试题的一种方法,即在一个所有数字出现次数都是偶数,除了一个数字出现奇数次的数组中,利用异或运算的性质找出出现奇数次的数字,并提供了C语言实现的代码示例。
325 1

热门文章

最新文章