LeetCode 287. 寻找重复数

//二分法查找
class Solution {
    public int findDuplicate(int[] nums) {
        //定义数组左边界的指针 left,右边界指针 right
        int left = 1;
        int right = nums.length - 1;

        while(left < right){
            //确定mid, 这里的写法参考了题解中liweiwei1419的写法,我这菜鸡一般都写 mid = left + (right - left) / 2;
            int mid = (left + right) >>> 1;
            //定义一个计数器 count,统计数组中的元素小于等于 中间元素mid的数量
            int count = 0;
            for(int num : nums){
                if(num <= mid){
                    count++;
                }
            }
            //遍历完一次 判断下一次遍历的区间
            //liweiwei1419大神讲解了抽题原理,讲 若mid = 4, 小于等于4的元素如果严格大于4个,此时重复元素一定在【1,4】区间里
            if(count > mid){
                //更改 right边界 [left,mid]
                right = mid;
            }else{
                //更改 left 边界 [mid+1,right]
                left = mid + 1;
            }
        }
        return left;
    }
}

 这道题(据说)花费了计算机科学界的传奇人物Don Knuth 24小时才解出来。并且我只见过一个人(注:Keith Amling)用更短时间解出此题。作为普通人的我们在刷题的道路上不要气馁,努力前行,相信努力和汗水不会白费。

双指针解法(官方题解),推荐官方题解的动画演示,双指针法有其数学道理,有能力的同学请自行深研。

详细讲解请移步官方题解,谢谢。

//快慢指针法
class Solution {
    public int findDuplicate(int[] nums) {
        //定义快慢指针 slow ,fast
        int slow = nums[0];
        int fast = nums[nums[0]];

        while(slow != fast){
            slow = nums[slow];
            fast = nums[nums[fast]];
        }
        //这里置 fast  或者 slow 都可以
        slow = 0;
        while(slow != fast){
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}
原文地址:https://www.cnblogs.com/peanut-zh/p/13904384.html