單鏈表判環判相交綜合題

題目

給定兩個單鏈表的頭節點head1和head2,單鏈表可能有環,也可能無環。如何判斷兩個鏈表是否相交?相交的話返回相交的第一個節點,不想交的話返回NULL。

要求:如果鏈表1的長度爲N,鏈表2的長度爲M,時間複雜度O(N+M),額外空間複雜度O(1)。


分析:

  1. 首先我們先判定兩個鏈表是否有環,如果只有其中一個鏈表有環,一個鏈表無環,那證明這兩個鏈表不會相交。然後再分成都有環和無環情況分別分析。
  2. 都無環的情況:先求得每一鏈表的環的入口節點loop1和loop2。可參見

http://blog.csdn.net/u013616945/article/details/75315940

代碼如下:

 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;
    }
  1. 都有環的情況下:有如下三種可能

這裏寫圖片描述

  • 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;
    }
}

輸出:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章