LeetCode数组:寻找重复数

寻找重复数

题目描述

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。

你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

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

解题思路1:二分查找

为什么可以应用二分查找呢?它又不是按照顺序进行排列
此时可以根据它的取值范围进行二分查找,取[1, n]中间数,然后来计数nums中比他小的个数有多少,因为比mid小的只能是有mid个如果多于这个数则代表重复的数在左边这部分,否则则在右边,然后依次进行划分,跳出循环不满足左小于右则直接返回左几颗

代码1

class Solution {

    public int findDuplicate(int[] nums) {
        int len = nums.length; // n + 1 = len, n = len - 1

        // 在 [1..n] 查找 nums 中重复的元素
        int left = 1;
        int right = len - 1;
        while (left < right) {
            int mid = (left + right) / 2;

            // nums 中小于等于 mid 的元素的个数
            int count = 0;
            for (int num : nums) {
                if (num <= mid) {
                    count++;
                }
            }

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

解题思路2:快慢指针

建立索引与值的映射关系的链表。
利用快慢指针的关键是,检测环以及找到环的起始点
检测环容易一点,快指针走两步慢指针走一步,直到两只相遇,即为有环,找到环的入口用到一些数学知识

  • 设数组的起始位置到环的起始位置的距离为a。

  • 设环的起始位置到相遇点的距离为b。

  • 设相遇点到环的起始位置的距离为c。
    当两个指针(pre1,pre2)相遇时。

  • 此时先假设快指针(pre1)走了一圈就相遇,即:a+2b+c,那么慢指针走过的距离为:a+b;
    由于快指针依次走两步,假设其速度为2,慢指针为1,相同时间到达同一点,建立等式:(a+b)/1=(a+2b+c)/2 解等式即可得到a=c。
    那么此时只需要让一个指针从开始0位置以速度为1走,慢指针继续原来位置原来速度走,相遇时就是环入口位置。

  • 换一种情况:当慢指针到达b时,快指针已经在环中走了k圈,建立等式:(a+b)/1=(a+(k+1)b+kc)/2
    解等式得到:a=(k-1)b+kc。这个等式代表从相遇点走k-1圈后再走c的距离等于a。那这就说明了慢指针继续原来位置原来速度走,相遇时就是环入口位置。
    在这里插入图片描述

代码2

class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0;
        int fast = 0;
        slow = nums[slow];
        fast = nums[nums[fast]];
        while(slow != fast){
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        int pre1 = 0;
        int pre2 = slow;
        while(pre1 != pre2){
            pre1 = nums[pre1];
            pre2 = nums[pre2];
        }
        return pre1;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值