LeetCode----Find the Duplicate Number

给定一个包含n + 1个整数的数组,所有整数都在1到n之间,证明至少存在一个重复数字。假设只有一个重复数字,找出这个重复的数字。问题要求不修改数组,使用常数额外空间,且运行复杂度小于O(n^2)。解决方案包括使用弗洛伊德循环检测法和二分法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Find the Duplicate Number

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

Note:

  1. You must not modify the array (assume the array is read only).
  2. You must use only constant, O(1) extra space.
  3. Your runtime complexity should be less than O(n2).
  4. There is only one duplicate number in the array, but it could be repeated more than once.

分析:

给定一个数组,数组长度为n+1,里面的数都在1和n之间,这样,数组里肯定有一个数是出现两次的。假定只有一个数字重复了,找出那个重复数。

要求:数组不可修改,只读;只能使用常数个空间;算法复杂度要小于O(n^2),即不能暴力;假定那个重复数只有一个,但是可以出现许多次。

这题想了好久没想出来。查看了Discuss才明白。

第一种解法:

使用弗洛伊德循环检测法,记得昨天才写了一题叫Linked List Cycle,这题就是用该检测法写出来的。

思路是,根据数组元素的特点,将数组元素与下标一一映射起来。比如数组是13422,则0对应1,1对应3,2对应4等。这样,如果将这种映射当成链的话,可以顺着下标,下标对应的值,下标对应值的对应下标的值,一直遍历,链中有环,则最后一定会进行循环中,比如对于上面的数组,最后陷入了循环下标2对应值4,下标4对应值2,下标2对应值4,如此循环。

单单找到了循环还不够,我们还需要找到进入循环的那个数字,它才是要找的重复数。可以重新用一个下标为0的值从头开始映射,这样与前面循环中的指针相遇时,找到的就是循环的起点。


代码1:

class Solution(object):
    def findDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        slow, fast = 0, 0
        while True:
            slow = nums[slow]
            fast = nums[nums[fast]]
            if slow == fast:
                break
        # fast和slow一定在循环中某点相遇了,但是相遇的点不一定是刚刚进入循环的那个元素,
        # 需要从0开始继续寻找
        find = 0
        while find != slow:
            slow = nums[slow]
            find = nums[find]
        return find


第二种解法:

使用二分法。


代码:

class Solution(object):
    def findDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        l, r = 0, len(nums) - 1
        while l <= r:
            mid = l + (r - l) / 2
            cnt = 0
            for n in nums:
                if n <= mid:
                    cnt += 1
            if cnt > mid:
                r = mid - 1
            else:
                l = mid + 1
        return l

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值