题目链接:287. 寻找重复数
题目:
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
提示:
- 1 <= n <= 105
- nums.length == n + 1
- 1 <= nums[i] <= n
- nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次
进阶:
如何证明 nums 中至少存在一个重复的数字?
你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?
思路和算法:
在这题中,有个关键点:一定存在一个重复整数,除了重复的那个数字可以出现两次或两次以上,其他数字都只能出现一次,且数字取值范围在[1, n]。所以,不妨有个大胆的想法,可不可以假设数组找重复元素的过程就像找链表是否存在环的过程???
我们对 nums 数组建图,每个位置 i 连一条 i→nums[i] 的边。由于存在的重复的数字 target,因此 target 这个位置一定有起码两条指向它的边,因此整张图一定存在环,且我们要找到的 target 就是这个环的入口,那么整个问题就等价于 142. 环形链表 II。
定义快慢指针,在一个循环中,慢指针走一步,快指针就走两步,这个循环的结束条件是找到重复元素,即快慢指针的值相等。但是上面的循环容易忽略一种情况:指针到不了位置0,因为范围为[1, n],所以无论快慢指针如何走都不能到达位置0。这时将慢指针置于位置0,再循环一遍,直到再次找到重复元素。因为两个循环后快慢指针的值都相等,所以返回快慢指针中的任何一个值都可以。
代码(c++):
//范围:[1, n]
//只能有一个重复的整数,并且重复整数一定存在
//重复的那个数字可以重复多次(两次以上包括两次)
//快慢指针
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int slow = 0, fast = 0;
//找到重复元素,但指针到不了位置0,因为范围为[1, n]
do {
slow = nums[slow]; //慢指针走一步
fast = nums[nums[fast]]; //快指针走两步
} while (slow != fast);
//将慢指针置为0,解决上面位置到不了0的问题
slow = 0;
while (slow != fast) {
slow = nums[slow];
fast = nums[fast];
}
//当快慢指针的值相等时,即找到了重复元素
//return fast; //返回slow或fast均可
return slow;
}
};
- 时间复杂度:O(n);
- 空间复杂度:O(1)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)