[LEETCODE] 287. Find the Duplicate Number

本文介绍了解决LeetCode上287题“寻找重复数字”的两种高效方法:一是利用二分查找进行优化;二是通过快慢指针寻找链表中的环来找到重复数字。这两种方法均能在限定条件下解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[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.

这道题刚读题的时候觉得不应该是hard 难度的题。但是看了note 之后想了很久。。。。

一开始先用hash,因为有重复,所以直接把数存到对应的hash数组里面就很快可以找到,但是题目规定要O(1) ,所以不能使用额外的数组。。。

然后就想sort,结果题目又说不能修改array。。。

最后想用暴力遍历两次数组的方法,但是题目要求时间复杂度低于O(n2)。

最后发现可以用两种方法解决。
第一种是对暴力法的优化。就是使用2分的方法。根据抽屉原理,我们可以知道duplicate number 是在mid 的左边还是右边,以此类推,我们可以逐渐缩小范围,直至最后找到该duplicate number。

public class Solution {
    public int findDuplicate(int[] nums) {
        int min = 0, max = nums.length - 1;
        while(min <= max){
            int mid = min + (max - min) / 2;
            int cnt = 0;
            for(int i = 0; i < nums.length; i++){
                if(nums[i] <= mid){
                    cnt++;
                }
            }
            if(cnt > mid){
                max = mid - 1;
            } else {
                min = mid + 1;
            }
        }
        return min;
    }
}

第二种是找环。如果array 中所有的数都是不同的话,那么下标和数是一一对应的关系,否则,下标和数就是多对一的关系。这样的话,如果我们每次都把下标对应的那个数作为新的下标,那么它最后会变成一个环。根据这个环我们就可以找到重复的那个数。

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int slow = 0;
        int fast = 0;
        do {
            slow = nums[slow];
            fast = nums[nums[fast]];
        } while(slow != fast);
        int find = 0;
        while (find != slow) {
            find = nums[find];
            slow = nums[slow];
        }
        return find;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值