LeetCode 287. Find the Duplicate Number

暴力解法

时间 O(nlog(n)),空间O(n),按题目中Note“只用O(1)的空间”,照理是过不了的,但是可能判题并没有卡空间复杂度,所以也能AC。

class Solution:
# 基本思路为,将第一次出现的数字
def findDuplicate(self, nums: List[int]) -> int:
s = set()
for i in nums:
a = i in s
if a == True:
return i
else:
s.add(i)

双指针判断环

时间O(n),空间O(1),思路十分巧妙,但是使用条件比较苛刻。根据题目给出的条件,恰好能用这种解法,这应该也是出题人推荐的解法。

题意分析:

  1. 输入的序列有n+1个数字,每个数字在1~n之间取,这为构成数字环创造了条件。
  2. 只有一个数字有重复,所以只可能构成一个环。

注:上面所说的环是指1->2->3->1

以样例1为例:[1,3,4,2,2]

0 1 2 3 4
1 3 4 2 2

如下图所示,其中2->4->2构成环,入环点为2

解题思路

由题意分析可知,每个样例都可以画成这样一张图,我们只需要找出图中的环,并找出入环点,即为所求的重复数字key,下面都用key表示所求的重复数字。

为什么必定存在环

以样例1为例,图中出现了5个点0-4,图中存在5根指针线,5个点5根线,必定存在环。

n个点,点的范围去0~n-1,n根线,必定存在环。(n-1根线是恰好无环的情况,自己画图可知)

找环的方法

设置一个慢指针slow,一个快指针fast。slow每次走一步,fast每次走两步,如果slow与fast能相遇,说明图中存在环,并且相遇点一定存在于环中。

为什么key一定为入环点?

有题意分析中的表可知,key的入度一定大于1,即不止一个点可以直接到key。而key一定存在于环中,所以key一定为入环点。样例1中3,4都可到达2,2的入度2,2为入环点,即为所求的key。

怎么找入环点key?

slow和fast相交的点记为相遇点P。

slow和fast从起点0到相遇点P运行步骤如下:

这个相遇点P与起点0到达入环点key的步数 差距为环L的整数倍,故设置slow2从起点0开始,每次走一步,slow从相遇点P开始,每次走一步,slow和slow2一定会相遇在入环点key。

我们可以有一个小小的证明,如下图

设起点0到达入环点key的步数为x,相遇点P到达入环点key的步数为y。

设slow指针走到相遇点P的步数为t,fast走到相遇点P的步数为2*t。

设走完环一圈的步数为L

2 * t - x + y = M * L(一)

t - x + y = N * L (二)

fast指针在环中走的步数2t-x,此时到达相遇点P,key->P->key步数为2t-x+y = M * L,正好为L的M倍,M为常数。(一)式

slow指针在环中走的步数t-x,此时到达相遇点P,key->P->key步数为t-x+y = N * L,正好为L的N倍,N为常数。(二)式

2倍(二)式 减 (一)式

y-x = (2N-M) * L

所以y与x的步数差距为L倍的环。

得证。

如何确定起点0一定会进入包含key的环?

假设存在不包含key的环,起点0在不包含key的环中绕圈。

0 a1 a2 a3 a4 a5 a6
b1 b2 b3 b4 b5 b6 b7

按题意不包含环,b[i]与b[j]一定不相等(i != j)

由于b1~b7从1开始,所以b[i]只能从a[j]中取(1<=i<=7,1<=j<=6)

从6个数字的集合a中取7个数字,所以假设不成立,必定存在相同数字b[k],即为key。

代码如下

class Solution:
def findDuplicate(self, nums: List[int]) -> int:
# 如果只有两个元素,第一个元素一定是重复元素
if len(nums) == 2:
return nums[0] # fast每次走两步,slow每次走一步,起始点可以为任意位置
fast = 0
slow = 0
# python没有do while,所以在循环外写了一遍
slow = nums[slow]
fast = nums[nums[fast]]
while slow != fast:
slow = nums[slow]
fast = nums[nums[fast]] # fast从起点每次走一步,一定会与slow相遇,此时slow可能在环中走了多倍的L步。
# L为环一圈的步数
fast = 0
while fast != slow:
slow = nums[slow]
fast = nums[fast]
return fast

LeetCode 287. Find the Duplicate Number (python 判断环,时间复杂度O(n))的更多相关文章

  1. [LeetCode] 287. Find the Duplicate Number(Floyd判圈算法)

    传送门 Description Given an array nums containing n + 1 integers where each integer is between 1 and n  ...

  2. [LeetCode] 287. Find the Duplicate Number 寻找重复数

    Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...

  3. LeetCode 287. Find the Duplicate Number (找到重复的数字)

    Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...

  4. [LeetCode] 287. Find the Duplicate Number 解题思路

    Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...

  5. LeetCode : 287. Find the Duplicate Number

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAACRAAAAMMCAYAAAAhQhmZAAAMFGlDQ1BJQ0MgUHJvZmlsZQAASImVlw ...

  6. leetcode 217. Contains Duplicate 287. Find the Duplicate Number 442. Find All Duplicates in an Array 448. Find All Numbers Disappeared in an Array

    后面3个题都是限制在1-n的,所有可以不先排序,可以利用巧方法做.最后两个题几乎一模一样. 217. Contains Duplicate class Solution { public: bool ...

  7. 287. Find the Duplicate Number hard

    287. Find the Duplicate Number   hard http://www.cnblogs.com/grandyang/p/4843654.html 51. N-Queens h ...

  8. 【LeetCode】287. Find the Duplicate Number 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 保存已经访问过的数字 链表成环 二分查找 日期 题目 ...

  9. 【LeetCode】287. Find the Duplicate Number

    Difficulty:medium  More:[目录]LeetCode Java实现 Description Given an array nums containing n + 1 integer ...

随机推荐

  1. day36 类的三大特性---封装以及Property特性

    目录 类的封装 如果真的要拿 类的property特性 setter & deleter 类属性用法 类与对象的绑定方法和非绑定方法 对象方法&类方法&静态方法 隐藏模块内的函 ...

  2. Crossing Rivers UVA - 12230 概率与期望

    题目大意:有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v.船会往返在河的两岸,人到达河岸时,船的位置是随机 ...

  3. eas之编辑表单元格

    --指定表列行单元不可编辑 // 锁定表格.行.列.单元 table.getStyleAttributes().getProtection().setLocked(true); row.getStyl ...

  4. iphone 事件冒泡规则

    今天碰到的一个比较烦人的问题是,在body上添加事件处理函数,发现在iphone上怎么也没办法触发事件,找了半天,发现iPhone处理冒泡事件的规则: 1.点击某个元素: 2.如果这个元素上没有处理该 ...

  5. [51Nod1486] 大大走格子 (dp+容斥)

    传送门 Description 有一个h行w列的棋盘,里面有一些格子是不能走的,现在要求从左上角走到右下角的方案数. Input 单组测试数据. 第一行有三个整数h, w, n(1 ≤ h, w ≤ ...

  6. Ubuntu Server下docker实战 01: 安装docker

    本系列文章主旨在于使用docker来搭建实际可用的基础服务,具体到每一步的操作和设置. 关于docker的原理.前世今生的内容,园子里已经有太多的文章了,此处就不再赘述. 要使用docker,当然第一 ...

  7. WinRTXamlToolkit在Win8.1实现统计图

    [注1]WinRTXamlToolkit是免费控件,不过很久不更新了,而且网上的资源很少.后来我发现syncfusion控件有免费的community版本,并且有详细文档,所以就转过去使用syncfu ...

  8. 洛谷 P2023 BZOJ 1798 [AHOI2009]维护序列

    题目描述 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一 ...

  9. 介绍一个不错的服务器综合监控工具脚本集aspersa

    http://blog.csdn.net/jackyrongvip/article/details/9217869

  10. I - Tunnel Warfare

    I - Tunnel Warfare HDU - 1540 思路:原来以为自己已经完全理解了线段树,现在发现其实还差一些火候,做题的时候太拘泥于格式,思路不是很能放开. #include<cst ...