287. 寻找重复数

题目:

287. 寻找重复数
287. 寻找重复数_第1张图片

题解:

1. 题解一:二分查找

1.1 解释一:

在这里插入图片描述
287. 寻找重复数_第2张图片

1.2 解释二:

287. 寻找重复数_第3张图片

1.3 解释三:

287. 寻找重复数_第4张图片

2. 题解二:快慢指针

142. 环形链表 II

2.1 解释一:

快慢指针思想, fast 和 slow 是指针, nums[slow] 表示取指针对应的元素
注意 nums 数组中的数字都是在 1 到 n 之间的(在数组中进行游走不会越界),
因为有重复数字的出现, 所以这个游走必然是成环的, 环的入口就是重复的元素, 
即按照寻找链表环入口的思路来做
快慢指针,时间O(n),空间O(1)
把数组看作链表,nums[i]表示第i个节点指向第nums[i]个节点
然后问题就变成了找一个有环的链表中环的起始节点

287. 寻找重复数_第5张图片
287. 寻找重复数_第6张图片

2.2 解释二:

287. 寻找重复数_第7张图片
287. 寻找重复数_第8张图片
287. 寻找重复数_第9张图片
287. 寻找重复数_第10张图片

2.3 解释三:

287. 寻找重复数_第11张图片
287. 寻找重复数_第12张图片

代码:

1. 代码一:二分查找

public class code287 {

    // 方法1:二分查找
    public static int findDuplicate(int[] nums) {
        int len = nums.length;
        int left = 1;
        int right = len - 1;
        while(left < right)
        {
            // 在 Java 里可以这么用,当 left + right 溢出的时候,无符号右移保证结果依然正确
            int mid = (left + right) >>> 1;
            int count = 0;
            for(int i = 0; i < len; i++)
            {
                if(nums[i] <= mid)
                {
                    count++;
                }
            }
            // 根据抽屉原理,小于等于 4 的个数如果严格大于 4 个
            // 此时重复元素一定出现在 [1, 4] 区间里
            if(count > mid)
            {
                right = mid; // 重复元素位于区间 [left, mid]
            }
            else
            {
                left = mid + 1; // if 分析正确了以后,else 搜索的区间就是 if 的反面,[mid + 1, right]
            }
        }
        return left;
    }

    public static void main(String[] args) {
        int nums1[] = { 1, 3, 4, 2, 2 };
        int res1 = findDuplicate(nums1);
        System.out.println(res1);

        int nums2[] = { 3, 1, 3, 4, 2 };
        int res2 = findDuplicate(nums2);
        System.out.println(res2);
    }
}

2. 代码二:快慢指针

public class code287 {

    public static int findDuplicate(int[] nums) {
        int slow = 0;
        int fast = 0;
        slow = nums[slow];
        fast = nums[nums[fast]];
        // 第一步找到相遇点
        // 慢指针走一步nums[slow];
        // 快指针走两步nums[nums[fast]]
        while(fast != slow)
        {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        // 快指针归位(0)
        fast = 0;
        // 第二步找到环入口
        // 快指针和慢指针以相同步调行走,并最终在环入口相遇
        while(fast != slow)
        {
            slow = nums[slow];
            fast = nums[fast];
        }
        return fast;
    }

    public static void main(String[] args) {
        int nums1[] = { 1, 3, 4, 2, 2 };
        int res1 = findDuplicate(nums1);
        System.out.println(res1);

        int nums2[] = { 3, 1, 3, 4, 2 };
        int res2 = findDuplicate(nums2);
        System.out.println(res2);
    }
}

参考:

  1. 287.寻找重复数
  2. 快慢指针,一看就懂
  3. 寻找重复数
  4. 使用二分法查找一个有范围的整数(结合抽屉原理)
  5. 快慢指针的解释 [从@Damien_Undo写的题解得到启发]
  6. 前端灵魂画师图解快慢指针
  7. 详细通俗的思路分析,多解法
  8. 『图解』怎么想到 二分查找 和 转成有环链表
  9. 说一下本题用快慢指针来求解的具体转换步骤.
  10. 287. 寻找重复数
  11. 快慢指针
  12. 【287题】寻找重复数
  13. 循环检测方法细说
  14. 二分法+快慢指针 逐行解释 python3
  15. 绝对值+二分法 + 环入口
  16. 二分法&快慢指针

你可能感兴趣的:(热题,HOT,100,数组,快慢指针,二分查找)