给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。
示例 1:
输入: [1,3,4,2,2]
输出: 2
示例 2:
输入: [3,1,3,4,2]
输出: 3
说明:
不能更改原数组(假设数组是只读的)。
只能使用额外的 O(1) 的空间。
时间复杂度小于 O(n2) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-duplicate-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解:
思路一:
- 遍历数组,使用Hashset存储遍历过的元素
- 当遍历当前元素时
- 如果set中包含,则为重复元素,返回当前元素
- 如果set中不包含, 则将当前元素加入set中
- 遍历完这边链表,都没发现重复时,return -1
- 时间复杂度 : O(N)
- 空间复杂度 : O(N)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/**
*
*
* 解法一:
* 遍历数组,使用set存放遍历过的值
* 遍历时,如果set中包含, 则返回 当前元素
* 如果不包含,加入set中
*
* 时间复杂度 : O(N)
* 空间复杂度 : O(N)
*
*/
public int findRepeatNumber1(int[] nums) {
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (set.contains(nums[i])) return nums[i];
set.add(nums[i]);
}
return -1;
}
|
思路二:
- 上述解题中发现,我们完全没有用到此条件:
- 所以,如果没有重复元素,则所有元素在排序后,都应该 == 下标index + 1
- 那么,空间复杂度O(1), 时间复杂度 O(N)的解法就来了
- 遍历数组,当 下标+1 != 当前元素 时,将当前元素交换至正确的位置
- 交换过程中
- 如果当前元素 == 正确位置上的元素, 则重复, return 当前元素
- 如果当前元素 != 正确位置上的元素, 则依次将元素交换至正确的位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/**
*
* 解法二:
* 上述题解发现,我们完全没有用到数组中这个条件:
* 长度为n, 且所有数字都在 [1, n]范围内
*
* 所以,如果没有重复元素, 则所有元素在排序后,都应该与 下标index一致
*
* 那么,空间复杂度O(1),时间复杂度O(n)的解法就来了
* 1,遍历数组, 当 下标 + 1!= 当前元素时,将当前元素交换至正确的位置。
* 2,交换过程中,如果 当前元素 == 正确位置上的元素, 则重复,return当前元素
* 3,交换过程中,如果 当前元素 != 正确位置上的元素, 则依次将正确位置上的元素,移动位置
*
*
* */
// 每个元素跟其下标对比 + 1,若不相同, 则交换元素至正确索引
//https://www.toutiao.com/i6761686631729594894
public static int findDuplicate1(int[] nums) {
for (int i = 0; i < nums.length; i++) {
// 这里需要注意,一定不要 先取出来 int num = nums[i]
// 因为 nums[i] 在每一轮 while循环,是变化的。所以每一轮都取
while (nums[i] != i + 1) {
if (nums[i] == nums[nums[i] - 1]) return nums[i];
swap(nums,i,nums[i] - 1);
}
}
return -1;
}
|
优化后的效果