题目描述
要求:
- 时间复杂度小于O(n^2)
- 空间复杂度为O(1),set就别想了
- 不修改数组 nums
方法1: 快慢指针floyd判圈算法,不修改原数组
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0, fast = 0;
do {
slow = nums[slow];
fast = nums[nums[fast]];
} while (slow != fast);
// 相遇了
// 找入口
int cur = 0;
while (cur != slow) {
slow = nums[slow];
cur = nums[cur];
}
return cur;
//这么写上来就进不了循环
// while (slow != fast) {
// slow = nums[slow];
// fast = nums[nums[fast]];
// }
// return nums[cur]; //错误写法,相当于return node.next
}
}
方法2:原地hash,但是修改了nums
- 这个题里的归位是指
nums[index] = index + 1 - 如果数组中有重复数字,那么在归位的过程中会遇到重复,因为有相同的数字来抢占对应的index
- 比如:
[1,2,3,4,5,5], 两个数字5如果都要归位的话,他们对应的index都是4,当一个5先归位到index=4的格子,另一个5在归位时发现index = 4上已经有一个5了,说明有重复的两个5。
- 比如:
- 这种原地哈希只适用于数字范围和数组大小有限定关系。像
[1,2,554,452,9,452]就不能用了。
class Solution {
public int findDuplicate(int[] nums) {
for (int i = 0; i < nums.length; i++) {
//如果没有归位
while (nums[i] != i + 1) {
//当前数字对应的正确的index上已经被相同的数字抢占,说明遇到重复数
if (nums[i] == nums[nums[i] - 1]) {
return nums[i];
}
swap(nums, i, nums[i] - 1);
}
}
return -1;
}
public void swap(int[] nums, int m, int n) {
int tmp = nums[m];
nums[m] = nums[n];
nums[n] = tmp;
}
}