作者: 负雪明烛
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. linux中chage命令的基本使用

    在Linux中chage命令常用于设置系统用户的账户属性 Usage: chage [options] LOGIN Options: -d, --lastday LAST_DAY set date o ...

  2. mysql数据查询语言DQL

    DB(database)数据库:存储数据的'仓库',保存了一系列有组织的数据 DBMS(Database Management System)数据库管理系统:用于创建或管理DB SQL(Structu ...

  3. RB-Tree深度探索

    关联式容器就是通过key值来寻找value,这个和数据库很相像,为了提升查找效率,因此关联式容器底层大多数用红黑树或哈希表来实现. 红黑树是高度平衡的二叉树,它也被称为平衡二元搜索树. 如上所示,正常 ...

  4. 【STM32】使用SDIO进行SD卡读写,包含文件管理FatFs(六)-FatFs使用的思路介绍

    [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(一)-初步认识SD卡 [STM32]使用SDIO进行SD卡读写,包含文件管理FatFs(二)-了解SD总线,命令的相关介绍 [STM3 ...

  5. Oracle—全局变量

    Oracle全局变量 一.数据库程序包全局变量       在程序实现过程中,经常用遇到一些全局变量或常数.在程序开发过程中,往往会将该变量或常数存储于临时表或前台程序的全局变量中,由此带来运行效率降 ...

  6. linux下怎么查看某个命令属于哪个包

    # yum whatprovides */ip  或者 # yum provides */ip 即可

  7. vim使用配置(转)

    在终端下使用vim进行编辑时,默认情况下,编辑的界面上是没有行号的.语法高亮度显示.智能缩进等功能的. 为了更好的在vim下进行工作,需要手动配置一个配置文件: .vimrc 在启动vim时,当前用户 ...

  8. Mysql的行级锁

    我们首先需要知道的一个大前提是:mysql的锁是由具体的存储引擎实现的.所以像Mysql的默认引擎MyISAM和第三方插件引擎 InnoDB的锁实现机制是有区别的. Mysql有三种级别的锁定:表级锁 ...

  9. MyBatis(3):优化MyBatis配置文件

    一.连接数据库的配置单独放在一个properties文件中 1,创建一个database.properties driver=com.mysql.jdbc.Driver url=jdbc:mysql: ...

  10. 莫烦python教程学习笔记——保存模型、加载模型的两种方法

    # View more python tutorials on my Youtube and Youku channel!!! # Youtube video tutorial: https://ww ...