leetcode 287

题目链接

这道题目要求在含有n+1个数字的数组中找出唯一一个出现多次的数字,而这些数字的范围是1-n,要求不改变数组本身以及常数空间。

首先我想到的办法是用Bitmap,即一个整型的数字X来表示某个数字是否出现过,如果出现过,那么就在X中对应的位置1。但是这个前提即使n不能太大了,否则整型的数字存储不下。反正这道题用了long long也不行。

这道题目看了别人的解答,可以说非常巧妙了。因为数组的范围是1-n,那么我们可以把数字之间的转移关系变成一个有向图。比如[2,1,2],那么2->2, 1->1,2->2。

这个例子太过简单,我们来举一个复杂一点的例子。此时数组为[3,1,3,4,2]。

首先第一个数字3指向下标3的数字4,

数字4指向下标4的数字2

数字2指向下标2的数字3

数字1指向下标1的数字1

这样变成一个有向图以后就是

从这里看出来3,4,2形成了一个环,而环的入口点是3,这个问题就转换成了找图入口点的问题,可以把图看成链表,找链表入口点的问题就成了leetcode 142 了。利用快慢指针即可。

当然这里还有一个问题,看上图中,1是单独出来的,那么当我们初始化的时候,如果刚好碰到像1这种单独成环的怎么办?其实我们从数组第1个点进去即可,即下标为0的数字。因为题目说了数组中数字的范围是1-n的,所以0点处的值是不可能单独成环的,放心的从第一个数字开始找环即可。

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int n = (int)nums.size();
        // if(n == 1) return 
        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;
    }
};

  

猜你喜欢

转载自www.cnblogs.com/leohujx/p/9747477.html