[剑指offer]数组中重复的数字
题目描述:
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
我的解法(Set方法):
class Solution {
public int findRepeatNumber(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for(int num:nums){
if(set.contains(num)){
return num;
}else {
set.add(num);
}
}
return 0;
}
}
很一般吧。
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
我研究了下示例代码:
class Solution {
public int findRepeatNumber(int[] nums) {
int i = 0;
while(i < nums.length){
if(nums[i] == i){
i++;
continue;
}
if(nums[nums[i]] == nums[i]) return nums[i];
int tmp = nums[nums[i]];
nums[nums[i]] = nums[i];
nums[i] = tmp;
}
return -1;
}
}
然后我突然明白一个事实,我其实是用了一个通用解法,而示例代码实际上属于扣题了。
题目说了,在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。
于是它先将它排序。
初始:[2, 3, 1, 0, 2, 5, 3]
后续:
用通俗的话来说这个逻辑就是:
判断当前的数是否在它应该在的位置,例如2就应该在nums[2]上,
如果不在这个位置上,就再去判断它和它应该在的那个位置上的数是否相等,
不相等则交换,然后循环。
这个方法很眼熟,一下子叫不出名字,数据结构应该学过这个。
看到一个更简单的,算是完美利用了题目:
class Solution {
public int findRepeatNumber(int[] nums) {
int[] arr = new int[nums.length];
for(int i = 0; i < nums.length; i++){
arr[nums[i]]++;
if(arr[nums[i]] > 1) return nums[i];
}
return -1;
}
}
他直接就用标记的方法,例如你这个[2, 3, 1, 0, 2, 5, 3]
第一个是2,那就这样标记[0010000]
第二个是3,那就变成这样[0011000]
当最后出现2的时候,便可以输出三了。
很巧妙。
其他是他和第二个方法用的都是同一种方法,只是第三种方法的写法比较巧妙,所以两者之间的开销其实是基本一样的。