LeetCode 100. 相同的樹 | Python

100. 相同的樹


題目來源:力扣(LeetCode)https://leetcode-cn.com/problems/same-tree

題目


給定兩個(gè)二叉樹,編寫一個(gè)函數(shù)來檢驗(yàn)它們是否相同。

如果兩個(gè)樹在結(jié)構(gòu)上相同,并且節(jié)點(diǎn)具有相同的值,則認(rèn)為它們是相同的。

示例 1:

輸入:       1         1
          / \       / \
         2   3     2   3

        [1,2,3],   [1,2,3]

輸出: true

示例 2:

輸入:      1          1
          /           \
         2             2

        [1,2],     [1,null,2]

輸出: false

示例 3:

輸入:       1         1
          / \       / \
         2   1     1   2

        [1,2,1],   [1,1,2]

輸出: false

解題思路


由題意可知,若兩個(gè)二叉樹相同,那么兩個(gè)樹在結(jié)構(gòu)上相同,并且節(jié)點(diǎn)具有相同的值。那么,我們可以通過深度優(yōu)先搜索(DFS)、廣度優(yōu)先搜索(BFS)去判斷兩個(gè)二叉樹是否相同。

思路:DFS、BFS

深度優(yōu)先搜索(DFS)

使用深度優(yōu)先搜索,遇到的情況及分析如下:

  • 當(dāng)兩個(gè)二叉樹都空時(shí),那么可以判定兩個(gè)二叉樹相同,返回 True;
  • 當(dāng)兩個(gè)二叉樹其中一個(gè)為空,而另外一個(gè)不為空時(shí),那么兩個(gè)二叉樹一定不同的,返回 False;
  • 當(dāng)兩個(gè)二叉樹都不為空的情況下,要對節(jié)點(diǎn)的值進(jìn)行判斷。分別對兩個(gè)二叉樹的根節(jié)點(diǎn),以及根節(jié)點(diǎn)的左右子樹的值進(jìn)行判斷。若出現(xiàn)不同,則表示兩個(gè)二叉樹不同,返回 False,否則返回 True。

具體的代碼見【代碼實(shí)現(xiàn) # 深度優(yōu)先搜索】

廣度優(yōu)先搜索(BFS)

同樣的,我們也可以使用廣度優(yōu)先搜索的方法來解決這個(gè)問題,這里我們要借助輔助隊(duì)列,算法具體的過程如下:

  • 判斷兩個(gè)二叉樹是否同時(shí)為空,若是,返回 True;
  • 判斷兩個(gè)二叉樹是否其中一個(gè)為空,另一個(gè)不為空,若是,返回 False;
  • 當(dāng)兩個(gè)二叉樹都不為空時(shí),開始廣度優(yōu)先搜索,這里使用隊(duì)列,分別存儲兩個(gè)二叉樹的節(jié)點(diǎn):
    • 初始先將兩個(gè)二叉樹的根節(jié)點(diǎn)分別放入隊(duì)列中;
    • 出隊(duì),對出隊(duì)的兩個(gè)節(jié)點(diǎn)的值進(jìn)行比較:
      • 當(dāng)兩個(gè)節(jié)點(diǎn)值不同,那么二叉樹一定不同;
      • 當(dāng)兩個(gè)節(jié)點(diǎn)值相同,繼續(xù)判斷二叉樹的結(jié)構(gòu)是否相同,也就是當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)是否存在為空的情況。同時(shí)為空,判定為相同,但當(dāng)兩個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)僅有一個(gè)為空,那么二叉樹不同。
      • 當(dāng)兩個(gè)節(jié)點(diǎn)值相同,結(jié)構(gòu)也相同時(shí),將兩個(gè)節(jié)點(diǎn)的非空子節(jié)點(diǎn)分別存入隊(duì)列中。這里需要注意的是,存儲時(shí),如果子節(jié)點(diǎn)不為空,那么考慮的順序都為從左到右。

當(dāng)前面的算法執(zhí)行結(jié)束后,如果隊(duì)列都為空,那么表示兩個(gè)二叉樹是相同的;如果隊(duì)列不都為空,那么表明二叉樹的結(jié)構(gòu)不同,也就是說兩個(gè)二叉樹不同。

具體的代碼見【代碼實(shí)現(xiàn) # 廣度優(yōu)先搜索】

代碼實(shí)現(xiàn)


# 深度優(yōu)先搜索
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        
        def dfs(p, q):
            # 兩個(gè)二叉樹都為空的情況
            if p == None and q == None:
                return True
            # 兩個(gè)二叉樹只有一個(gè)為空的情況
            elif p == None or q == None:
                return False
            # 二叉樹都不為空的情況,比較值
            elif p.val == q.val:
                # 當(dāng)根節(jié)點(diǎn)的值相同時(shí),往下繼續(xù)判斷左右子樹的值
                return dfs(p.left, q.left) and dfs(p.right, q.right)
            # 值不同,返回 False
            return False
            

        return dfs(p, q)

# 廣度優(yōu)先搜索
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        from collections import deque
        # 判斷兩個(gè)二叉樹是否為空的情況
        if not p and not q:
            return True
        elif not p or not q:
            return False
        # 都不為空的情況,使用隊(duì)列,存儲二叉樹的節(jié)點(diǎn)
        # 先將兩個(gè)根節(jié)點(diǎn)入隊(duì)
        queue_p = deque([p])
        queue_q = deque([q])

        while queue_p and queue_q:
            node_p = queue_p.popleft()
            node_q = queue_q.popleft()
            
            # 比較值
            if node_p.val != node_q.val:
                return False
            # 比較結(jié)構(gòu)
            left_p, right_p = node_p.left, node_p.right
            left_q, right_q = node_q.left, node_q.right
            # 這里使用異或,直接判斷兩個(gè)為空以及其中一個(gè)為空的情況
            # ^ 相同返回 0,否則返回 1
            # 只有返回 1 的情況才會執(zhí)行語句,也就是不同返回 False
            if (not left_p) ^ (not left_q):
                return False
            if (not right_p) ^ (not right_q):
                return False
            # 值與結(jié)構(gòu)相同時(shí),當(dāng)子節(jié)點(diǎn)非空,將子節(jié)點(diǎn)按照從左到右的順序入隊(duì)
            if left_p:
                queue_p.append(left_p)
            if right_p:
                queue_p.append(right_p)
            if left_q:
                queue_q.append(left_q)
            if right_q:
                queue_q.append(right_q)
        
        # 最后需要判斷隊(duì)列是否為空
        # 如果隊(duì)列不都為空,那么表明二叉樹結(jié)構(gòu)不同
        return not queue_p and not queue_q

實(shí)現(xiàn)結(jié)果


實(shí)現(xiàn)結(jié)果 | 深度優(yōu)先搜索
實(shí)現(xiàn)結(jié)果 | 廣度優(yōu)先搜索

歡迎關(guān)注


公眾號 【書所集錄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容