287. 寻找重复数 - 力扣(LeetCode)

题目描述

给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。

示例 1:

输入: [1,3,4,2,2]
输出: 2

示例 2:

输入: [3,1,3,4,2]
输出: 3

说明:

  1. 不能更改原数组(假设数组是只读的)。
  2. 只能使用额外的 O(1) 的空间。
  3. 时间复杂度小于 O(n2) 。
  4. 数组中只有一个重复的数字,但它可能不止重复出现一次。

题解1

如果没有数组只是只读的,空间只能是O(1)的限制,常用的方法有排序,然后判断相邻元素是否存在相等的(违背了数组是只读的原则)。或者用一个哈希表记录出现的数字,再次出现时,表明是重复元素(违背了空间只能是只读的原则)。除此之外,我没有想到空间为O(1)或数组只读的算法。

参考题解,二分查找法。

这个二分查找法不同于传统的二分查找,它的时间复杂度为 O ( n l o g n ) O(nlogn) ,因为每次二分前,需扫描一次数组,统计不大于当前猜测值元素mid的元素的个数,如果个数大于猜测元素,表明重复元素位于[big, mid]区间,否则,重复元素位于[mid + 1, end]区间。

代码1

/*
二分法查找
时间复杂度为:O(nlogn)
空间复杂度为:O(1)
*/

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int len = nums.size(), cnt = 0;
        int left = 1, right = len - 1, mid = left + (right - left) >> 1;
        while(left < right){
            cnt = 0;
            mid = left + (right - left) / 2;//mid为猜测值
 
            for(auto num:nums){
                if(num <= mid){//统计不大于mid的数的数量
                    ++cnt;
                }
            }

            if(cnt > mid){//重复的数出现在[left, mid]
                right = mid;
            }
            else{//重复的数出现在[mid + 1, right]
                left = mid + 1;
            }
        }
        return left;
    }
};

题解2

官方题解提供的Floyd判圈法。将原始问题转换为求链表的环的起点。

根据只有一个重复数字,且n+1个数字处于[1,n]的范围内,我们很容易构造这样一个链表。

链表的每一个节点 n o d e 1 node_1 为nums[0],后一个节点为 n o d e 2 = n u m s [ n o d e 1 node_2 = nums[node_1 ,则每i个节点为 n u m s [ n o d e i 1 ] nums[node_{i-1}] ,因为nums数组中存在重复元素,必定会形成环。重复的元素即为环的起点

根据Floyd判圈法,我们很容易找到环的起点。

代码2

/*
快慢指针
时间复杂度为:O(n)
空间复杂度为:O(1)
*/

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int slow = nums[0], fast = nums[0];//从起点出发
        slow = nums[slow], fast = nums[nums[fast]];
        //slow移动一点,fast移动两步

        //找到两个相遇的位置
        while(slow != fast){
            slow = nums[slow];
            fast = nums[nums[fast]];
        }

        //找到环的起点,即重复的元素
        slow = nums[0];
        while(slow != fast){
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
};
发布了169 篇原创文章 · 获赞 35 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/happyeveryday62/article/details/104190045