环形链表问题

力扣(LeetCode)---环形链表

力扣(LeetCode)---环形链表II

两个环形链表问题

①判断链表中是否存在环。

②求环形链表的入口节点。

1 判断链表中是否存在环 

对于一个存在环的链表,在遍历链表时,指针进入到环状链表后一定是一个死循环,根据这个特性,我们可以设置一个快指针和一个慢指针,因为是一个循环,所以快慢指针终将会相遇,相遇就代表这个链表存在环。

 

快指针一次走两步,慢指针一次走一步,如果有环,快指针和慢指针终将相遇。

1.1 问题:

为什么快指针走两步,慢指针走一步就一定行呢,快指针一次走三步呢,走四步呢,走N步呢,是否也行得通呢??

对于这个问题,我们知道如果快指针比慢指针多走一步。

假设图中一段表示一步,当slow和fast都进入圆环时候。

此时slow和fast相差的距离是2。如果再走一步。

此时fast和slow距离为1,所以我们可以理解到,当slow和fast在环中,如果slow和fast的位置不同,当slow每走一步,fast走两步,那么fast和slow之间的距离每次就会少一步,以此往复,fast和slow终将相遇。

如果fast每次走三步甚至n步呢?

根据以上我们可以知道,当slow和fast进入环后,fast每次走三步,slow每次走一步,那么fast和slow的距离就会每次少两步,那么如果再进行下一步之前fast恰好出现在slow的前一个,那么下一步过后,fast就会把slow略过,进而可能导致死循环,永远也无法找到。

1.2 完整代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    
    if(head==NULL||head->next==NULL)
        return false;
    struct ListNode*slow=head;
    struct ListNode*fast=head->next;
    while(fast&&fast->next)
    {
        if(slow==fast)
        {
            return true;
        }
        slow=slow->next;
        
        fast=fast->next->next; 
    }
    return false;
}

2  求环形链表的入口节点。

这个问题是让我们找到从头结点开始进入到环链表的第一个节点。也是就是图上的2的结点。

2.1 方法一

定义慢指针和快指针,如果存在环链表,则分割快指针和慢指针的相交位置。

此时将问题转换成了两条单链表相交求交点的问题。(后续更新)。

2.2 方法二

假设头节点到环入口节点的距离为L,入口节点到相遇结点距离为X,假设环周长为C。

如果我们算slow和fast到相遇走过的步数的话,我们可以得到:

所以如果要找环入口头结点,我们只需要用一个指针phead从头结点开始遍历,一个指针从meet的地方继续向下走,一步一步的,由于meet在环内,所以meet走(N-1)C的距离之后还在原处,所以当meet等于phead的时候,这个位置就是环入口节点。

完整代码 

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    if(head==NULL||head->next==NULL)
        return NULL;
    struct ListNode*slow=head;
    struct ListNode*fast=head;
    struct ListNode*meet=NULL;
    while(fast&&fast->next)
    {
        
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            meet=slow;
            break;
        }
    }
    if(meet==NULL)
    {
        return NULL;
    }
    slow=head;
    while(slow)
    {
        if(slow==meet)
        {
            return meet;
        }
        slow=slow->next;
        meet=meet->next;
    }
    return NULL;
}
  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 环形链表的约瑟夫问题是指给定一个环形链表,从链表中的某个节点开始,按照一定规则进行报数并删除节点,直到所有节点都被删除。具体的解决方法是使用一个不带头结点的循环链表来处理。首先构建一个有n个节点的单循环链表,然后从指定的节点开始,按照规定的报数规则进行计数,当计数到达指定数值m时,删除对应的节点。然后从被删除节点的下一个节点重新开始计数,直到最后一个节点被删除,算法结束。遍历环形链表可以通过一个辅助指针curBoy来实现,通过一个while循环遍历链表,直到curBoy.next等于链表的头节点结束。生成一个出圈顺序可以通过创建一个辅助指针helper来实现,首先让helper指针移动m-1次,然后将指向的节点出圈。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [用环形链表解决约瑟夫问题](https://blog.csdn.net/yunhech/article/details/107444728)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【数据结构+算法环形链表——约瑟夫环(Josephu)问题](https://blog.csdn.net/m0_45097186/article/details/104227805)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值