leetcode: Find the Duplicate Number

Question

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.

以下步骤循环进行直到指针 low l o w high h i g h 要大:
1.找到 low l o w high h i g h 的中间点 mid=low+(highlow)/2 m i d = l o w + ( h i g h − l o w ) / 2 ,将待搜索待搜索区域划为两段 [low,mid],[mid,high] [ l o w , m i d ] , [ m i d , h i g h ] 。对数值落在其中一个区域的元素进行计数,如 [low,mid] [ l o w , m i d ] ,若落在该区域的元素数量大于该区域的容量 midlow m i d − l o w 则说明重复元素落在该区域,否则落在另一区域。
2.依照新的待搜索区域更新 low l o w high h i g h ,以及 mid m i d
代码如下:

class Solution:
    def findDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        low,high = 0,len(nums)-1
        while low<=high:
            count = 0
            mid = low+(high-low)//2
            for n in nums:
                #这里实际是计的落在[0,mid]区域内元素的数量
                #即每次都搜索整个数组,将整个数组划分为[0,mid],[mid,high]
                #low只是作为寻找mid的辅助指针
                if n<=mid:
                    count += 1
            if count<=mid:
                low = mid+1
            else:
                high = mid-1
        return low

Solution Two–龟兔赛跑

先放代码

class Solution:
    def findDuplicate(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        slow,fast = nums[0],nums[nums[0]]
        while fast!=slow:
            slow = nums[slow]
            fast = nums[nums[fast]]

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

这个算法的思想借鉴于leetcode的题目:Linked List Cycle II。
将数组看成一个链表,数组元素的序号视为指向链表元素的指针,数组元素的值视为链表元素(值相同则视为同一链表元素)。由于数组中存在重复元素,则数组对应的链表一定存在环(有多个指针指向同一元素,该元素也是环的起点)。
第一个while循环用来寻找环是否存在,本题已经能确定一定有环,则用来寻找cross point X。
第二个while循环中,将其中一个指针指回head,该指针走过距离H刚好等于另一指针从X走外圈到E的距离,就可以找到E(即重复元素)。
证明:
第一个while中,
fast指针走过的距离是:H+L(环的长度)+D
slow指针走过的距离:H+D
又有每次slow走一步,fast都会走两步:2H+2D = H+D+L, 即 H+D = L
那么fast指向head之后一次也只走一步了,它走过H距离的同时, slow刚好走过L-D, 二者在E点汇合。

Consider the following linked list, where E is the cylce entry and X, the crossing point of fast and slow.
H: distance from head to cycle entry E
D: distance from E to X
L: cycle length
          __
         /   \
head_____H______E     \
        \     /
         X_____/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值