算法思想:快慢指针

快慢指针

     快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,
如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。

Question 1

     为什么快指针每次走两步,慢指针走一步可以相遇,有没有可能遇不上,请推理证明!
slow一次走一步,fast一次走两步,fast先进环,假设slow也走完入环前的距离,准备进环,此时fast 和slow之间的距离为N,接下来的追逐过程中,每追击一次,他们之间的距离缩小一步。
追击过程中fast和slow之间的距离变化:

因此,在带环链表中慢指针走一步,快指针走两步最终一定会相遇。

Question 2

快指针一次走3步,走4步,...n步行吗?

step1:

按照上面的分析,慢指针每次走一步,快指针每次走三步,此时快慢指针的最大距离为N,接下来的 追逐过程中,每追击一次,他们之间的距离缩小两步。
追击过程中fast和slow之间的距离变化:

 分析:

1.如果N是偶数,第一轮就追上了。

2.如果 N是奇数,第一轮追不上,快追上,错过了,距离变成-1,即C-1,进入新的一轮追击。

    Case1 :C-1如果是偶数,那么下一轮就追上了。

    Case2 :C-1如果是奇数, 那么就永远都追不上。

总结一下追不上的前提条件: N是奇数,C是偶数

step2

假设:
环的周长为C,头结点到slow结点的长度为L,slow走一步,fast走三步,当slow指针入环后,
slow和fast指针在环中开始进行追逐,假设此时fast指针已经绕环x周。
在追逐过程中,快慢指针相遇时所走的路径长度:
      fast:  L+xC+C-N
      slowL
由于慢指针走一步,快指针要走三步,因此得出: 3 * 慢指针路程 = 快指针路程 ,即:
      3L=L+xC+C-N
      2L=(x+1)C-N
对上述公式继续分析:由于偶数乘以任何数都为偶数,因此一定为偶数,则可推导出可能得情
   Case1:偶数 = 偶数 - 偶数
   Case2:偶数 = 奇数 - 奇数
由step1中(1)得出的结论,如果N是偶数,则第一圈快慢指针就相遇了。
由step1中 (2) 得出的结论,如果N是奇数,则fast指针和slow指针在第一轮的时候套圈了,开始进 行下一轮的追逐;当N是奇数,要满足以上的公式,则 (x+1)C 必须也要为奇数,即C为奇数,满足(2) 中的结论,则快慢指针会相遇。
因此, step1 中的N是奇数,C是偶数不成立,既然不存在该情况,则快指针一次走3步最终一定也 可以相遇。
快指针一次走4、5.....步最终也会相遇,其证明方式同上。

题目

了解快慢指针的思想后,我们来看一道算法题。

思路

  快慢指针,若指针指向同一个节点,则链表带环。

画图解释

完整代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head)
{
    //快慢指针
    ListNode*slow=head;
    ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
           return true;
        }
    }
    //两个指针始终没有相遇
    return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值