題目
給定兩個單鏈表的頭節點head1和head2,單鏈表可能有環,也可能無環。如何判斷兩個鏈表是否相交?相交的話返回相交的第一個節點,不想交的話返回NULL。
要求:如果鏈表1的長度爲N,鏈表2的長度爲M,時間複雜度O(N+M),額外空間複雜度O(1)。
分析:
- 首先我們先判定兩個鏈表是否有環,如果只有其中一個鏈表有環,一個鏈表無環,那證明這兩個鏈表不會相交。然後再分成都有環和無環情況分別分析。
- 都無環的情況:先求得每一鏈表的環的入口節點loop1和loop2。可參見
代碼如下:
ListNode *getLoopNode(ListNode *head){
if(head==NULL||head->next==NULL||head->next->next==NULL){
return NULL;
}
ListNode *pSlow=head->next;
ListNode *pFast=head->next->next;
while(pSlow!=pFast){
if(pFast->next==NULL||pFast->next->next==NULL){
return NULL;
}
pSlow=pSlow->next;
pFast=pFast->next->next;
}
pFast=head;
while(pSlow!=pFast){
pSlow=pSlow->next;
pFast=pFast->next;
}
return pSlow;
}
無環的情況有兩種可能,分別如下:
這種情況的求解的基本思想如下:
先求出兩個鏈表長度的差值n,讓長鏈表先走n步,然後一起走,如果能相遇則證明兩個鏈表有相交,反之則沒有。
代碼如下:
ListNode * noLoop(ListNode *head1,ListNode *head2){
if(head1==NULL||head2==NULL){
return NULL;
}
ListNode *cur1=head1;
ListNode *cur2=head2;
int n=0;
while(cur1->next!=NULL){
n++;
cur1=cur1->next;
}
while(cur2->next!=NULL){
n--;
cur2=cur2->next;
}
if(cur1!=cur2){//最後的節點不相同直接返回false;
return NULL;
}
cur1=n>0?head1:head2;
cur2=cur1==head1?head2:head1;
n=abs(n);
while(n!=0){
n--;
cur1=cur1->next;
}
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
}
- 都有環的情況下:有如下三種可能
- case 1和case 2其實可以合併在一起處理,也就是說他們的入環節點loop1跟loop2是不相同的,那麼讓一個節點從loop1或loop2開始走,走一圈過程當中如果節點遇到loop2或loop1,則證明兩鏈表是相交的,如果走了一圈沒有相遇,則證明兩鏈表是不相交的。
- case 3類似於無環情況,基本思想都是先讓長鏈表先走兩鏈表的差值步(這裏差值步爲兩鏈表未到入環節點的差值),然後兩鏈表一起走,如果相遇,證明相交。
代碼如下:
LisNode * bothLoop(ListNode *head1,ListNode *loop1,ListNode *head2,ListNode *loop2){
ListNode *cur1=NULL;
ListNode *cur2=NULL;
if(loop1==loop2){
cur1=head1;
cur2=head2;
int n=0;
while(cur1!=loop1){
n++;
cur1=cur1->next;
}
while(cur2!=loop2){
n--;
cur2=cur2->next;
}
cur1=n>0?head1:head2;
cur2=cur1==head1?head2:head1;
n=abs(n);
while(n!=0){
n--;
cur1=cur1->next;
}
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
}else {
cur1=loop1->next;
while(cur1!=loop1){
if(cur1==loop2){
return loop1;
}
cur1=cur1->next;
}
return NULL;
}
}
總體測試代碼如下:
#include <iostream>
#include <math.h>
using namespace std;
struct ListNode{
int val;
struct ListNode *next;
ListNode(int data):val(data),next(NULL){}
};
ListNode *getLoopNode(ListNode *);
ListNode *noLoop(ListNode *,ListNode *);
ListNode *bothLoop(ListNode *,ListNode*,ListNode *,ListNode*);
ListNode *chkInter(ListNode* head1, ListNode* head2) {
// write code here
if(head1==NULL||head2==NULL)
return NULL;
ListNode *loop1=getLoopNode(head1);
ListNode *loop2=getLoopNode(head2);
if(loop1==NULL&&loop2==NULL){
return noLoop(head1,head2);
}
if(loop1!=NULL&&loop2!=NULL){
return bothLoop(head1,loop1,head2,loop2);
}
return NULL;
}
int main()
{
// 1->2->3->4->5->6->7->null
ListNode *head1=new ListNode(1);
head1->next=new ListNode(2);
head1->next->next=new ListNode(3);
head1->next->next->next=new ListNode(4);
head1->next->next->next->next=new ListNode(5);
head1->next->next->next->next->next=new ListNode(6);
head1->next->next->next->next->next->next=new ListNode(7);
//0->9->8->6->7->null
ListNode *head2=new ListNode(0);
head2->next=new ListNode(9);
head2->next->next=new ListNode(8);
head2->next->next->next=head1->next->next->next->next->next;
cout<<chkInter(head1,head2)->val<<endl;
}
ListNode *getLoopNode(ListNode *head){
if(head==NULL||head->next==NULL||head->next->next==NULL){
return NULL;
}
ListNode *pSlow=head->next;
ListNode *pFast=head->next->next;
while(pSlow!=pFast){
if(pFast->next==NULL||pFast->next->next==NULL){
return NULL;
}
pSlow=pSlow->next;
pFast=pFast->next->next;
}
pFast=head;
while(pSlow!=pFast){
pSlow=pSlow->next;
pFast=pFast->next;
}
return pSlow;
}
ListNode * noLoop(ListNode *head1,ListNode *head2){
if(head1==NULL||head2==NULL){
return NULL;
}
ListNode *cur1=head1;
ListNode *cur2=head2;
int n=0;
while(cur1->next!=NULL){
n++;
cur1=cur1->next;
}
while(cur2->next!=NULL){
n--;
cur2=cur2->next;
}
if(cur1!=cur2){//最後的節點不相同直接返回false;
return NULL;
}
cur1=n>0?head1:head2;
cur2=cur1==head1?head2:head1;
n=abs(n);
while(n!=0){
n--;
cur1=cur1->next;
}
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
}
ListNode* bothLoop(ListNode *head1,ListNode *loop1,ListNode *head2,ListNode *loop2){
ListNode *cur1=NULL;
ListNode *cur2=NULL;
if(loop1==loop2){
cur1=head1;
cur2=head2;
int n=0;
while(cur1!=loop1){
n++;
cur1=cur1->next;
}
while(cur2!=loop2){
n--;
cur2=cur2->next;
}
cur1=n>0?head1:head2;
cur2=cur1==head1?head2:head1;
n=abs(n);
while(n!=0){
n--;
cur1=cur1->next;
}
while(cur1!=cur2){
cur1=cur1->next;
cur2=cur2->next;
}
return cur1;
}else {
cur1=loop1->next;
while(cur1!=loop1){
if(cur1==loop2){
return loop1;
}
cur1=cur1->next;
}
return NULL;
}
}
輸出: