287. Find the Duplicate Number。

本文介绍了一种在不修改原始数组且仅使用常数级额外空间的情况下,寻找数组中重复数字的方法。该方法的时间复杂度低于O(n^2),利用了数组元素间的特定关系,通过模仿链表循环检测的方式实现。

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

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)的时间复杂度。


刚开始只注意到了空间复杂度和时间复杂度的限制,没有注意到数组只读,所以用了之前的一种方法进行解决。就是用数组的元素作为下标去进行访问,然后将访问过的元素标记为负的,下次访问的时候观察是否为父数就能够判断是否重复了。但是这样做就修改了数组,刚开始没有注意到这个,而且ac了之后看速度快的前几个也是类似的做法,后来才注意到不能修改。

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        for(int i=0;i<nums.size();i++) {
            int n = abs(nums[i]);
            if(nums[n] < 0) {
                return abs(nums[i]);
            } else {
                nums[n] *= -1;
            }
        }
        return -1;
    }
};

看到Solution中的解法,其中的排序和集合都在空间或者时间复杂度上不满足限定条件,最后一个有趣的解法完全符合要求,解法与之前的链表中的142. Linked List Cycle II。最后一种类似,将数组看作成一个链表,其中能够根据数组中的元素找到下一个节点位置,所以同样的使用两个哨兵进行移动,当相遇的时候让其中一个哨兵从头开始运动,然后两个哨兵再次相遇的时候就是我们要找的重复元素,Solution中配有动画,理解起来十分方便:https://leetcode.com/problems/find-the-duplicate-number/solution/

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int tortoise = nums[0];
        int hare = nums[0];

        do {
            //cout << tortoise << "," << hare << endl;
            tortoise = nums[tortoise];//慢的走一步
            hare = nums[nums[hare]];//快的走两步
        } while(tortoise != hare);

        int ptr1 = nums[0];
        int ptr2 = tortoise;

        while(ptr1 != ptr2) {
            //cout << ptr1 << "," << ptr2 << endl;
            ptr1 = nums[ptr1];
            ptr2 = nums[ptr2];
        }

        return ptr1;
    }
};
(c++题解,代码运行时间小于200ms,内存小于64MB,代码不能有注释)It’s time for the company’s annual gala! To reward employees for their hard work over the past year, PAT Company has decided to hold a lucky draw. Each employee receives one or more tickets, each of which has a unique integer printed on it. During the lucky draw, the host will perform one of the following actions: Announce a lucky number x, and the winner is then the smallest number that is greater than or equal to x. Ask a specific employee for all his/her tickets that have already won. Declare that the ticket with a specific number x wins. A ticket can win multiple times. Your job is to help the host determine the outcome of each action. Input Specification: The first line contains a positive integer N (1≤N≤10 5 ), representing the number of tickets. The next N lines each contains two parts separated by a space: an employee ID in the format PAT followed by a six-digit number (e.g., PAT202412) and an integer x (−10 9 ≤x≤10 9 ), representing the number on the ticket. Then the following line contains a positive integer Q (1≤Q≤10 5 ), representing the number of actions. The next Q lines each contain one of the following three actions: 1 x: Declare the ticket with the smallest number that is greater than or equal to x as the winner. 2 y: Ask the employee with ID y all his/her tickets that have already won. 3 x: Declare the ticket with number x as the winner. It is guaranteed that there are no more than 100 actions of the 2nd type (2 y). Output Specification: For actions of type 1 and 3, output the employee ID holding the winning ticket. If no valid ticket exists, output ERROR. For actions of type 2, if the employee ID y does not exist, output ERROR. Otherwise, output all winning ticket numbers held by this employee in the same order of input. If no ticket wins, output an empty line instead. Sample Input: 10 PAT000001 1 PAT000003 5 PAT000002 4 PAT000010 20 PAT000001 2 PAT000008 7 PAT000010 18 PAT000003 -5 PAT102030 -2000 PAT000008 15 11 1 10 2 PAT000008 2 PAT000001 3 -10 1 9999 1 -10 3 2 1 0 3 1 2 PAT000001 3 -2000 Sample Output: PAT000008 15 ERROR ERROR PAT000003 PAT000001 PAT000001 PAT000001 1 2 PAT102030
最新发布
08-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值