287. 寻找重复数

二分查找

解题思路

  1. n + 1 个整数,放在长度为 n 的数组里,并且数字都在 [1, n] 范围内,根据「抽屉原理」(把 10 个苹果放进 9 个抽屉,至少有一个抽屉里至少放 2 个苹果),至少会有 1 个整数是重复的;

  2. 定义 leftright 两个指针,统计原始数组中 小于等于 mid 索引 的元素的个数 count

    • 如果 count > mid,重复元素就在区间 [left…mid] 里;
    • 如果 count <= mid,重复元素一定可以在区间 [mid + 1…right] 里找到;

复杂度

  1. 时间复杂度:O(nlogn),二分法的时间复杂度为 O(log⁡n),在二分法的内部,遍历数组的时间复杂度为 O(n)

  2. 空间复杂度:O(1)

代码实现

function findDuplicate(nums) {
    let len = nums.length;
    let left = 1;
    let right = len - 1;

    while (left < right) {
        let mid = left + Math.floor((right - left) / 2);

        // 根据 nums 数组中 小于等于 mid 索引 的元素的个数来判断 查找范围
        let count = 0;
        for (let i = 0; i < nums.length; i++) {
            if (nums[i] <= mid) {
                count++;
            }
        }

        if (count > mid) {
            right = mid; // 下一轮搜索的区间 [left,mid]
        } else {
            left = mid + 1; // 下一轮搜索的区间 [mid + 1,right]
        }
    }

    return left;
}

快慢指针

解题思路

  1. 该题可以转化成「环形链表寻找入口」,可以参考 leetcode🧑‍💻 142. 环形链表 II

  2. 数组的值可以看成 next 指针的指向;

复杂度

  1. 时间复杂度:O(n)

  2. 空间复杂度:O(1)

代码实现

var findDuplicate = function (nums) {
    let slow = 0;
    let fast = 0;

    // 找到相遇的点
    do {
        slow = nums[slow];
        fast = nums[nums[fast]];
    } while (slow != fast);

    // 找到环形链表的入口
    slow = 0;
    while (slow != fast) {
        slow = nums[slow];
        fast = nums[fast];
    }

    return slow;
};
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 二分查找
    1. 1.1. 解题思路
    2. 1.2. 复杂度
    3. 1.3. 代码实现
  2. 2. 快慢指针
    1. 2.1. 解题思路
    2. 2.2. 复杂度
    3. 2.3. 代码实现