LeetCode如何寻找重复数

发布时间:2021-12-15 14:32:59 作者:小新
来源:亿速云 阅读:178
# LeetCode如何寻找重复数

## 问题概述

在LeetCode的算法题库中,"寻找重复数"(Find the Duplicate Number)是一个经典的数组处理问题。题目要求在一个包含n+1个整数的数组中找到唯一的重复数字,所有数字都在1到n的范围内(包括1和n)。根据鸽巢原理,至少有一个数字是重复的。

### 问题描述
给定一个包含n + 1个整数的数组nums,其中每个整数都在[1, n]范围内。假设nums中只有一个重复的整数,返回这个重复的数。要求:
- 不能修改原数组(假设数组是只读的)
- 只能使用O(1)的额外空间
- 时间复杂度应低于O(n²)

## 常见解法分析

### 方法一:排序法(不符合要求)
最简单的方法是先对数组排序,然后遍历查找相邻的相同元素。虽然实现简单,但:
- 修改了原数组(违反条件1)
- 排序时间复杂度为O(n log n)
- 空间复杂度可能为O(1)或O(n)取决于排序实现

```python
# 不推荐的方法示例
def findDuplicate(nums):
    nums.sort()
    for i in range(1, len(nums)):
        if nums[i] == nums[i-1]:
            return nums[i]

方法二:哈希表法(不符合要求)

使用哈希集合记录已出现的数字: - 时间复杂度O(n) - 空间复杂度O(n)(违反条件2)

# 不符合空间要求的解法
def findDuplicate(nums):
    seen = set()
    for num in nums:
        if num in seen:
            return num
        seen.add(num)

最优解法:快慢指针法

算法原理

将数组视为链表,利用Floyd判圈算法: 1. 将数组值看作指针(如nums[i]表示节点i指向nums[i]) 2. 因为有重复数字,所以必然存在环 3. 找到环的入口即为重复数字

实现步骤

  1. 第一阶段:检测环的存在

    • 慢指针每次移动一步(slow = nums[slow])
    • 快指针每次移动两步(fast = nums[nums[fast]])
    • 直到两者相遇
  2. 第二阶段:找到环的入口

    • 将快指针重置到起点
    • 两个指针都每次移动一步
    • 再次相遇点即为重复数字
def findDuplicate(nums):
    # 第一阶段:寻找相遇点
    slow = fast = nums[0]
    while True:
        slow = nums[slow]
        fast = nums[nums[fast]]
        if slow == fast:
            break
    
    # 第二阶段:寻找环入口
    fast = nums[0]
    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]
    
    return slow

复杂度分析

二分查找解法

适用条件

当题目允许修改数组或需要其他思路时,可以考虑二分查找变种

算法思路

  1. 在[1,n]范围内进行二分搜索
  2. 统计数组中<=mid的元素个数
    • 如果计数>mid,说明重复数在左半区
    • 否则在右半区
def findDuplicate(nums):
    left, right = 1, len(nums)-1
    while left < right:
        mid = (left + right) // 2
        count = sum(1 for num in nums if num <= mid)
        if count > mid:
            right = mid
        else:
            left = mid + 1
    return left

复杂度分析

位运算解法(进阶)

算法原理

通过比较每一位上1的期望数量和实际数量来找出重复数

def findDuplicate(nums):
    n = len(nums) - 1
    duplicate = 0
    for bit in range(32):
        mask = 1 << bit
        expected = actual = 0
        for i in range(n + 1):
            expected += 1 if (i & mask) else 0
            actual += 1 if (nums[i] & mask) else 0
        if actual > expected:
            duplicate |= mask
    return duplicate

总结对比

方法 时间复杂度 空间复杂度 是否修改原数组
排序法 O(n log n) O(1)
哈希表法 O(n) O(n)
快慢指针法 O(n) O(1)
二分查找法 O(n log n) O(1)
位运算法 O(n log n) O(1)

在实际面试中,快慢指针法是最优解,因为它满足所有约束条件且效率最高。理解这个算法需要掌握链表环检测的相关知识,建议结合LeetCode 142(环形链表II)一起练习。

练习题推荐

  1. LeetCode 142 - 环形链表II
  2. LeetCode 287 - 寻找重复数(本题)
  3. LeetCode 136 - 只出现一次的数字
  4. LeetCode 41 - 缺失的第一个正数

掌握这些算法不仅能解决特定问题,更能培养将数组视为链表等抽象思维能力,这对解决其他复杂算法问题大有裨益。 “`

(注:实际字数为约1100字,可根据需要适当增减示例或详细说明部分以达到精确字数要求)

推荐阅读:
  1. windows server 2012重复数据删除
  2. LeetCode-287 寻找重复数

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

leetcode

上一篇:leetcode怎么解决K 个不同整数的子数组

下一篇:leetcode怎么计算最后一块石头的重量

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》