首页 » C语言 » Leetcode算法学习日志-287 Find the Duplicate Number

Leetcode算法学习日志-287 Find the Duplicate Number

原文 http://blog.csdn.net/Zarlove/article/details/79213831

2018-02-01 02:00:42阅读(309)

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. 题意分析

给定n+1个数,它们的取值从1-n选取,可以证明一定会有重复元素,如果限定只有一个重复元素,找出这个重复元素。

解法分析

本题是双指针(快慢指针)的应用,解法同Leetcode 142 Linked List cycle II,现在先来讲解下142.该题给定一个链表,要求如果链表有圈,则找出这个圈的入口点,如果没有,则返回null指针。情形如下图所示:

                          Leetcode<a href=算法学习日志-287 Find the Duplicate Number" src="http://img.blog.csdn.net/20180131103142467?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWmFybG92ZQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">


令快指针慢指针分别为fp和sp,这里都令快指针走两步,慢指针走一步,如果不是两倍的比例,可能会造成不便。两个指针同时从h出发,如果fp->next或fp->next-next为空,则无圈,否则当sp进入圈中时,fp可以看做按顺时针追及sp,由于每一次运动它们的间距减一,而sp刚进圈时它们的间距小于圈长r,因此fp必然在sp走完一圈之前追上sp,此时fp已经绕圈n次。该模型能解决如下三个问题:

是否有圈

当fp->next==NULL或fp->next->next==NULL时无圈,第二个判断主要是避免链长为2的情形。

圈长

如果确定有圈,则当fp==sp时它们相遇,此时只需要让一个指针不动,另一个指针按1的步长运动,等到再次相遇时的步数就是圈长r。

入圈点

如上图,当第一次相遇时,sp走了a+x,fp走了a+x+nr,由于它们的速度是两倍关系,所以2(a+x)=a+x+nr,a+x=nr,a=(n-1)r+r-x,r-x为相遇点到入圈点的距离,此表达式表示如果给定两点,一个从h(头)出发,一个从相遇点c出发,它们一定能在入圈点相遇,因此找到相遇点后,只需要进行上述操作就能找到入圈点。C++代码如下:

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode *fast=head;
        ListNode *slow=head;
        if(head==NULL)
            return head;
        while(1){
            if(fast->next==NULL||fast->next->next==NULL)
                return NULL;
            fast=(fast->next)->next;
            slow=slow->next;
            if(slow==fast)
                break;
        }
        slow=head;
        while(slow!=fast){
            slow=slow->next;
            fast=fast->next;
        }
        return fast;  
    }
};
对于本题,数组的下标就是指向它的指针,而它值就是他的next指针,如下例:

下标:0 1 2 3 4 5

值:   1 3 2 4 5 4

可以看出head指针为0,它的元素为1,下标1指向元素3,下标3指向元素4,下标4指向元素5,下标5指向元素4,下标4又指向元素5,可以看到从元素4开始进入圈。因此定义fast和slow作为快慢指针(下标),用上述方法即可得到结果。C++代码如下:

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
        int fast=0;
        int slow=0;
        while(1){
            fast=nums[nums[fast]];
            slow=nums[slow];
            if(fast==slow)
                break;
        }
        fast=0;//slow is alse ok
        while(fast!=slow){
            fast=nums[fast];
            slow=nums[slow];
        }
        return fast; 
    }
};




最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹