题目描述

给定一个包含 个整数的数组 ,其数字都在 之间(包括 ),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

说明

  • 不能更改原数组(假设数组是只读的)。
  • 只能使用额外的 的空间。
  • 时间复杂度小于
  • 数组中只有一个重复的数字,但它可能不止重复出现一次。

示例1

        输入:
[1,3,4,2,2]
输出:
2

示例2

        输入:
[3,1,3,4,2]
输出:
3

题解

二分法

根据抽屉原理,如果大小为 的抽屉里放了大于 个数,那么一定有一个抽屉里至少放了两个数。

那我们不妨统计一下数组中有多少个数满足 ,数量记为

如果 ,那么根据抽屉原理, 中一定有一个数出现了至少两次。

反之如果 ,那么说明满足 的数的数量是 ,而抽屉大小是 ,所以根据抽屉原理, 中一定有一个数出现了至少两次。

综上,可以采用二分法,不断缩小 的范围,最终得到这个出现至少两次的数的值。

时间复杂度

快慢指针法

因为 中数据范围是 ,所以 。那么接着用 作为下标来索引值,得到 。如果 已经出现过了 ,那么重复值已经找到了。否则的话 还没出现过的话,继续用 作为下标来索引,直到出现重复值。

可以发现按照这种方法索引下去,形成了一个链,也就是 。最终这条链末端一定会产生出一个环,那么环的入口一定就是那个重复的数。

举个例子,如下图所示,最终环产生在了 上面,而 又是链进入环的入口,所以重复的数就是

那么如何求链表中的环呢?这其实是一道面试经常会问到的经典题,标准解法就是用两个快慢指针

初始时两个指针指着链表头结点,然后同时移动。慢指针一次移动一个结点,快指针一次移动两个结点。当下一次快指针又和慢指针相遇时,停止移动。然后用第三个指针指着头结点,慢指针留在原地,两者同时移动,都是一次移动一个结点,直到相遇。这时两者指着的结点就是环的入口了。

大家可以用上面的例子自己画图演示一下,我下面严格证明一下为什么这样是对的。

假设如下图所示,链表中链的长度是 ,环的长度是

假设慢指针和快指针第一次相遇时,慢指针移动的距离是 ,那么快指针移动距离就是

可以列出等式 ,也就是两者距离差值一定是环长度的正整数 倍,同时 是使得 的最小正整数,即 。这时候慢指针离入口的距离是 ,也就是说,慢指针只需要再多绕 个环的长度,就能恰好和从头结点而来的指针相遇在入口处。

时间复杂度

扩展:

那有人可能会问了,那要是链最后回到了 ,不就没有链,只有环了吗?哪来的入口?这是对的,所以本题中限制了 数组里都是大于 的,如果范围是 的话,不能直接用数值但下标索引了,不然会出现下面这种情况,也就是 也在环里了。

其实这种情况我们只需要稍稍修改一下索引,让 不可能出现在环里就行了,也就是让 当作索引,如下图所示。最终重复的数只需要减去 就行了。

代码

二分法(c++)

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

快慢指针法(c++)

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

二分法(python)

        class Solution:def findDuplicate(self, nums):n = len(nums) - 1l, r = 1, nwhile l < r:m = l+(r-l)//2cnt = sum([x<=m for x in nums])if cnt > m:r = melse:l = m + 1return l

快慢指针法(python)

        class Solution:def findDuplicate(self, nums):slow, fast = 0, 0while True:slow = nums[slow]fast = nums[nums[fast]]if slow == fast:breakfind = 0while find != slow:slow = nums[slow]find = nums[find]return find

每日算法系列【LeetCode 287】寻找重复数相关推荐

  1. LeetCode 287. 寻找重复数

    给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 1: 输入: [1,3 ...

  2. LeetCode 287. 寻找重复数(BitMap)

    文章目录 1. 题目信息 2. 解题 2.1 BitMap 2.2 set去重 2.3 官方解题,快慢指针 1. 题目信息 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之 ...

  3. leetcode 287. 寻找重复数(Find the Duplicate Number)

    目录 题目描述: 示例 1: 示例 2: 解法: 题目描述: 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一 ...

  4. 重复次数最多的 子串_每日算法系列【LeetCode 424】替换后的最长重复字符

    题目描述 给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次.在执行上述操作后,找到包含重复字母的最长子串的长度. 示例1 输入: s = &quo ...

  5. 【LeetCode】【HOT】287. 寻找重复数(抽象环形链表)

    [LeetCode][HOT]287. 寻找重复数 文章目录 [LeetCode][HOT]287. 寻找重复数 package hot;public class Solution287 {publi ...

  6. 【手绘漫画】图解LeetCode之寻找重复数(LeetCode287题),抽屉原理

    文章目录 图解LeetCode刷题计划 1.写在前面 2.题目 3.正文 4.代码 5.讨论 图解LeetCode刷题计划 1.写在前面 手绘漫画系列正式上线!!!"图解LeetCode刷题 ...

  7. 287. 寻找重复数

    寻找重复数 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. class So ...

  8. 求栈中元素个数算法_每日算法系列【LeetCode 315】计算右侧小于当前元素的个数...

    题目描述 给定一个整数数组 nums ,按要求返回一个新数组 counts .数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量. 示例 ...

  9. 【leetcode】287. 寻找重复数

    题目链接:传送门 题目描述: 给定一个数组 nums 包含 n + 1 个整数,每个整数在 1 到 n 之间,包括 1 和 n.现在假设数组中存在一个重复的数字,找到该重复的数字. 注意 不能修改数组 ...

  10. 【leetcode】287 寻找重复数(查找)

    题目链接:https://leetcode-cn.com/problems/find-the-duplicate-number/ 题目描述 给定一个包含 n + 1 个整数的数组 nums,其数字都在 ...

最新文章

  1. Spring Boot 2.3.0 发布:支持Java14、打包Docker镜像、优雅关机配置...
  2. 教育部免费开放的2.4万门网课,都在这里!
  3. python流程控制-python简单流程控制
  4. MySQL如何存储Emoji表情,UTF-8和UTF-8MB4字符编码有何区别
  5. python查找字符串关键词_Python字符串查找基本操作案例解析
  6. 轴固定位置_3轴、3+2轴、5轴加工都有哪些区别?这篇文章给你整明白
  7. so文件成品评论【整理】
  8. getFilterFromRunTimeService - what is the trigger point of data load
  9. 什么是eager loading
  10. 苹果或推出不到两千元的iPhone!安卓手机不淡定了
  11. 速达启动时显示“对象名ACCSET无效“
  12. 思科路由器配置NAT地址转换
  13. 计算机安全设置超链接设置,word做超链接操作方法
  14. 价值几百元的EMlog仿大表哥资源网模版
  15. 计算机无法安装操作系统的原因,关于电脑无法安装IE浏览器的原因有哪些
  16. 算法导论-3.递归部分习题选
  17. swagger Could not resolve pointer: /definitions/Person does not exist in document
  18. Python 快速对比字符串的差异
  19. 小学计算机教研组总结,小学信息技术教研组工作总结范文
  20. 计算机恢复工具有哪些,电脑数据恢复软件选哪个?这三款恢复工具不容错过

热门文章

  1. 当我在linux图形界面终端输入startx,我在干什么
  2. cocos2d-x学习之旅(九): 2.2 盘古开天辟地,进入游戏世界
  3. 第一个冷门与真正的死亡之组
  4. Java 四种权限修饰符
  5. Html和Css学习笔记-html进阶-div与span
  6. 记账程序及GitHub学习记录2
  7. 进程+协程 计算操作
  8. 常用模块 re模块
  9. 简单的抽奖function
  10. 疯狂Java讲义(十一)---- 初始化块