Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、题目描述
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例
示例1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3
限制
- 2 <= n <= 100000
难度:简单
此题为简单题,兄弟们可以重拳出击,没错,就是你想到的那种方法,简单粗暴!
二、思路分析
众所周知,力扣上,简单题是真简单,中等题有些困难,困难题看不懂答案。
题目解析
-
找出给定数组中重复的数字,根据题目描述,数组 nums 的长度为 n,且其中的所有数字都在 [0,1] 区间,其中含有一个或多个重复数字,且重复次数不限,找到任意一个重复数字返回。
-
容器判重:题目理解后,首先想到的就是遍历数组,并在遍历过程中使用容器记录每个出现的数字,如果容器中已经存在当前数字,则说明该数字重复,返回当前数字即可。
-
数组判重:容器记录并判断重复可以用于任意寻找重复数字的情况,而当前题目还可以使用数组判重的方式
- 题目数组中所有数字都在 [0,1] 区间内,也就是在长度为 n 的数组索引范围内,因此可以使用长度为 n 的数组记录出现的数字,如果数字存在则对应索引位置赋值为 1;如果已经为 1,说明索引对应数字重复。
-
数组原地判重:元素数组和记录数组长度都是 n,因此可以考虑合二为一,在原数组上遍历同事进行操作记录,实现原地判重
- 数组中数字均在 [0,1] 区间,可以在遍历到数字后,为其对应索引位置上的数字 +n 或 -n 作为标记,
- 在遍历操作之前判断数字是否仍然在 [0,1] 区间内,如果不存在说明索引对应数字重复,返回索引值,
- 由于遍历时不确定数字是否有变动,需要在操作时对所有数字进行 %n 后进行索引操作。
三、AC 代码
使用容器判重
- 使用set容器存储元素并判重,set为不重复集合,添加元素时如果已经存在返回false,否则返回true
public int findRepeatNumber(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
for(int i = 0; i < nums.length; i++){
//if(set.contains(nums[i])) return nums[i];
if(!set.add(nums[i])) return nums[i];
}
return -1;
}
数组原地判重
- 使用 +n 或者 -n 来标识对应位置标注为已出现过,因为所有元素都在[0,1] 区间,且可以保持原有元素,本方法使用 +n 操作,并使用 >= n 判断
public int findRepeatNumber(int[] nums) {
int n = nums.length;
for(int i = 0; i < n; i++){
int cur = nums[i] % n;
if(nums[cur] >= n) return cur;
nums[cur] += n;
}
return -1;
}
四、总结
知识点
- set 容器用于存储不重复元素,如果已经存在,则加入时返回 false,效率高
- 对于数组中元素不超过数组索引范围的,可以使用定长数组来代替容器,甚至可以直接在原数组上操作,如果允许对原数组修改的话。
最后
阳春三月,算法刷起来!LeetCode 剑指 Offer。
简单题,不需要考虑太多,开干就是了。