leetcode 160. Intersection of Two Linked Lists

来源:互联网 发布:网络零售平台有哪些 编辑:程序博客网 时间:2024/05/12 15:31

Descrpition

Write a program to find the node at which the intersection of two singly linked lists begins.

For example, the following two linked lists:

A: a1 → a2

c1 → c2 → c3

B: b1 → b2 → b3
begin to intersect at node c1.

Notes:

If the two linked lists have no intersection at all, return null.
The linked lists must retain their original structure after the function returns.
You may assume there are no cycles anywhere in the entire linked structure.
Your code should preferably run in O(n) time and use only O(1) memory.
Credits:
Special thanks to @stellari for adding this problem and creating all test cases.

My solution

突破口:链表的交点特点是什么呢?
回想前面练习中检测环的问题, 这里的突破口也应该围绕点在存在交点的跑道上运行会有怎样的特点来突破. 自然的想到把尾部和A/B的头连起来,形成了环, 但是, 采取旧策略runner和walker相遇的地方不一定是交点位置, 卡死在这有点误导的思路上了.
查看Discuss网友代码, 明白思路是构造成两个环, A尾接B头, B尾接A头, 这样的话两个环是等长度!! 这点很重要, 同时因为a,b 两个遍历指针的速度一致(都为1), 而二者起始不同, 所以a,b永远是一前一后, 但由于两个环大小不同, 所以终究会相遇. 所以到这里理解为, 思路是在一个含有交叉点的”8”字形环上, 两个速度相同的a,b 终究会相遇在交点上. 所以有如下代码:

/** * Definition for singly-linked list. * struct ListNode { *     int val; *     ListNode *next; *     ListNode(int x) : val(x), next(NULL) {} * }; */#include "tree.h"class Solution {public:    /// 明白思路之后自己写的code;实际上也是跑不通的,进入死循环//    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {//        if(!headA||!headB) return NULL;//        ListNode *a = headA;//        ListNode *b = headB;//        while (a != b) {//            if (!a->next) a = headB;//            else a = a->next;//            if (!b->next) b = headA;//            else b = b->next;//        }//        return a==b?a:NULL;//    }    /// Discuss 网友代码如下,仔细对比自己的和别人的,发现问题所在    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB)    {        ListNode *p1 = headA;        ListNode *p2 = headB;        if (p1 == NULL || p2 == NULL) return NULL;        while (p1 != NULL && p2 != NULL && p1 != p2) {            p1 = p1->next;            p2 = p2->next;            //            // Any time they collide or reach end together without colliding            // then return any one of the pointers.            //            if (p1 == p2) return p1;            //            // If one of them reaches the end earlier then reuse it            // by moving it to the beginning of other list.            // Once both of them go through reassigning,            // they will be equidistant from the collision point.            //            if (p1 == NULL) p1 = headB;            if (p2 == NULL) p2 = headA;        }        return p1;    }};int main() {    Solution s;    ListNode *l1 = new ListNode(1);    ListNode *l2 = new ListNode(2);    ListNode *l3 = new ListNode(3);    ListNode *l4 = new ListNode(4);    ListNode *l5 = new ListNode(5);    ListNode *l6 = new ListNode(6);    l1->next = l2;    l2->next = l3;    l3->next = l4;    l5->next = l6;//    l6->next = l3;    ListNode *l = s.getIntersectionNode(l1, l5);    return 0;}

实际上, 我的思路有很大失误的. 因为上文中的”总会相遇”准确的说, 是在一次首尾接壤之后必定会相遇, 这时a,b 都跑了同样长度的路径, 必定在交点处相遇. 也就是基本思路变成了, 让a,b 跑过相同的距离, 必定在交点处相遇, 这里的交点也就是终点.
我的代码是陷入了死循环, 因为我先判断next是否为NULL, 代码运行中永远不会让a,b 变为NULL, 然而不存在公共交点的两个链表, 在首尾相接,一次遍历之后, 终点也是一致的 : NULL

Discuss

牛x网友的5行 C++ code

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {    ListNode *cur1 = headA, *cur2 = headB;    while(cur1 != cur2){        cur1 = cur1?cur1->next:headB;        cur2 = cur2?cur2->next:headA;    }    return cur1;}

注意cur1和cur2 是允许取NULL的(因为判断的不是cur1->next?.. : ..), 因为NULL是无交点链表的终点!!!