Leetcode——287. 寻找重复数
首先很简单的做法即用哈希表记录数字出现的次数,最后循环哈希表输出value值不为1的key值。
class Solution {
public:int findDuplicate(vector<int>& nums) {unordered_map<int, int> map;for(int x : nums){map[x]++;}for(auto& entry : map){if(entry.second != 1){return entry.first;}}return 0;}
};
接着就是考虑高效算法,这里可以将数组看作一个链表,这个思想确实很巧妙,但也很难考虑到。
当看作是一个链表时,其任务就是找链表的环了。
如果允许修改原数组,即我们可以标记负号表示已经来过。
class Solution {
public:int findDuplicate(vector<int>& nums) {int idx = 0;while(nums[idx] > 0){int old = idx;idx = nums[old];nums[old] = -nums[old];}return idx;}
};
如果不允许修改原数组,则用快慢指针找环即可。
class Solution {
public:int findDuplicate(vector<int>& nums) {int slow = 0;int fast = 0;do{slow = nums[slow];fast = nums[nums[fast]];}while(slow != fast);fast = 0;while (fast != slow) {fast = nums[fast];slow = nums[slow];}return slow;}
};
注意,双指针解法需要从同一位置出发。
当然,此题也可用二分查找求解。
由于我们要找的数范围为[1, n],所以取mid,遍历数组,如果<=mid的数字个数小于count,则说明[1, mid]范围上有数字少了,所以重复数字在[mid, n]区间。
class Solution {
public:int findDuplicate(vector<int>& nums) {int len = nums.size();int left = 0, right = len - 1;while(left < right){int mid = left + ((right - left) >> 1);int count = 0;for(int x : nums){if(x <= mid){count++;}}if(count > mid){right = mid;}else{left = mid + 1;}}return left;}
};