劍指offer:兩個鏈表的第一個公共結點

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

# -*- coding: utf-8 -*-
# @Time         : 2019-07-12 22:20
# @Author       : Jayce Wong
# @ProjectName  : job
# @FileName     : findFirstCommonNode.py
# @Blog         : https://blog.51cto.com/jayce1111
# @Github       : https://github.com/SysuJayce

class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    """
    兩個單向鏈表的第一個公共節點,如果存在這樣的公共節點,那麼這兩個鏈表從該節點開始剩餘的節點都是
    一樣的。

    解法1:
    對於第一個鏈表,遍歷其所有節點,在掃描到第x個節點的時候,從第二個鏈表中遍歷所有節點,如果存在
    一個和節點x一樣的節點,那麼節點x就是第一個公共節點。
    這種解法的時間複雜度爲O(n^2)

    解法2:
    前面說到如果兩個單向鏈表存在公共節點,那麼從第一個公共節點開始到最後一個節點都是公共節點。
    因此,如果我們能從兩個鏈表的末尾節點開始遍歷,找到最後一個相同的節點,那麼這個節點就是第一個
    公共節點。但是這個單向鏈表不支持反向遍歷,因此我們可以利用棧的性質,維護兩個輔助棧,分別保存
    兩個鏈表的節點,然後每次比較這兩個輔助棧的棧頂元素。最後我們就能在O(n)的時間複雜度內解決問題。

    解法3:
    雖然解法2的時間複雜度已經很優了,但是仍需要用到輔助空間,其實藉助快慢指針的思想,我們可以避免
    這樣的額外空間開銷。先計算兩個鏈表的長度,然後先移動長鏈表的指針,使得長短鏈表的指針距離各自的
    末尾有相同的距離,然後開始同時移動兩個指針,直到出現兩指針指向的節點相同爲止,那麼這個相同節點
    就是第一個公共節點。
    """
    def FindFirstCommonNode(self, pHead1, pHead2):
        # 記錄兩個鏈表的長度
        len1 = len2 = 0
        pNode1 = pHead1
        pNode2 = pHead2
        while pNode1:
            pNode1 = pNode1.next
            len1 += 1
        while pNode2:
            pNode2 = pNode2.next
            len2 += 1

        # 確定哪個鏈表是長鏈表,哪個鏈表是短鏈表
        if len1 > len2:
            pLong = pHead1
            pShort = pHead2
        else:
            pLong = pHead2
            pShort = pHead1

        # 調整長鏈表的指針,使得長短鏈表距離各自末尾節點距離相同
        diff = abs(len1 - len2)
        for i in range(diff):
            pLong = pLong.next

        # 同時移動長短鏈表指針,當出現第一個相同節點(即第一個公共節點)的時候,返回這個節點
        while pLong:
            if pLong == pShort:
                return pLong
            pLong = pLong.next
            pShort = pShort.next

        # 如果不存在公共節點,返回空指針
        return None
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章