循环链表的判断

重新理解了快慢指针,判断是否有循环这一问题。
142. Linked List Cycle II
287. Find the Duplicate Number
先看第一个:判断循环链表
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

Note: Do not modify the linked list.

Follow up:
Can you solve it without using extra space?
一般如果判断一个链表有循环的话,可以通过快慢指针判断。
假设循环圈的链表的节点数是c,快指针每次走两步,慢指针每次走一步。
如果快慢指针有相遇,则证明有圈。


下面说明:如果有圈,那么怎么找圈的入口。

如下有一个循环链表:

这里写图片描述
三个红圈内的节点假设分别代表:起始节点、循环入口和快慢指针的相遇节点。假设两者相遇时慢指针走的长度是s,则快指针已经做了2s步。如果有循环的圈的大小是c,则两者相遇时有2s=s+n*c,即s=n*c。慢指针比快指针少走了n圈,n是正整数。如果假设从起始点到循环入口的长度为x,从循环入口到相遇点的长度为a,有s=x+a.
故s=n*c=x+a。x=n*c-a=(n-1)*c+c-a。这里c-a是圈余下的部分。
因此,如果slow指针从相遇点开始继续走,另一个指针从起始处开始走,那么他们相遇的点必定是这个循环的入口。这里两个指针都是一步一步的走。
因为x=n*c-a=(n-1)*c+c-a.
对于142问题:

 ListNode *detectCycle(ListNode *head) {
        if(!head||!head->next) return NULL;
       ListNode* slow=head->next,*fast=head->next->next; 
       while(fast!=slow)
       {
           if(fast==NULL||fast->next==NULL) return NULL;
           slow=slow->next;
           fast=fast->next->next;
       }//slow指向相遇节点
       //下面找入口点
       fast=head;
       while(fast!=slow)
       {
           fast=fast->next;
           slow=slow->next;
       }
       return slow;
    }

对于找重复数:
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.
这里可以把数组看成一个链表:当前的元素值就是它下一个要遍历的位置,即链表的next。
nums[i]的next是nums[nums[i]]。
这里的重复元素可以看成链表循环的入口处。就可以用142的方法解决。

int findDuplicate(vector<int>& nums) {
       if(nums.size()==1) return nums[0];
       int slow=nums[0];
       int fast=nums[nums[0]];
       while(slow!=fast)
       {
           fast=nums[nums[fast]];
           slow=nums[slow];
       }//此时找到相遇点
       //另一个指针从起始处开始,和slow同时走,直到相遇在入口处
       fast=0;
       while(slow!=fast)
       {
           slow=nums[slow];
           fast=nums[fast];
       }
       return slow;

    }

转载于echoxiaolee

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值