题目:找出数组中重复的数字。
描述:在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
题意很容易理解,就是在数组里面找到重复的数字,而且是任意一个,随着正常思路,就是遍历数组,然后用一个 set 来保存遍历过的元素,如果遍历元素的时候,发现 set 中已经存在的此元素,说明重复了,直接返回即可。
随着这个思路,很容易就写下以下的代码:
class Solution {
public int findRepeatNumber(int[] nums) {
int len = nums.length;
Set<Integer> numsSet = new HashSet();
for (int i = 0; i < len; i++) {
if (numsSet.contains(nums[i])) {
return nums[i];
}
numsSet.put(nums[i]);
}
return -1;
}
}
以上解法没啥毛病,时间复杂度 O(n),空间复杂度O(n)。
细心的同学肯定还注意到题干的一句话:数组 nums 里的所有数字都在 0~n-1 的范围内。
所以可以利用数组来替代 set 的操作:
class Solution {
public int findRepeatNumber(int[] nums) {
int len = nums.length;
int[] indexNums = new int[len];
for (int i = 0; i < len; i++) {
if (indexNums[nums[i]] != 0) {
return nums[i];
}
indexNums[nums[i]] = 1;
}
return -1;
}
}
以上解法,稍微思考一下应该不难理解。
时间复杂度 O(n),空间复杂度O(n)。
此时再来看看时间复杂度能否优化,发现好像并不行,只能遍历一遍才能得知重复,那空间复杂度呢?能否原地处理?
可以的!
根据数组 nums 里的所有数字都在 0~n-1 的范围内这句话的含义,我们可以得知数组内部的值不会大于数组长度,所以每个值都能找到对应的下标位置。
举个例子: 如果数组里面有 5 ,那么数组长度必定大于等于 6 ,所以一定存在 num[5] 。
如果我们把数组的所有元素搬迁到对应下标的位置,那么重复的数组必定会争抢相同下标的位置,根据这个条件就可以得知重复。
所以看下以下代码:
class Solution {
public int findRepeatNumber(int[] nums) {
int i = 0, len = nums.length;
while(i < len) {
//如果当前位置的值等于当前下标,那说明不用移动。
if(nums[i] == i) {
i++;
continue;
}
//如果当前位置的值,已经在对应下标的位置,存在,说明重复了,直接返回
if(nums[i] == nums[nums[i]]) {
return nums[i];
}
// 交换值,使得数组对应下标存储下标的值。
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
return -1;
}
}
时间复杂度 O(n),空间复杂度O(1)。
所以要好好看题目,题目有些条件其实就是给予我们启发的。
一道简单题
链接如下:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/