快慢指针的应用

快慢指针的原理

快慢指针是利用两个指针移动速度的不一样,实现一些有趣的追击行为。就像上学时求解的那些操场上的追击问题一样。

问题1:判断两个链表是否相交。(链表不存在环结构)

形如:

 方法:循环第一个链表到最后一个节点,记下该节点的指针P1,然后循环第二个链表到最后一个节点,然后将这个节点的指针和P1做比较,如果相同则相交,否则就不相交。

问题2:判断两个链表是否相交。(链表可能存在环结构)

形如:

方法:先使用快慢指针遍历链表判断链表是否带环。

1、如果都不带环,则判断最后的节点指针是否相同,相同就说明相交,不相同就不相交。

2、一个带环一个不带环,则两个链表必然不相交。

3、两个都带环,则判断其中一个链表的快慢指针相遇的节点是否在另外一个链表上,在说明相交,不在说明不相交。

问题3:一个单链表,判断是否存在环

方法:采用“快慢指针”的方法。设置两个指针fast和slow,开始的时候两个指针指向链表头head,然后每次操作slow向前走一步(slow=slow->next),fast每次向前走两步(fast=fast->next->next)。

由于fast比slow快,如果有环,则fast一定先进入环,slow后进入环。然后在环内它们必然在一定步骤必然相遇。如果没有环,那么fast就会遇到null。

if (slow != null && fast->next != null)
{
    slow = slow->next;
    fast = fast->next->next;
    if (slow == fast)
        // 有环
}
else
{
    // 无环
}

 问题4:一个存在环的单链表,找出环的入口点

分析一下:当slow刚到达环的入口处时,fast在环上的任意一个点处,此时fast距离slow设为x,x一定是小于等于环的长度r的。那么当slow再走x步后,fast必然就和slow相遇了(刚开始fast相距slow为x,slow又走了x,此时fast就走了2*x,则刚好遇上)。如上图所示。

从上面的分析知道,当fast和slow相遇时,slow走的距离x是小于等于r的,现在假设:fast已经在环内循环了n(1 <= n)圈。slow走了s步,fast就走了2*s步,由于fast走过的步数 = s + n*r。

则有下面的等式:

2\ast s=s+n\ast r ;(1) \newline => s = n*r;(2) \newline

如果整个链表的长度是L,入口和相遇点距离是x,起点到入口点的距离是a,则有:

a+x = s = n\ast r;(3)   由(2)推出。

a+x = (n-1)\ast r+r = (n-1)\ast r + (L-a);(4)  由环的长度=链表总长度-起点到入口的距离求出。

a = (n-1)\ast r + (L-a-x);(5)

分析等式(5),(L-a-x) 是相遇点到入口的距离,再结合上图分析可知,当两个指针一个指针在链表头另一个在相遇点同时出发,每次走一步,当指向头指针的走到入口处时,相遇点的指针也刚好走到入口处。

代码如下:

Node* findLoopStart(Node *head)
{
    Node *fast, *slow;
    slow = fast = head;
    while (slow != NULL && fast->next != NULL)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (slow == fast) break;
    }
    if (slow == NULL || fast->next == NULL) return NULL; //没有环,返回NULL值
   
    Node * ptr1 = head; //链表开始点
    Node * ptr2 = slow; //相遇点
    while (ptr1 != ptr2)
    {
        ptr1 = ptr1->next;
        ptr2 = ptr2->next;
    }
    return ptr1; //找到入口点
}

扩展问题:

1、寻找链表的中点位置

2、寻找链表的倒数第k的位置

 

 

 

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nmg10

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值