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


刚开始只注意到了空间复杂度和时间复杂度的限制,没有注意到数组只读,所以用了之前的一种方法进行解决。就是用数组的元素作为下标去进行访问,然后将访问过的元素标记为负的,下次访问的时候观察是否为父数就能够判断是否重复了。但是这样做就修改了数组,刚开始没有注意到这个,而且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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值