leetcode [287. 寻找重复数]

(https://leetcode-cn.com/problems/find-the-duplicate-number/)

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

1:二分查找:

这里的二分是对1~n 进行二分,主要思想是我们在1~n中进行二分取值,设中间的数为mid,如果在nums数组中<= mid的数大于了mid,那么答案肯定在1~mid中,否则答案就在mid+1 ~ n中。

为什么是这样?其实是题目限制的比较严格,用往抽屉里放香蕉的方法去说,nums[i] 表示第i根香蕉放在nums[i] 号抽屉里,按理说一个抽屉里只能放一个香蕉,我们的目的是找出哪个抽屉里多放了香蕉。我们从1~n号抽屉里抽了mid号抽屉,如果mid号抽屉和前边的抽屉里的香蕉和大于了mid,那么1 ~mid号抽屉里肯定有某个抽屉多放了,因为如果不多放,1 ~ mid 号抽屉里的香蕉和最多为mid 个 。

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = nums.size(),left = 1,right = n-1,cnt;
        while(left < right){
            cnt = 0;
            int mid = (left+right)/2;
            for(int i = 0; i < n; i++) if(nums[i] <= mid) cnt++;
            if(cnt > mid) right = mid;
            else left = mid+1;
        }
        return left;
    }
};

2:快慢指针:

在分析之前需要对 Floyd 判圈算法(又称龟兔赛跑算法)有所了解,如果不知道,可看我的这篇随笔https://www.cnblogs.com/Beic233/p/12965361.html

看完之后,我们就可以把nums数组给化成一个链表,nums[i] 就表示i号链表顶点的next指针指向nums[i] 号顶点,这时候再看一眼题目,题目保证了除了答案所求的顶点外,其他顶点肯定是一进一出,所以我们这个链表必有环,而答案就是这个环的起点(这里可以画画)。而下面的步骤对于了解 Floyd 判圈算法的你就非常简单了

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int fast = 0,slow = 0;
        do{
            fast = nums[nums[fast]];
            slow = nums[slow];
        }while(fast != slow);
        slow = 0;
        while(slow != fast){
            slow = nums[slow];
            fast = nums[fast];
        }
        return fast;
    }
};

猜你喜欢

转载自www.cnblogs.com/Beic233/p/12965678.html