面试题 3 :数组中重复的数字
leetcode-cn 题目地址
difficulty:Easy
Tags:
- 哈希表
- 数组
1. 题目描述
题目一
在一个长度为 n 的数组里的所有都在 0 ~ n - 1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组{2,3,1,0,2,5,3}
,那么对应的输出是重复的数字 2 或者 3。
2. 解题思路
排序法
简单直接。
时间复杂度为:
public int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
for (int num : nums) {
if (num < 0 || num > nums.length - 1) {
return -1;
}
}
Arrays.sort(nums);
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] == nums[i + 1]) {
return nums[i];
}
}
return -1;
}
交换法
public int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
for (int num : nums) {
if (num < 0 || num > nums.length - 1) {
return -1;
}
}
int t;
// 交换法,期望使得每一个元素落在其 index 的位置上
for (int i = 0; i < nums.length; i++) {
while (i != nums[i]) {
if (nums[i] == nums[nums[i]]) {
return nums[i];
}
t = nums[i];
nums[i] = nums[t];
nums[t] = t;
}
}
return -1;
}
对于例子:{2,3,1,0,2,5,3}
。按照上述的算法进行分析:
- 绕过特判。
i = 0
时,0 == nums[0]
不成立,且第 0 个数字不等于第 2 个位置上的数字。交换法,数组变为{1,3,2,0,2,5,3}
- 第 0 个数字不为 0 ,继续交换和判断。数组变为
{3,1,2,0,2,5,3}
- 第 0 个数字不为 0 ,继续交换和判断,数组变为
{0,1,2,3,2,5,3}
- 第 0 个数字为 0,结束第 i 个数字的交换操作。(一共交换了 2 次。)
- 第 0 个数字不为 0 ,继续交换和判断。数组变为
- 后面的
{1,2,3}
位置正确,无需交换操作。 i = 4
时,4
不等于nums[4]
,nums[4]
等于2
,nums[2]
等于2
,即nums[i] == nums[[nums[i]]]
成立,即出现了重复的数字,返回该数字。
复杂度分析
- 时间复杂度
- 虽然有 2 重循环,但是有个很巧的规律,每个数找到其对应的位置,最多只需要 2 次。如果一个数字是不重复的,那么交换 2 次后就会归位,否则就会出现重复,返回改数字即可。
- 即复杂度为
O(n)
- 空间复杂度
O(1)
3. 总结
善于寻找规律,尤其要分析出 :每个数找到其对应的位置,最多只需要 2 次交换。
可以使用一个具体的例子去分析问题,寻找规律。