掘金团队号上线,助你 Offer 临门! 点击 查看详情
一、题目描述
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例:
输入
[2, 3, 1, 0, 2, 5, 3]
输出
2 或 3
限制
2 <= n <= 100000
二、思路分析
我的思路
题目有点小问题,如果没有重复的返回啥?这里暂时返回-1;
- 最先思路肯定就是一个HashSet,然后不断的往里面塞和判断,这样就是空间换时间(直接的方法有很多:排序,循环去判断等)
- 后面想起了使用亦或来做,但是亦或其实不是这个场景的,想错了。(主要是印象中之前中好像有类似的题目是用亦或去做的)
- 最后想不出什么可以空间复杂度O(1) 时间复杂度还为O(n)的了,于是使用bitmap稍微降低一下空间复杂度(但是如果数字很多,重复数字又很靠前,那么申请bitmap的内存可能大于hashSet的内存)
最佳思路
长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内 (!!!! 我看漏了这最关键的信息,这样O(1)和O(n)就好找了) 也就是自身数组就可以当做那个bitmap,只要遇到不在自己索引位置的地方做交换和比较就行了。
三、AC 代码
我的写法:
public static int findRepeatNumber(int[] nums) {
byte[] bitmap = new byte[nums.length];
for (int num : nums) {
byte b = bitmap[num];
if (b == (byte) 1) {
return b;
} else {
bitmap[num] = (byte) 1;
}
}
return -1;
}
题解中清爽的写法
// 有意思的是,这个在跑的结果中显示比上面的内存占用还大 😂
public int findRepeatNumber2(int[] nums) {
for (int index = 0; index < nums.length; index++) {
int num = nums[index];
if (nums[num] == num && index != num) {
return num;
} else {
int tmp = nums[num];
nums[num] = num;
nums[index] = tmp;
}
}
return -1;
}
四、总结
除了考虑对bitmap了解,还需要能针对不同场景,对bitmap活学活用。