leetcode - Find the Duplicate Numbe

链接:https://leetcode.com/problems/find-the-duplicate-number/

两种解法:

1)利用二分+鸽巢原理

其实就是使用二分搜索来枚举重复数字的范围;根据鸽巢原理,如果数组中<=1/2n的数字超过了1/2n,则说明1~1/2n中有重复的数字,因此我们可以根据该原理来枚举重复数字所在的范围,具体实现代码如下:

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

上述算法的时间复杂度是O(nlogn)

2)类似链表找环的起始节点(映射找环法)

首先来看一下具体的一个例子,数组元素为2,1,3,将数组下标和元素构成一个映射,即0->2, 1->1, 2->3,我们将该映射看成是一个函数f(n),其中n是元素下标,f(n)是该下标对应的元素;如果我们以0为下标,根据f(n)计算出一个值,再以这个值为下标,则可以得到类似链表的一串数字,0->2->3

如果数组中有重复的数字,则在上述串会出现重复,例如数组元素为2,1,3,1,则进行顺序映射过程中,有0->2->3->1->1->1.....,因为我们可以借鉴类似链表找环的方式,来查找重复的数字,并且重复的数字就是环的起始位置

具体代码如下:

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;
    }
};

上述算法的时间复杂度是O(n),可以参加https://segmentfault.com/a/1190000003817671

posted @ 2016-05-12 22:06  Shirley_ICT  阅读(193)  评论(0编辑  收藏  举报