作者: 负雪明烛
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软件安装管理:rpm与yum

    目录 1. rpm包的管理 1.1 介绍 1.2 rpm包的简单查询指令 1.3 rpm 包名的基本格式 1.4 rpm其它指令 1.5 卸载rpm包 1.6 安装rpm包 2. yum 2.1 说明 ...

  2. UE4之Slate:App默认窗口的创建流程

    UE4版本:4.24.3源码编译 Windows10 + VS2019开发环境 在先前分享的基础上,现在来梳理下App启动时默认窗口的创建流程,以及相关的类.对象之间的抽象层级: 纯C++工程配置 S ...

  3. Azkaban(一)【集群安装】

    目录 一.下载解压 二. 配置Mysql 三. 配置Azkaban Executor 四. 配置Azkaban WebServer 一.下载解压 1.下载地址:https://github.com/a ...

  4. 【leetcode】15. 3 Sum 双指针 压缩搜索空间

    Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i ...

  5. 【leetcode】633. Sum of Square Numbers(two-sum 变形)

    Given a non-negative integer c, decide whether there're two integers a and b such that a2 + b2 = c. ...

  6. Spring事务隔离级别和传播特性(转)

    相信每个人都被问过无数次Spring声明式事务的隔离级别和传播机制吧!今天我也来说说这两个东西. 加入一个小插曲,一天电话里有人问我声明式事务隔离级别有哪几种,我就回答了7种,他问我Spring的版本 ...

  7. Linux系统的文件复制移动删除与VIM编辑

    目录 今日内容概要 内容详细 复制文件 移动文件 删除文件 系统别名(针对 rm 改别名) vim编辑器 今日内容概要 复制文件 移动文件 删除文件 vim编辑器 内容详细 复制文件 # 命令: cp ...

  8. Python——连接数据库操作

    一.数据库基础用法 要先配置环境变量,然后cmd安装:pip install pymysql 1.连接MySQL,并创建wzg库 #引入decimal模块 import pymysql #连接数据库 ...

  9. MicroK8S 安装 修改IP 设置镜像加速 升级 卸载等

    系统要求: Ubuntu 20.04 LTS, 18.04 LTS or 16.04 LTS或其他支持snapd的操作系统 内存:4G+ 硬盘:20G+ 官方文档 安装microk8s sudo sn ...

  10. Mac终端学习C笔记

    Mac终端自带Clang,是一个C语言.C++.Objective-C语言的轻量级编译器,也可以进行c程序编译.具体Clang和gcc区别不做详细介绍. 终端自动vi编辑器. 终端命令笔记: gcc ...