LeetCode:287. Find the Duplicate Number

LeetCode:287. 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.

Example 1:

Input: [1,3,4,2,2]
Output: 2
Example 2:

Input: [3,1,3,4,2]
Output: 3

找到数组中重复多次的那个数(唯一)。

思路一:元素值作索引

从位置0开始遍历数组,每次得到的元素值作为下一个遍历的元素,并且将遍历过的元素置为0,如果存在重复的元素值,那么这个位置的元素肯定会被多次访问,如果访问到的元素值为0则表明这个下标已经被访问过了,也就是要找的重复元素。

Python 实现代码

class Solution:
    def findDuplicate(self, nums):
        l = len(nums)
        index = 0
        while(nums[index] != 0):
            tmp = nums[index]
            nums[index] = 0
            index = tmp
            if (nums[tmp] == 0):
                return tmp
思路二:快慢指针

官方还提供了一个叫 Floyd's Tortoise and Hare (Cycle Detection) 的算法。核心思想是用两个指针检测数组访问次序中存在的环形链表。

Python 实现代码

class Solution:
    def findDuplicate(self, nums):
        # Find the intersection point of the two runners.
        tortoise = nums[0]
        hare = nums[0]
        while True:
            tortoise = nums[tortoise]
            hare = nums[nums[hare]]
            if tortoise == hare:
                break
        
        print(tortoise,hare)
        return tortoise
        # Find the "entrance" to the cycle.
        ptr1 = nums[0]
        ptr2 = tortoise
        while ptr1 != ptr2:
            ptr1 = nums[ptr1]
            ptr2 = nums[ptr2]
        
        return ptr1

x

同样是以当前元素值作为下次访问的下标,首先是快慢指针都从0位置出发,慢指针每次移动一个元素,快指针每次移动两个元素。因为存在重复元素,所以这种遍历方法肯定会存在一个环形遍历次序,两个指针也会最终访问重叠。可以按照下面的具体步骤找到环入口:

  1. 设:slow指针移动速度为1,fast指针移动速度为2;如果slow指针在链表的非环部分(也就上面图中的前面四个节点部分)移动的长度为a,slow指针在环内移动长度为b;
  2. 两指针相遇时候记为C点(不是环入口),slow指针移动距离为a+b,fast指针移动距离为2(a+b),可知两指针距离差a+b即为整数倍的环长
  3. 从head开始移动a的距离为入环点(环入口),由2可知从head开始移动a+(a+b)的距离也为入环点,即从C点开始继续移动距离a则可到达入环点
  4. 再将slow指针移动回head处,同时同速移动两个指针,相遇点即为入环点。

THE END.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值