主要分析了链表尾部有环的时候怎么处理,无环的解法参考selfboot

两个无环的链表

当链表无环时,分为有交点和无交点,而每种情况下又分为等长和不等长。当链表等长时,同时从头遍历两个链表,最晚在第一次遍历完成时就能判断并返回交点;当其不等长时,某链表遍历完成,使其指向另一个链表的头结点,在第二次遍历时就能找出相同的结点或者返回NULL。

ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)
{
    if (pHead1 == NULL || pHead2 == NULL) return NULL;
    ListNode* p1 = pHead1;
    ListNode* p2 = pHead2;
    while (p1 != p2){
        p1 = (p1 == NULL ? pHead2 : p1->next);
        p2 = (p2 == NULL ? pHead1 : p2->next);
    }
    return p1;
}

两个尾部有环的链表

需要先检索两个链表的环入口结点,即loop点。
①如果loop点相同:解法同无环的解法,只不过拼接点改为了loop点。
同loop时
②如果loop点不同:当p1点从loop出发,第一次回到loop1前,若相遇loop2,则相交,否则无交点。
不同loop时

ListNode* bothLoop(ListNode* pHead1, ListNode* loop1, ListNode* pHead2, ListNode* loop2){
    ListNode* p1 = NULL;
    ListNode* p2 = NULL;
    if (loop1 == loop2){
        while (p1 != p2){
            p1 = (p1 == loop1 ? pHead2 : p1->next); //解法同无环解法,拼接点设置为loop点即可。
            p2 = (p2 == loop1 ? pHead1 : p2->next);
        }
        return p1;
    }
    else {
        p1 = loop1->next; //当p1点从loop出发,第一次回到loop1前,若相遇loop2,则相交,否则无交点。
        while (p1 != loop1){
            if (p1 == loop2){
                return loop1;
            }
            p1 = p1->next;
        }
        return NULL;
    }
}

附上完整代码

class Solution{
    public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if (pHead == NULL || pHead->next == NULL)
            return NULL;
        ListNode* p1 = pHead->next; //慢指针,一次前进一格
        ListNode* p2 = pHead->next->next; //快指针,一次前进两格
        while (p1 != p2)
        {
            if (p2 == NULL || p2->next == NULL) //如果快指针p2走到头了,说明链表不成环
            {
                return NULL;
            }
            p1 = p1->next; //快慢前进
            p2 = p2->next->next;
        } //假如成环,会在p1、p2相遇时结束第一个while。此时p1到入口的距离等于head到入口的距离
        p2 = pHead; //让p2指向链表头部,p1位置不变。
        while (p1 != p2)
        {
            p1 = p1->next;
            p2 = p2->next;
        }
        return p1; //p1, p2每次走一步直到p1 == p2; 此时p1指向环的入口。
    }

ListNode* bothLoop(ListNode* pHead1, ListNode* loop1, ListNode* pHead2, ListNode* loop2){
    ListNode* p1 = NULL;
    ListNode* p2 = NULL;
    if (loop1 == loop2){
        while (p1 != p2){
            p1 = (p1 == loop1 ? pHead2 : p1->next);        //解法同无环解法,拼接点设置为loop点即可。
            p2 = (p2 == loop1 ? pHead1 : p2->next);
        }
        return p1;
    }
    else {
        p1 = loop1->next;                                  //当p1点从loop出发,第一次回到loop1前,若相遇loop2,则相交,否则无交点。
        while (p1 != loop1){
            if (p1 == loop2){
                return loop1;
            }
            p1 = p1->next;
        }
        return NULL;
    }
}
ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2){
    if (pHead1 == NULL || pHead2 == NULL) return NULL;
    ListNode* p1 = pHead1;
    ListNode* p2 = pHead2;
    ListNode* loop1 = EntryNodeOfLoop(pHead1);            //查询是否有环的入口结点,并返回
    ListNode* loop2 = EntryNodeOfLoop(pHead2);
    if (loop1 == NULL && loop2 == NULL){                  //链表都无环解法,最坏时间复杂度O(m + n)
        while (p1 != p2){
            p1 = (p1 == NULL ? pHead2 : p1->next);
            p2 = (p2 == NULL ? pHead1 : p2->next);
        }
        return p1;
    }
    else if (loop1 != NULL && loop2 != NULL){             //链表都有环
        return bothLoop(pHead1,loop1,pHead2,loop2);
    }
    else{                                                 //一个有环一个无环,无交点
        return NULL;
    }
}
};