LeetCode 287. Find the Duplicate Number

问题描述

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.

问题分析

一个长度为n+1的数组,其中放了区间为[1,n]的数。当中有一个数出现了多次。其他值出现一次。让找出这个数。
没有限制条件,可以的方法是:统一每个数出现的次数。排序,找出连续相同的数。
体局中有一些限制:
空间复杂度是O(1)。
时间复杂度是O(n^2)
同时不能改变当前的数组。
这样就将之前的方法给排除了。

方法一

首先求出当前数的区间。[low,high].然后用中位数mid。然后判断[low,mid-1],[mid+1 , high]数的个数,如果两个都小于区间长度,那么mid就出现了多次。如果两个中有一个大于区间长度,那么就继续判断,知道区间 low = high。这个和二分法有点类似。使用了抽屉原理。

代码实现
 public int findDuplicate(int[] nums) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int num : nums) {
            if (num > max) {
                max = num;
            }
            if (num < min) {
                min = num;
            }
        }
        while (max > min) {
            int mid = (min + max) / 2;
            int leftCout = numnCount(nums, min, mid - 1);
            int rightCount = numnCount(nums, mid + 1, max);
            if (leftCout > (mid - min)) {
                max = mid - 1;
            } else if (rightCount > (max - mid)) {
                min = mid + 1;
            } else {
                return mid;
            }
        }
        return min;
    }

    /**
     * 计算在这连个数之间的数的个数
     *
     * @param nums
     * @param max
     * @param min
     * @return
     */
    private int numnCount(int[] nums, int min, int max) {
        int count = 0;
        for (int num : nums) {
            if (num >= min && max >= num) {
                count++;
            }

        }
        return count;
    }
方法二

在一个数组中,如果有一个重合的数,如果类似于树一样遍历的话,会有环。
如果用两个指针,以一倍和两倍的速度往前移动,最终两倍的指针会追上一倍的指针。相遇的位置是在环中的某一个点上。这个时候,使用另外一个指针从数组头部开始,然后同时往前走,两个指针一定会相遇,而且相遇的位置是在环的入口的地方。,也是这个系统总相同的数的位置。可以证明一下的。

代码实现
public int findDuplicate(int[] nums) {
        if (nums.length > 1) {
            int slow = nums[0];
            int fast = nums[nums[0]];
            while (slow != fast) {
                slow = nums[slow];
                fast = nums[nums[fast]];
            }
            fast = 0;
            while (slow != fast) {
                slow = nums[slow];
                fast = nums[fast];
            }
            return slow;
        }
        return -1;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值