有关环形链表的一些问题

前言

在解决问题之前,我们先来了解一下什么是环形链表,我们以leetcode上的一道题目来感受一下,

读者可以先尝试自己做一下或者直接看下面题目的图片。

题目链接:. - 力扣(LeetCode)

leetcode141.环形链表

从图片中我们可以很容易看出,环形链表就是链表中的某一个节点与链表的另外一个节点相连接,而形成的环状结构。那么我们怎么判断一个链表是否为环形链表呢?我们可以把环状结构看成一个圆,那么我们可以定义快慢指针,以指针是否会相遇为判断条件,如果相遇,那么它就是一个带环的链表,否则它就不带环。下面是代码实现。

bool hasCycle(struct ListNode *head) {
    struct ListNode*slow=head;
    struct ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast){return true; }
    }
    return false;
}

循环的结束条件为快指针以及快指针的下一个节点是否为空,如果为空就证明链表不带环,否则快慢指针就一定会相遇。

那么fast一次走两步时一定会相遇,那么fast一次走三步,四步,五步呢,下面我以fast一次走三步为例来推断是否在所有情况下fast和slow一定会相遇。

当N和C都为偶数时,slow和fast一定可以相遇,也就可以证明slow和fast一定可以相遇。

leetcode142.环形链表II

题目链接:. - 力扣(LeetCode)

第一种思路:

这道题目依旧是使用了快慢指针法。先通过快慢指针找到相遇的节点,一边从相遇的节点开始走,一边从头节点开始走,当前者与后者相遇的时候,此时即为环形链表的头节点。

​
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow=head;
    struct ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            struct ListNode*meet=slow;
            while(head!=meet)
            {
                head=head->next;
                meet=meet->next;
            }
            return meet;
        }
        
    }
    return NULL;
}

​

第二种思路:

还是使用快慢指针,先是找到相遇点,将相遇点的next指针指向空,这样这道题就变成了找相交链表的相交点。

 struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode*curA=headA;
    struct ListNode*curB=headB;
    int lenA=0,lenB=0;
    while(curA->next)
    {
        curA=curA->next;
        lenA++;
    }
    while(curB->next)
    {
        curB=curB->next;
        lenB++;
    }
    if(curA!=curB)
    {
        return NULL;
    }
    int len=abs(lenA-lenB);
    struct ListNode*shortlist=headA;
    struct ListNode*longlist=headB;
    if(lenA>lenB)
    {
        shortlist=headB;
        longlist=headA;
    }
    while(len--)
    {
        longlist=longlist->next;
    }
    while(longlist!=shortlist)
    {
        longlist=longlist->next;
        shortlist=shortlist->next;
    }
    return longlist;
}
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode*slow=head;
    struct ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            struct ListNode*meet=slow;
            struct ListNode*newhead=meet->next;
            meet->next=NULL;
            struct ListNode*a=getIntersectionNode(head,newhead);
            return a;
        }
    }
    return NULL;
}

我们来证明一下第一种方法

推出的表达式中c-N是环形链表的头节点和相遇点的距离,不管fast走多少圈,环形链表的头节点

与slow和fast的相遇点的距离都和链表与环形链表的头节点的距离相同。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值