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] 区域内,首先让证明必定会有一个重复数,这不禁让博主想起了小学华罗庚奥数中的抽屉原理(又叫鸽巢原理),即如果有十个苹果放到九个抽屉里,如果苹果全在抽屉里,则至少有一个抽屉里有两个苹果,这里就不证明了,直接来做题吧。题目要求不能改变原数组,即不能给原数组排序,又不能用多余空间,那么哈希表神马的也就不用考虑了,又说时间小于 O(n2),也就不能用 brute force 的方法,那也就只能考虑用二分搜索法了,在区间 [1, n] 中搜索,首先求出中点 mid,然后遍历整个数组,统计所有小于等于 mid 的数的个数,如果个数小于等于 mid,则说明重复值在 [mid+1, n] 之间,反之,重复值应在 [1, mid-1] 之间,然后依次类推,直到搜索完成,此时的 low 就是我们要求的重复值,参见代码如下:

解法一:

class Solution {
public:
int findDuplicate(vector<int>& nums) {
int left = , right = nums.size();
while (left < right){
int mid = left + (right - left) / , cnt = ;
for (int num : nums) {
if (num <= mid) ++cnt;
}
if (cnt <= mid) left = mid + ;
else right = mid;
}
return right;
}
};

经过热心网友 waruzhi 的留言提醒还有一种 O(n) 的解法,并给了参考帖子,发现真是一种不错的解法,其核心思想快慢指针在之前的题目 Linked List Cycle II 中就有应用,这里应用的更加巧妙一些,由于题目限定了区间 [1,n],所以可以巧妙的利用坐标和数值之间相互转换,而由于重复数字的存在,那么一定会形成环,用快慢指针可以找到环并确定环的起始位置,确实是太巧妙了!

解法二:

class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = , fast = , t = ;
while (true) {
slow = nums[slow];
fast = nums[nums[fast]];
if (slow == fast) break;
}
while (true) {
slow = nums[slow];
t = nums[t];
if (slow == t) break;
}
return slow;
}
};

这道题还有一种位操作 Bit Manipulation 的解法,也十分的巧妙。思路是遍历每一位,然后对于 32 位中的每一个位 bit,都遍历一遍从0到 n-1,将0到 n-1 中的每一个数都跟 bit 相 ‘与’,若大于0,则计数器 cnt1 自增1。同时0到 n-1 也可以当作 nums 数组的下标,从而让 nums 数组中的每个数字也跟 bit 相 ‘与’,若大于0,则计数器 cnt2 自增1。最后比较若 cnt2 大于 cnt1,则将 bit 加入结果 res 中。这是为啥呢,因为对于每一位,0到 n-1 中所有数字中该位上的1的个数应该是固定的,如果 nums 数组中所有数字中该位上1的个数多了,说明重复数字在该位上一定是1,这样我们把重复数字的所有为1的位都累加起来,就可以还原出了这个重复数字,参见代码如下:

解法三:

class Solution {
public:
int findDuplicate(vector<int>& nums) {
int res = , n = nums.size();
for (int i = ; i < ; ++i) {
int bit = ( << i), cnt1 = , cnt2 = ;
for (int k = ; k < n; ++k) {
if ((k & bit) > ) ++cnt1;
if ((nums[k] & bit) > ) ++cnt2;
}
if (cnt2 > cnt1) res += bit;
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/287

类似题目:

First Missing Positive

Missing Number

Single Number

Find All Numbers Disappeared in an Array

Set Mismatch

Array Nesting

Linked List Cycle II

参考资料:

https://leetcode.com/problems/find-the-duplicate-number/

https://leetcode.com/problems/find-the-duplicate-number/discuss/72872/O(32*N)-solution-using-bit-manipulation-in-10-lines

https://leetcode.com/problems/find-the-duplicate-number/discuss/73045/Simple-C%2B%2B-code-with-O(1)-space-and-O(nlogn)-time-complexity

https://leetcode.com/problems/find-the-duplicate-number/discuss/72846/My-easy-understood-solution-with-O(n)-time-and-O(1)-space-without-modifying-the-array.-With-clear-explanation.

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] 287. Find the Duplicate Number 寻找重复数的更多相关文章

  1. 287 Find the Duplicate Number 寻找重复数

    一个长度为 n + 1 的整形数组,其中的数字都在 1 到 n 之间,包括 1 和 n ,可知至少有一个重复的数字存在.假设只有一个数字重复,找出这个重复的数字.注意:    不能更改数组内容(假设数 ...

  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] 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 解题思路

    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 : 287. Find the Duplicate Number

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAACRAAAAMMCAYAAAAhQhmZAAAMFGlDQ1BJQ0MgUHJvZmlsZQAASImVlw ...

  8. 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 ...

  9. 287. Find the Duplicate Number hard

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

随机推荐

  1. 【转载】什么是NVMe?

    什么是NVMe? [转载]什么是NVMe:http://storage.it168.com/a2018/0921/5045/000005045252.shtml NVMe是Non-Volatile M ...

  2. 【redis】redis异常-MISCONF Redis is configured to save RDB snapshots

    使用redis报错: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persis ...

  3. C#下的时间测试(用于计算方法执行时间)

    public class Timing { private TimeSpan m_StartTime; private TimeSpan duringTime; public Timing() //构 ...

  4. java进销存管理系统的设计与实现-springboot源码

    开发环境: Windows操作系统 开发工具:MyEclipse/Eclipse + JDK+ Tomcat + MySQL 数据库   项目简介:   系统前段页面采用jsp + JavaScrip ...

  5. Java多线程——查看线程堆栈信息

    Java多线程——查看线程堆栈信息 摘要:本文主要介绍了查看线程堆栈信息的方法. 使用Thread类的getAllStackTraces()方法 方法定义 可以看到getAllStackTraces( ...

  6. VMware——虚拟机的安装

    VMware——虚拟机的安装 摘要:本文主要记录了虚拟机的安装过程. 下载 可以去官网或者其他可靠站点下载虚拟机的安装包. 这次用的版本是:VMware-workstation-full-14.1.7 ...

  7. Python【day 10】函数进阶-动态函数

    形参小结 1.位置参数2.默认值参数3.动态参数 1.*args 位置参数的动态传参. 系统会自动的把所有的位置参数聚合成元组 2.**kwargs 关键字参数的动态传参. 系统会自动的把所有的关键字 ...

  8. Python基础17

    写出来的代码,若有部分不想运行,可注释掉. 看跑出来的结果,再加进来调试.

  9. 软工Alpha七天冲刺

    七天冲刺博客: 1.第一篇Scrum冲刺博客 2.第二篇Scrum冲刺博客 3.第三篇Scrum冲刺博客 4.第四篇Scrum冲刺博客 5.第五篇Scrum冲刺博客 6.第六篇Scrum冲刺博客 7. ...

  10. Google Analytics 学习笔记一 —— GA简介

    GA的原理 网页页面添加GA跟踪代码,以"一像素"传递信息给服务器 hit(交互) --> sessions(会话) --> user(用户) 竞品对比 Firebas ...