LeetCode 287. Find the Duplicate Number

LeetCode 287

最简单的想法就是先排序,然后遍历去检查。

    def findDuplicate2(self, nums: List[int]) -> int:
        nums.sort()
        for x in range(1, len(nums)):
            if nums[x] == nums[x-1]:
                return nums[x]

但是题目里面给出了两个限制:

  • You must not modify the array (assume the array is read only).
  • You must use only constant, O(1) extra space.

前面的排序就破坏了第一个条件。需要考虑其他的方法,如果我们把数组中的值想象成link,那么其实可以把数组理解为一种点直接的链表连接,重复的时候其实就是进入了循环。按照例子【1,3,4, 2, 2】,把数字看出链表的指针,那么就是 1 --》3–》2–》4–》2. 所以这个问题可以转换为在链表中找loop的起始点的问题。
那么我们就可以使用 Floyd’s Tortoise and Hare 算法,
这个算法实现比较简单,原理需要一点证明:

假设Loop长度是L = y+z,
在相遇的点,我们知道 x + n1L + y 是乌龟跑过的距离
x+n2
L+y 是兔子跑过的距离。又有兔子的速度是乌龟的两倍,那么
2x+2n1L+2y = x +n2L + y =>
x + 2n1L +y = n2L =>
x +2n1L + L = n2L + Z,
左右同时对L取mod,那么我们就有 x % L = z % L, 由于Z小于L,那么就有 z = x % L.
通过这个我们知道,如果从x点和meeting-point出发,最终他们会在loop起点的地方相遇。

    def findDuplicate(self, nums: List[int]) -> int:    
        fast = nums[nums[0]]
        slow = nums[0]
        while slow != fast:
            fast = nums[nums[fast]]
            slow = nums[slow]

        slow = 0
        while slow != fast:
            slow = nums[slow]
            fast = nums[fast]

        return fast

参考: https://cs.stackexchange.com/questions/10360/floyds-cycle-detection-algorithm-determining-the-starting-point-of-cycle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值