LeetCode 第 287 号问题:寻找重复数,一道非常简单的数组遍历题,加上四个条件后感觉无从下手
今天分享的题目来源于 LeetCode 第 287 号问题:寻找重复数。
题目描述
给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
- 不能更改原数组(假设数组是只读的)。
- 只能使用额外的 O(1) 的空间。
- 时间复杂度小于 O(n2) 。
- 数组中只有一个重复的数字,但它可能不止重复出现一次。
题目解析
个人博客:www.cxyxiaowu.com
给定一个整形数组,数组的长度是 n + 1,数组里面存放的元素是区间 [1, n] 上的数,这个数组中有且仅有一个元素是重复的,题目让我们找出这个元素,并且这道题给了如下的限制:
- 不能改变数组
- 只能使用 O(1) 的空间
- 时间复杂度必须小于 O(n^2)
- 重复的元素可重复多次
首先不能改变数组导致无法排序,也无法用 index 和元素建立关系;
只能使用 O(1) 的空间意味着使用哈希表去计数这条路也走不通;
时间复杂度必须小于 O(n^2) 表示暴力求解也不行;
重复的元素可重复多次 这一条加上后,本来可以通过累加求和然后做差 sum(array) - sum(1,2,...,n) 的方式也变得不可行。
本来是非常简单的一道数组遍历的题目,加上了上面这四个条件后感觉有点无从下手。
我们说做题要借助算法,而不是空想,因此对于这道题也不例外,我们可以问自己这样一个问题,就是 “什么样的算法可以不使用额外的空间解决数组上面的搜索问题?”。
静静的思索一下。
你这时应该隐隐约约知道了,难道是 二分查找!
什么?二分查找法?!
二分查找法不是对有序数组才适用么?
这里澄清一个误区,二分法的使用 并不一定 需要在排序好的数组上面进行,不要让常见的例题限制了你的思路,二分法还有一个比较高级的用法叫做 按值二分。
这道题目交代的信息很少,我们只需要关注两个东西 - 数组,数组里的元素,利用二分我们需要去思考的是,我们要找符合条件的元素作为答案,那么比答案小的元素具有什么样的特质,比答案大的元素又具有什么样的特质?,结合题目给我们的例子来看看:
( 说明:下面的 <= 符号表明 小于或者等于。)
例1:
[1,3,4,2,2] 元素个数
<= 1 的元素:1 1
<= 2 的元素:1, 2, 2 3
<= 3 的元素:1, 2, 2, 3 4
<= 4 的元素:1, 2, 2, 3, 4 5
例2:
[3,1,3,4,2]
<= 1 的元素:1 1
<= 2 的元素:1, 2 2
<= 3 的元素:1, 2, 3, 3 4
<= 4 的元素:1, 2, 3, 3, 4 5
极端一点的例子 (必须保证数组的长度是 n + 1, 并且元素都在区间[1,n] 上, 有且只有一个重复)
[3,3,3,3,4]
<= 1 的元素: 0
<= 2 的元素: 0
<= 3 的元素:3, 3, 3, 3 4
<= 4 的元素:3, 3, 3, 3, 4 5
看完上面几个例子,相信你明白了一个事实:
“如果选中的数 小于 我们要找的答案,那么整个数组中小于或等于该数的元素个数必然小于或等于该元素的值;
如果选中的数 大于或等于 我们要找的答案,那么整个数组中小于或等于该数的元素个数必然 大于 该元素的值”
而且你可以看到,我们要找的答案其实就处于一个分界点的位置,寻找边界值,这又是二分的一个应用,而且题目已经告诉我们数组里面的值只可能在 [1, n] 之间,这么一来,思路就是在 [1, n] 区间上做二分,然后按我们之前提到的逻辑去做分割。整个解法的时间复杂度是 O(nlogn),也是满足题目要求的。
上面的解法不是最优的,但是个人觉得是根据现有的知识比较容易想到的。
另外一种 O(n) 的解法借鉴快慢指针找交点的思想,算法非常的巧妙,也非常的有趣,但不太容易想到,这里把代码放上。
代码实现一
//二分查找
class Solution {
public int findDuplicate(int[] nums) {
int len = nums.length;
int start = 1;
int end = len - 1;
while (start < end) {
int mid = start + (end - start) / 2;
int counter = 0;
for (int num:nums) {
if (num <= mid) {
counter++;
}
}
if (counter > mid) {
end = mid;
} else {
start = mid + 1;
}
}
return start;
}
}
代码实现二
//快慢指针
public int findDuplicate(int[] nums) {
int fast = nums[nums[0]];
int slow = nums[0];
while (fast != slow) {
fast = nums[nums[fast]];
slow = nums[slow];
}
slow = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return slow;
}
❤️ 看完三件事:
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个忙:
- 点赞,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓 -_-)
- 关注我和专栏,让我们成为长期关系
- 关注公众号「五分钟学算法」,第一时间阅读最新的算法文章,公众号后台回复 1024 送你 50 本 算法编程书籍。
LeetCode 第 287 号问题:寻找重复数,一道非常简单的数组遍历题,加上四个条件后感觉无从下手的更多相关文章
- [LeetCode] Find the Duplicate Number 寻找重复数
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), pro ...
- LeetCode:寻找重复数【287】
LeetCode:寻找重复数[287] 题目描述 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数 ...
- Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number)
Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number) 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 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 ...
- 【Leetcode】287. 寻找重复数(数组模拟链表的快慢指针法)
寻找重复数 根据题意,数组中的数字都在1~n之间,所以数字的范围是小于数组的范围的,数组的元素可以和数组的索引相联系. 例如:nums[0] = 1 即可以将nums[0]作为索引 通过nums[0] ...
- Java实现 LeetCode 287 寻找重复数
287. 寻找重复数 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 ...
- 287. 寻找重复数 Java解法
287. 寻找重复数 这题的难点就在于下面的说明了,我们先不管下面的那些说明的要求,用常规的解法来解答下上的题目. 排序思想解法 先把原来的数组进行排序,然后逐个遍历,一旦发现后一个元素和当前的元素相 ...
- Leetcode之二分法专题-744. 寻找比目标字母大的最小字母(Find Smallest Letter Greater Than Target)
Leetcode之二分法专题-744. 寻找比目标字母大的最小字母(Find Smallest Letter Greater Than Target) 给定一个只包含小写字母的有序数组letters ...
- Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II)
Leetcode之二分法专题-154. 寻找旋转排序数组中的最小值 II(Find Minimum in Rotated Sorted Array II) 假设按照升序排序的数组在预先未知的某个点上进 ...
随机推荐
- Java机械分词
这是我们做的一个小作业,不多说 直接附上我写的代码: public void Zheng() { try { BufferedReader bre = null; //String file = &q ...
- HTML+CSS+JavaScript实现2048小游戏
相信很多人都玩过2048小游戏,规则易懂.操作简单,我曾经也“痴迷”于它,不到2048不罢休,最高成绩合成了4096,现在正好拿它来练练手. 我对于2048的实现,除了使用了现有2048小游戏的配色, ...
- VG有空间,创建逻辑卷
1.查看VG空间 [root@CNSZ22PL2787 ~]# vgs VG #PV #LV #SN Attr VSize VFree VolGroup00 1 7 0 wz--n- 1.63t 1. ...
- 遇到XML-GB2312网页编码的处理方法
报的错误:encoding error : input conversion failed due to input error, bytes I/O error : encoder error 1 ...
- 数据库高级:SQL-CREATE-TABLE语句
作者:松软科技(www.sysoft.net.cn) 发布时间:2019/3/17 9:34:51 CREATE TABLE 语句 CREATE TABLE 语句用于创建数据库中的表. SQL CRE ...
- jmeter 命令压测生成报告
1.本地复制到远程 scp -r local_folder remote_username@remote_ip:remote_folder 或者 scp -r local_folder remote_ ...
- 【教程】Bluestacks0.7.9.860以上版3分钟教你摇一摇
Bluestacks 0.7.9.860 版或以上 , 打开文件夹Win 7 用户 : C:\ProgramData\Bluestacks\UserData\InputMapperWin XP 用户 ...
- C#基础知识总结(三)--反射
如何在C#.NET开发中使用反射. 首先,我新建一个普通的类库项目.在该项目的测试类中,定义好 属性.静态方法.实例方法.无参方法等... 代码如下: using System; using Syst ...
- vim编辑python脚本时Tab补全
所属分类:成长之路 使用Linux写python脚本的时候,初期最痛苦的是什么?当然是各种库的不熟悉,知道了库,里面的方法还要挨个看,挨个记. 所以这时候,很多小伙伴使用了ipython,最强大的功能 ...
- 代码审计之XSS及修复
xss在平时的测试中,还是比较重要的,如果存在储存型xss,就可以做很多事情了,打cookie,添加管理员等等很多操作. 以下所有代码都是我自己写的,可能有不美观,代码错误等等问题,希望大家可以指正. ...