作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/find-the-duplicate-number/description/

题目描述

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

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,其中有个数字出现了2次,其余数字都出现了1次。求出现2次的数字是多少。

解题方法

保存已经访问过的数字

最简单的方法就是保存已经访问过哪些数字了,当我们再次访问到这个数字的时候,就直接把这个数字返回即可。这个做法使用了额外的空间。

C++代码如下:

class Solution {
public:
int findDuplicate(vector<int>& nums) {
unordered_set<int> visited;
for (int num : nums) {
if (visited.count(num))
return num;
visited.insert(num);
}
return -1;
}
};

链表成环

这个题简直是神题呀,本来很简单的题目,加了一堆条件,导致很难做,考的这个算法如果不去学习的话,是不可能会做的!

把这个题的数组抽象成了Linked List Cycle II题。道理是因为有重复数字,那么指针在移动的过程中一定会因为这个重复的数字反复的经过某一条路径。这个路径就是我们所谓的链表的环。如果抽象到这个层面就可以使用求环的算法解析了。

如图所示,两个指针同时从直线起点开始,这个圈是顺时针方向走的,即走的顺序是S-O-x-c-O-x。

如果SO线段的长度a足够长,而圈很小的时候,当两者相遇时,快指针多走的可能不止一圈。下面要证明如果相遇之后,慢指针回到原点继续走再相遇的点在O点。

  1. 首先要证明的是,两指针相遇时,慢指针还没有走完整个链表。

    • 当慢指针没走完一圈时,显然成立
    • 假设慢指针走完了一圈之后相遇,可以假定快指针在O的前一个位置,慢指针走一圈回到了O点,此时快指针走了两圈又回到了O的前一个位置,所以在慢指针走玩一圈之前就已经相遇。
  2. 快慢指针在x处第一次汇合,xo之间距离为x,假如快指针走了n圈,快指针走过的路程为a+x+n*(c + x),慢指针走过的路程为a+x,所以a+x+n*(c + x) = 2(a+x),所以a + x = n*(c + x),也就是SOx之间的距离等于n圈的长度,所以令快指针从起点开始一次一步,慢指针从x开始顺时针方向转,同时前进,则快指针走a时,慢指针走了n*(c+x) - x的长度,则必会在O处相遇!

这个题中,一定有重复的数字,因此最少也得两个数字,故不用进行只有一个数字和是否有环的判断。

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

C++解法如下:

class Solution {
public:
int findDuplicate(vector<int>& nums) {
const int N = nums.size();
int slow = nums[0], fast = nums[nums[0]];
while (fast != slow) {
fast = nums[nums[fast]];
slow = nums[slow];
}
fast = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return fast;
}
};

二分查找

这个题还可以使用二分查找。

思路是我们在[1,N]范围内先求出mid,再统计小于等于mid的数字个数count,如果count<=mid,说明重复数字在[mid+1,N]中,否则在[1,mid)中。可能不明白为什么这么移动左右指针,所以,我做一下说明:

我们统计小于等于mid的数字个数count,当nums在[1,mid]双闭区间中的数字不存在重复时,count应该恰好等于mid;当nums在[1,mid]双闭区间中的数字存在重复时,count应该>mid;当nums在[1,mid]双闭区间中的数字存在遗漏时,count应该<mid。所以,当我们发现count <= mid时,说明重复数字在[mid + 1, N]中,否则在[1,mid)中。

class Solution {
public:
int findDuplicate(vector<int>& nums) {
const int N = nums.size();
int l = 0, r = N;
// [l, r)
while (l < r) {
int mid = l + (r - l) / 2;
int count = 0;
for (int n : nums){
if (n <= mid) {
count ++;
}
}
if (count <= mid)
l = mid + 1;
else
r = mid;
}
return r;
}
};

参考资料:

http://blog.csdn.net/monkeyduck/article/details/50439840
https://blog.csdn.net/l294265421/article/details/50478818

日期

2018 年 3 月 12 日
2018 年 12 月 23 日 —— 周赛成绩新高
2019 年 1 月 11 日 —— 小光棍节?

【LeetCode】287. Find the Duplicate Number 解题报告(Python & C++)的更多相关文章

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

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

  2. LeetCode 287. Find the Duplicate Number (python 判断环,时间复杂度O(n))

    LeetCode 287. Find the Duplicate Number 暴力解法 时间 O(nlog(n)),空间O(n),按题目中Note"只用O(1)的空间",照理是过 ...

  3. 【LeetCode】652. Find Duplicate Subtrees 解题报告(Python)

    [LeetCode]652. Find Duplicate Subtrees 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博 ...

  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 (找到重复的数字)

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

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

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

  7. 【LeetCode】316. Remove Duplicate Letters 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  8. 【LeetCode】754. Reach a Number 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 数学 日期 题目地址:https://leetcod ...

  9. 【LeetCode】414. Third Maximum Number 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 替换最大值数组 使用set 三个变量 日期 题目地址 ...

随机推荐

  1. 7本Python必读的入门书籍,你看过吗?(附福利)

    Python入门书籍不用看太多,看一本就够.重要的是你要学习Python的哪个方向,或者说你对什么方向感兴趣,因为Python这门语言的应用领域比较广泛,比如说可以用来做数据分析.机器学习,也可以用来 ...

  2. 【模板】滑动窗口最值(单调队列)/洛谷P1886

    题目链接 https://www.luogu.com.cn/problem/P1886 题目大意 有一个长为 \(n\) 的序列 \(a\) ,以及一个大小为 \(k\) 的窗口.现在这个从左边开始向 ...

  3. C#筛选项联动,联动筛选

    protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { FillDep(); } // FillDG(); ...

  4. 4 — springboot中的jsr303检验

    1.导入依赖 <!--JSR303校验的依赖 --> <dependency> <groupId>org.springframework.boot</grou ...

  5. HTML 基本标签2

    HTML标题通过<h1>-<h6>标签定义(<h1>定义最大的标题,<h6>定义最小的标题) <html>用于定义HTML文档 HTML段落 ...

  6. tomcat在eclipse上发布,Perference下的server找不到解决办法

    help--->Install New software得到如下所示 下面work with选项的内容与你的eclipse版本有关 我的eclipse版本为eclipse-java-2019-0 ...

  7. Linux命令之用户权限管理

    1.创建组.删除组.修改组名.查看组 groupadd 组名 #添加用户组 groupdel 组名 #删除用户组 groupmod -n 新组名 原组名 #修改用户组名称 groups 用户名 #查看 ...

  8. When does compiler create default and copy constructors in C++?

    In C++, compiler creates a default constructor if we don't define our own constructor (See this). Co ...

  9. SpringBoot(1):初始SpringBoot

    一. SpringBoot 简介 1. SpringBoot介绍 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程.该框架使用了特 ...

  10. 使用RabbitMQ搭建MQTT服务

    由于近期公司需要搭建一套物联网采集环境,底层设备采用MQTT协议传输数据.服务器环境为linux,考虑到现有环境已经有RabbitMQ环境,Rabbit是基于AMQP协议开发的一套高效的消息传输队列. ...