287. 寻找重复数
给定一个包含 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) 。
数组中只有一个重复的数字,但它可能不止重复出现一次。
解题思路
一开始直接用了哈希的思想,遍历一遍数组,边遍历边使用Map标记,当有相同的时候就退出。这个方法时间复杂度O(n),空间复杂度也时O(n)虽然空间复杂度不符合题目要求,但是提交了也通过了。
class Solution {
public int findDuplicate(int[] nums) {
Map<Integer, Integer> mp=new HashMap<Integer, Integer>();
int c;
for(int i=0;i<nums.length;i++) {
if(mp.containsKey(nums[i])) {
c=nums[i];
break;
}
mp.put(nums[i], 1);
}
return c;
}
}
既然额外的空间复杂度为O(1),那么可以用双重for循环跑,这样的时间复杂度就是O(n2)了。
class Solution {
public int findDuplicate(int[] nums) {
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(nums[i]==nums[j]){
return nums[i];
}
}
}
return -1;
}
}
那么还有没有什么方法可一降低他的时间复杂度呢,这时候想到了快慢指针这个东西。
那么首先快慢指针是什么呢?
快慢指针中的快慢指的是移动的步长,即每次向前移动速度的快慢。例如可以让快指针每次沿链表向前移动2,慢指针每次向前移动1次。
快慢指针主要应用于求链表是否有环,如果有环那么快慢指针迟早会相遇。在这个题目中可以每次令快指针fast=nums[nums[fast]],慢指针slow=nums[slow],那么他们一定会相遇。快慢指针的时间复制度为O(n),由于只定义了fast和slow两个常量空间复杂度为O(1)。
代码如下:
class Solution {
public int findDuplicate(int[] nums) {
int fast=0,slow=0;
fast=nums[nums[fast]];
slow = nums[slow];
while(fast!=slow) {
fast=nums[nums[fast]];
slow = nums[slow];
}
slow = 0;
while(fast!=slow) {
fast=nums[fast];
slow=nums[slow];
}
return slow;
}
}