劍指Offer——(36)兩個鏈表的第一個公共結點

題目描述:

輸入兩個鏈表,找出它們的第一個公共結點。

實現如下:

//節點結構體定義
struct ListNode 
{
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

方法一

//利用兩個棧,從頭開始遍歷兩個鏈表,將其節點的地址分別存入兩個棧中
//最終鏈表尾在棧頂
//依次出棧,記錄公共節點的地址,最後的值就是兩個鏈表的第一個公共節點
//注意
//1.判斷鏈表是否存在
//2.有可能不存在公共節點
//3.兩個鏈表有可能不一樣長
class Solution 
{
public:
    ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2) 
    {
        //防禦性動作,判斷鏈表是否存在
        if (pHead1 == NULL || pHead2 == NULL) return NULL;

        stack<ListNode*> p1Stk;
        stack<ListNode*> p2Stk;
        while (pHead1 != NULL)//遍歷pHead1鏈表,記錄節點地址併入棧
        {
            p1Stk.push(pHead1);
            pHead1 = pHead1->next;
        }
        while (pHead2 != NULL)//遍歷pHead2鏈表,記錄節點地址併入棧
        {
            p2Stk.push(pHead2);
            pHead2 = pHead2->next;
        }
        ListNode* tmp = NULL;//記錄公共節點的地址
        while (!p1Stk.empty() && !p2Stk.empty())//有可能出現不存在公共節點的情況
        {
            if (p1Stk.top() == p2Stk.top())//棧頂元素值相等
            {
                tmp = p1Stk.top();//記錄值
                p1Stk.pop();//出棧頂元素
                p2Stk.pop();//出棧頂元素
                continue;
            }
            else//如果棧頂元素不相等,則終止循環,return公共節點
                return tmp;
        }
        return tmp;//有可能出現不存在公共節點的情況
    }
};

方法二

//方法一中使用了輔助內存空間,使得空間複雜度爲O(m+n)
//方法二中保證遍歷鏈表的指針從相同個數的節點開始遍歷,即讓兩個鏈表的長度變得一樣
//第一次遍歷計算出兩個鏈表的長的
//第二次遍歷,讓長的鏈表先移動差值個節點,然後兩個鏈表在一同開始遍歷
class Solution
{
public:
    ListNode* FindFirstCommonNode(ListNode* pHead1, ListNode* pHead2)
    {
        //防禦性動作
        if (pHead1 == NULL || pHead2 == NULL) return NULL;
        int node1Num = 0;//記錄pHead1的長度
        int node2Num = 0;//記錄pHead2的長度
        ListNode* p1 = pHead1;
        ListNode* p2 = pHead2;

        while (p1 != NULL)//第一次遍歷
        {
            ++node1Num;
            p1 = p1->next;
        }

        while (p2 != NULL)//第二次遍歷
        {
            ++node2Num;
            p2 = p2->next;
        }

        p1 = pHead1;
        p2 = pHead2;
        int tmp = node1Num - node2Num;//計算兩個鏈表的長度差
        while (tmp > 0)//pHead1長時,先移動
        {
            p1 = p1->next;
            --tmp;
        }
        while (tmp < 0)//pHead2長時,先移動
        {
            p2 = p2->next;
            ++tmp;
        }
        while (p1 != p2)//之後開始一同移動
        {
            p1 = p1->next;
            p2 = p2->next;
        }
        return p1;//有可能不存在公共節點
    }
};

方法三

//大神做法!!!
//代碼如此簡單。。但想法如此巧妙!!!
//不再利用第一次遍歷,來記錄兩個鏈表的長度
//而是利用類似判斷鏈表是否有環的思路(不知道這樣理解對不對)
//當沒有公共節點時,依舊返回NULL                                                                                                                                            
class Solution 
{
public:
    ListNode* FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2) 
    {
        ListNode *p1 = pHead1;
        ListNode *p2 = pHead2;
        while (p1 != p2) 
        {
            p1 = (p1 == NULL ? pHead2 : p1->next);
            p2 = (p2 == NULL ? pHead1 : p2->next);
        }
        return p1;
    }
};
發佈了107 篇原創文章 · 獲贊 36 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章