算法-leetcode-142. 环形链表 II

题目链接 142. 环形链表 II
本题的解法主要是两种,都是在141题判断是否有环的基础上进行的

方法1:hash法

  1. 遍历链表,所有节点都放在hash中
  2. 如果一个节点已经在hash中存在,说明该节点就是环的连接点
    本方法时间复杂度为O(n),因为用到一个hash结构,所以空间复杂度为O(n),

方法2:双指针法(快慢指针法)

在141中已经知道快慢指针会在环中相遇,入下图:

在环上相遇后,记录第一次相遇点为Pos,连接点为Join,假设头结点到连接点的长度为LenA,连接点到第一次相遇点的长度为x,环长为R。

  • 第一次相遇时,slow走的长度 S = LenA + x;
  • 第一次相遇时,fast走的长度 2S = LenA + n*R + x;
  • 所以可以知道,LenA + x = nR;  LenA = nR -x;
    对于 LenA = nR -x 这个公式,可以得到 第一次碰撞点Pos到连接点Join的距离=头指针到连接点Join的距离,因此,分别从第一次碰撞点Pos、头指针head开始走,相遇的那个点就是连接点。* (指针a走了LenA的距离,此时指针b走了nR -x的距离,nR 表示在换上走了n圈,位置还是在Pos,但是-x表示要从Pos位置后退x个位置,刚好到达Join这个连接点)
    代码如下:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    if (!head || !head->next) {
        return NULL;
    }
    //这里要注意,初始化时,慢指针指向头指针的下一个节点,快指针指向头指针后两个节点的位置
    //如果慢指针初始为head,快指针初始为head->next,虽然能找到一个碰撞点,但是后面找环入口节点的时候就会有问题,无法遇到,进入死循环
    struct ListNode *slow = head->next, *fast = head->next->next;
    while (slow != fast) {
        if (!fast || !fast->next) {
            return NULL;
        }
        slow = slow->next;
        fast = fast->next->next;
    }
    
     slow = head;
     int pos = 0;
     while (slow != fast) {
         pos++;
         slow = slow->next;
         fast = fast->next;
     }
     return fast;
}

猜你喜欢

转载自www.cnblogs.com/xiaoshuai666/p/11391915.html