【LeetCode - 287】寻找重复数

1、题目描述

在这里插入图片描述

2、解题思路

  本题限制了不能改变原数组,且智能使用额外的 O(1) 的空间,说白了就是不能把无序数组改为有序。

  数组 nums 包含了 1 到 n 之间的数字,因此大概为:[1,2,3…,target,…n] 的样子。

  定义一个变量 cnt[i] 表示 nums[] 数组中小于等于 i 的数有多少个。

  例如数组 [1,3,4,2,2] 的 cnt = {0,1,3,4,5}。

  可以得出一个规律:在[0, target-1] 区间内,cnt[i] ≤ i;在 [target, n] 区间内,cnt[i] > i。

  因此,采用二分的方法,在 1 到 n 之间找出一个 target,使得它是最小的满足 cnt[i] > i 的数。

  具体算法如下:

  1、用二分法在[1,2,3…,target,…n]中选择一个候选值mid,

  2、若mid处 cnt <= mid,则说明target在mid右边:[1,2,3…mid…target…n]

  3、反之,target在mid左边:[1,2,3…target…mid…n]

  4、按上述判断结果重新划定[left,right],得出新的候选值mid,继续判断

3、解题代码

class Solution {
    public int findDuplicate(int[] nums) {
        int left = 1;
        int right = nums.length - 1;
        int ans = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            int cnt = 0;    //  cnt 表示 nums[] 数组中小于等于 mid 的数有多少个
            for (int i = 0; i < nums.length; ++i) {
                if (nums[i] <= mid) {
                    cnt++;
                }
            }
            if (cnt <= mid) {
                left = mid + 1;
            } else {
                right = mid - 1;
                ans = mid;
            }
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值