题目
原题链接
Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
给定一个包含个元素的数组,每个元素都在到之间(闭区间),证明至少一个元素重复,找出重复元素。
随想
这也是我遇到的一个面试题,当时想了很长时间,表现也不太好。
这个题和另外一个题:每个元素出现两次,有一个出现一次(Leetcode 136 Single Number)较为类似,有正好反过来的感觉。Leetcode136那道题异或位运算直接秒之。
证明一定有一个重复元素并不难,根据抽屉原理即可。
下面说如何找到它。
注意:并不要求到中的元素都要出现,也即这种输入也是合法的。
思路及代码
方法1 哈希表
用一个hash table去存储,然后查重复的元素。
平均时间复杂度是,空间复杂度是。
优点:
- 打破元素必须在到的约束,适用范围广
- 不修改输入参数
- 时间复杂度低
缺点:
- 空间复杂度高。
如果要求了空间复杂度是,那么该如何做呢?
方法2 排序
对原数组排序,排序后找相邻重复元素。
平均时间复杂度是,空间复杂度是。
优点:
- 打破元素必须在到的约束,适用范围广
- 空间复杂度低
缺点:
- 时间复杂度高
- 修改了输入参数
方法3 二分查找
对原数组进行二分查找,假如结果确定在在区间范围中,则记 ,统计的元素个数是否小于等于,如果是,说明结果在,否则说明结果在;重复上述过程。
最坏时间复杂度,空间复杂度。
优点:
- 空间复杂度低
- 不修改输入参数
缺点:
- 时间复杂度高
方法3可以看作是方法2的一个改进。
如果即要求空间复杂度空间复杂度,又要求时间复杂度,该如何实现呢?
代码
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int left = 1, right = nums.size(), mid, count;
while (left < right) {
mid = (left + right) / 2;
count = 0;
for (int i = 0; i < nums.size(); ++i) {
count += (nums[i] <= mid && nums[i] >= left);
}
if (count <= (mid - left + 1)) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
};
方法4 利用索引交换
把到都当作索引使用,例如把元素放到数组位置上。索引是没有元素能放对的,所以可以一直用索引中的元素交换它对应位置的元素,直到这两个元素相等,即找到了重复元素。
最坏时间复杂度,空间复杂度。因为每一次交换一定能放对一个元素,一共只有个元素,所以最坏只需要交换次。
(当时面试答得是这种方法,虽然后来手写代码写的是错的……emm)
优点:
- 空间复杂度低
- 时间复杂度低
缺点:
- 修改了输入参数
代码:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
while (nums[0] != nums[nums[0]]) {
swap(nums[0], nums[nums[0]]);
}
return nums[0];
}
};
方法5 链表判环
这个是非常推荐的一种方法!
把索引当作是地址,0当作是链表头,那么本质上这个题就是在找环入口,而且是在一定有环的情况下。
这样的话用快慢指针即可。类似Leetcode 142 Linked List Cycle II,不会链表找入口的话可以先看下这个题.
最坏时间复杂度,空间复杂度。
优点:
- 空间复杂度低
- 时间复杂度低
缺点:
暂无
代码:
class Solution {
public:
int findDuplicate(vector<int>& nums) {
int fast = 0, slow = 0;
do {
fast = nums[fast];
fast = nums[fast];
slow = nums[slow];
} while (fast != slow); // 这个do-while的写法非常精巧,可以仔细品一品
fast = 0;
while (fast != slow) {
fast = nums[fast];
slow = nums[slow];
}
return fast;
}
};
来源:CSDN
作者:叶萧不被占了吧
链接:https://blog.csdn.net/qq_32071849/article/details/103999517