暴力解法当然可以遍历两个链表,不过time O(mn) space O(1)暂且不说,
方法一:双指针,
time O(m+n),space O(1)
可以对比判断环形链表的快慢指针法。
这种方法构思十分十分十分巧妙,假设有两个链表,链表A: 1 2 3 * # 和链表B: a b c d e * # ,可以得出相交的第一个节点为*。那么A长度为la=5,*前面有lapre=3个元素;B长度为lb=7,*前面有lbpre=5个元素;可以发现lbpre+la=lapre+lb。
因此,只要用两个指针,每次前进一个节点,当pA到达末尾让其指向headB,当pB到达末尾让其指向headA那么当遍历10次后,两个指针都刚好到达*处,因此得到结果。
同时,针对无解的情况,记录两个链表的长度m和n,并且记录遍历次数i如果i>m+n时还没有满足条件的节点,可以断定无解;或者记录到达NULL的次数,如果第三次到达NULL之前还没有解,那么则无解。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *pA=headA,*pB=headB; if(pA==NULL || pB==NULL) return NULL; int cnt=0;//记录到达链表终点的次数 while(cnt<=2){ if(pA==pB) return pA; pA=pA->next; pB=pB->next; if(pA==NULL) {cnt++;pA=headB;} if(pB==NULL) {cnt++;pB=headA;} } return NULL; } };
进阶版:因为无解的话最终pA和pB在(m+n)次执行后都会同时指向NULL,因此当pA==pB时断开循环return即可。这样可以缩短代码长度
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { ListNode *pA=headA,*pB=headB; while(pA!=pB){ pA=pA?pA->next:headB; pB=pB?pB->next:headA; } return pA; } };
方法二:
使用哈希表O(n)时间,O(n)空间
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) { unordered_map<ListNode*,int> m; ListNode *pa=headA,*pb=headB; while(pa!=NULL){ m[pa]=1;pa=pa->next; } while(pb!=NULL){ if(m[pb]==1) return pb; pb=pb->next; } return NULL; } };
方法三: