LEETCODE(力扣) 142. 环形链表 II

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

链表中节点的数目范围在范围 [0, 104] 内
-105 <= Node.val <= 105
pos 的值为 -1 或者链表中的一个有效索引

自解

十分暴力的解法
用一个新链表储存所有链表的地址,依次遍历所有待查找链表的节点,将其指向的地址与新链表中储存的地址作比较。
能跑,但性能较差
image

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 //哈希表
struct ListNode1 {
      struct ListNode *address;
      struct ListNode1 *next;
  };

struct ListNode1 HashTable;
struct ListNode1 *tail=NULL;
struct ListNode1* find(struct ListNode *temp)
{
    struct ListNode1* head=HashTable.next;
    while(head!=NULL)
    {
        if(temp->next==head->address)return head;
        head=head->next;
    }
    return NULL;
}

void insert(struct ListNode *temp)
{
    struct ListNode1* newnode=(struct ListNode1*)malloc(sizeof(struct ListNode1));
    newnode->address=temp;
    newnode->next=NULL;
    tail->next=newnode;
    tail=tail->next;
}

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode1 *temp=NULL;
    HashTable.address=NULL;
    HashTable.next=NULL;
    tail=&HashTable;
    while(head!=NULL)
    {
        if((temp=find(head))!=NULL)
        {
            return head->next;
        }
        insert(head);
        head=head->next;
    }
    return NULL;
} 

力扣解

仍然是使用快慢指针
灵佬写的很清楚了
当快指针与慢指针在环中相遇时一共走了b步,设总头节点到环的头节点的节点数为a,环中的节点数为c,快指针在环中走了k圈
则2b-b=kc->b=kc(k是因为快指针一定是在节点中绕了k圈后才与慢指针相遇)
慢指针在从环节点头开始走过的距离为:b-a->kc-a(代入b=kc),也就是说此时慢指针在节点中再走a步就能到达环节点头
那我们让总节点头与慢指针同时动,两者相交时必定就在环节点的头

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 (fast == slow) { // 相遇
            while (slow != head) { // 再走 a 步
                slow = slow->next;
                head = head->next;
            }
            return slow;
        }
    }
    return NULL;
}

作者:灵茶山艾府
链接:https://leetcode.cn/problems/linked-list-cycle-ii/solutions/1999271/mei-xiang-ming-bai-yi-ge-shi-pin-jiang-t-nvsq/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

仿解

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *fast=head,*slow=head;
    while(fast&&fast->next)//等快慢指针相遇,若快指针遍历到NULL代表无环,会退出循环直接返回NULL
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow==fast)//相遇
        {
            while(head!=slow)//总头节点与慢指针同时动
            {
                head=head->next;
                slow=slow->next;
            }
            return head;//相遇后退出循环,此时相遇节点即为环节点的头节点
        }
    }
    return NULL;
}
posted @ 2025-04-28 10:37  Osen  阅读(14)  评论(0)    收藏  举报