LeetCode0993: 二叉樹的堂兄弟節點

題目介紹

描述:

在二叉樹中,根節點位於深度 0 處,每個深度爲 k 的節點的子節點位於深度 k+1 處。

如果二叉樹的兩個節點深度相同,但父節點不同,則它們是一對堂兄弟節點。

我們給出了具有唯一值的二叉樹的根節點 root,以及樹中兩個不同節點的值 x 和 y。

只有與值 x 和 y 對應的節點是堂兄弟節點時,才返回 true。否則,返回 false。

解題思路:

遞歸算法的關鍵是要明確函數的「定義」是什麼,然後相信這個定義,利用這個定義推導最終結果。

寫樹相關的算法,簡單說就是,先搞清楚當前 root 節點該做什麼,然後根據函數定義遞歸調用子節點,遞歸調用會讓孩子節點做相同的事情。

二叉樹題目的一個難點在於如何通過題目的要求思考出每一個節點需要做什麼

二叉樹解題策略

一 遞歸 二 隊列 + 迭代 (層次遍歷) 三 棧 + 迭代 (非遞歸遍歷) 四 其它

三種基本的遍歷方式,都可以用遞歸來實現。寫遞歸算法的時候,需要注意遞歸退出條件以及遞歸操作的表達。

自己的解法實現

def isCousins4(self, root, x, y):
        if not root: return []
        stack = [root]
        while stack:
            counter = 0
            for _ in range(len(stack)):
                node = stack.pop(0)
                if node.left and node.right and ((node.left.val == x and node.right.val == y) or (node.left.val == x and node.right.val == y)):
                    return False
                if node.val == x or node.val == y:
                    counter += 1
                    if counter == 2:
                        return True
                if node.left:
                    stack.append(node.left)
                if node.right:
                    stack.append(node.right)

網上比較優秀的解法

解法一

方法:標記父節點與深度 思路 當且僅當一對節點深度相同而父節點不相同時,它們是堂兄弟節點。一種非常直接的方法就是通過某種方法求出每一個節點的深度與父節點。

算法 我們用深度優先搜索標記每一個節點,對於每一個節點 node,它的父親爲 par,深度爲 d,我們將其記錄到 Hashmap 中:parent[node.val] = par 且 depth[node.val] = d。

def isCousins(self, root, x, y):
        parent = {}
        depth = {}
        def dfs(node, par = None):
            if node:
                depth[node.val] = 1 + depth[par.val] if par else 0
                parent[node.val] = par
                dfs(node.left, node)
                dfs(node.right, node)
        dfs(root)
        return depth[x] == depth[y] and parent[x] != parent[y]

解法二

方法1——深度優先搜索 輸出x和y的深度以及它們的父結點, 然後按照題意比較即可

def __init__(self):
        self.d = 0
        self.node = TreeNode()

    def isCousins2(self, root, x, y):
        def dfs(node, num, tmp):
            if not node: return
            tmp += 1
            if (node.left and node.left.val == num) or (node.right and node.right.val == num):
                self.d = tmp + 1
                self.node = node
                return
            dfs(node.left, num, tmp)
            dfs(node.right, num, tmp)
        dfs(root, x, 0)
        dx, xf = self.d, self.node

        dfs(root, y, 0)
        dy, yf = self.d, self.node

        if dx == dy and xf.val != yf.val:
            return True
        return False

解法三

哈希+BFS

def isCousins3(self, root, x, y):
        queue, hm = [(root, None)], {}  # BFS, 每層掃描完後考察是否找到其中一個點(若找到則跳出)
        while queue and not (x in hm or y in hm):
            n = len(queue)
            for i in range(n):  # 掃描每一層
                node, parent = queue.pop(0)
                if node:  # 把當前節點作爲父節點信息往下傳
                    queue += [(node.left, node), (node.right, node)]
                    hm[node.val] = parent  # 直接哈希記錄父節點
        return (x in hm and y in hm) and hm[x] != hm[y]  # 同一層且父節點不同

相關知識總結和思考

相關知識:

BFS:廣度/寬度優先。其實就是從上到下,先把每一層遍歷完之後再遍歷一下一層。

可以使用Queue的數據結構。我們將root節點初始化進隊列,通過消耗尾部,插入頭部的方式來完成BFS。

二叉搜索樹(BST)的特性:

  1. 若它的左子樹不爲空,則所有左子樹上的值均小於其根節點的值
  2. 若它的右子樹不爲空,則所有右子樹上的值均大於其根節點的值
  3. 它的左右子樹也分別爲二叉搜索樹

遞歸與迭代的區別

遞歸:重複調用函數自身實現循環稱爲遞歸; 迭代:利用變量的原值推出新值稱爲迭代,或者說迭代是函數內某段代碼實現循環;

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