Leetcode 287. 寻找重复数【快慢指针法&二分法】

问题描述

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

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

解题报告4

快慢指针法

很明显是,我们需要构成一个环,然后找到环的起点,即为重复的数。
具体解释见Leetcode 142. 环形链表 II【快慢指针法求环的起点】

二分法【抽屉原理】

因为数组中每个数的范围为: [ 0 , n ] [0,n] [0,n],我们取中间数 n / 2 n/2 n/2,如果整个数组中小于等于 n / 2 n/2 n/2 严格大于 n / 2 n/2 n/2,那么重复元素出现在 [ 0 , n / 2 ] [0,n/2] [0,n/2]这个区间内,否则在区间 [ n / 2 + 1 , n ] [n/2+1,n] [n/2+1,n]内。

实现代码

快慢指针法实现

class Solution{
    public:
        int findDuplicate(vector<int>nums) {
            int slow = nums[0];
            int fast = nums[nums[0]];
            
            //寻找相遇点
            while (slow != fast) {
                slow = nums[slow];
                fast = nums[nums[fast]];
            }
            //slow 从起点出发, fast 从相遇点出发, 一次一步
            slow = 0;
            while (slow != fast) {
                slow = nums[slow];
                fast = nums[fast];
            }
            return slow;
        }
};

二分法实现

#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    int findDuplicate(vector<int> &nums) {
        int len = nums.size();
        int left = 1;
        int right = len - 1;

        while (left < right) {
            int mid = left + (right - left) / 2;

            int cnt = 0;
            for (int num:nums) {
                if (num <= mid) {
                    cnt++;
                }
            }

            // 根据抽屉原理,小于等于 4 的数的个数如果严格大于 4 个,
            // 此时重复元素一定出现在 [1, 4] 区间里

            if (cnt > mid) {
                // 重复的元素一定出现在 [left, mid] 区间里
                right = mid;
            } else {
                // if 分析正确了以后,else 搜索的区间就是 if 的反面
                // [mid + 1, right]
                // 注意:此时需要调整中位数的取法为上取整
                left = mid + 1;
            }
        }
        return left;
    }
};

//作者:liweiwei1419
//链接:https://leetcode-cn.com/problems/find-the-duplicate-number/solution/er-fen-fa-si-lu-ji-dai-ma-python-by-liweiwei1419/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考资料

[1] Leetcode 287.寻找重复数
[2] 题解区:windliang
[3] 题解区:liweiwei1419
[4] 快慢指着找环入口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值