日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

数据结构 - 二叉树

發(fā)布時(shí)間:2023/12/4 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构 - 二叉树 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

二叉樹的遍歷思想在很多算法中體現(xiàn)。快速排序的本質(zhì)是二叉樹的先根遍歷,歸并排序和分治算法本質(zhì)是后根遍歷。
"二叉樹題目的難點(diǎn)在于如何通過(guò)題目的要求思考出 每一個(gè)節(jié)點(diǎn)需要做什么,在什么時(shí)候做 "。

文章目錄

  • 1.翻轉(zhuǎn)二叉樹
  • 2.填充二叉樹節(jié)點(diǎn)的右側(cè)指針*
  • 3.將二叉樹按先根順序展開成鏈表(即只有右子節(jié)點(diǎn)的樹)
  • 4.根據(jù)數(shù)組構(gòu)建最大二叉樹
  • 5.通過(guò)前序和中序遍歷結(jié)果構(gòu)造二叉樹
  • 6.尋找相同子樹——序列化*
  • 7.BST中第k大的元素
  • 8.BST轉(zhuǎn)換為累加樹
  • 9.判斷BST是否合法
  • 10.刪除BST指定節(jié)點(diǎn)**
  • 11.路徑總和III
  • 12.合并二叉樹
  • 13.BST轉(zhuǎn)雙向有序循環(huán)鏈表*
  • 14.樹的子結(jié)構(gòu)

1.翻轉(zhuǎn)二叉樹

寫遞歸函數(shù)時(shí)首先確定遞歸出口。
本題可以使用先根遍歷,也可以使用后根遍歷。
每個(gè)節(jié)點(diǎn)應(yīng)該讓自己的左右子樹翻轉(zhuǎn)后,交換其位置。也可以先交換再翻轉(zhuǎn)。

# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def invertTree(self, root):""":type root: TreeNode:rtype: TreeNode"""# 遞歸出口if root is None:return None# 后根left_node = self.invertTree(root.left)right_node = self.invertTree(root.right)root.right = left_noderoot.left = right_nodereturn root

2.填充二叉樹節(jié)點(diǎn)的右側(cè)指針*

leetcode116題。拉不拉東的經(jīng)典遞歸法:
每個(gè)節(jié)點(diǎn)應(yīng)該把左子節(jié)點(diǎn)指向右子節(jié)點(diǎn),并且當(dāng)該節(jié)點(diǎn)next不為空時(shí),其右子節(jié)點(diǎn)指向next的左子節(jié)點(diǎn)。

""" # Definition for a Node. class Node(object):def __init__(self, val=0, left=None, right=None, next=None):self.val = valself.left = leftself.right = rightself.next = next """class Solution(object):def connect(self, root):""":type root: Node:rtype: Node"""if root is None:return Noneself.connectTowNodes(root.left, root.right)return rootdef connectTowNodes(self, node1, node2):# 遞歸出口if node1 is None:returnnode1.next = node2self.connectTowNodes(node1.left, node1.right)self.connectTowNodes(node2.left, node2.right)self.connectTowNodes(node1.right, node2.left)

另一種巧妙的思路,避免了新建方法。利用先根遍歷的特性,從上往下進(jìn)行連接。當(dāng)前節(jié)點(diǎn)的next不為None時(shí),必有右兄弟,需要將右兄弟的左子節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)連接。

""" # Definition for a Node. class Node(object):def __init__(self, val=0, left=None, right=None, next=None):self.val = valself.left = leftself.right = rightself.next = next """class Solution(object):def connect(self, root):""":type root: Node:rtype: Node"""if root is None or root.left is None:return root# 連接相同父親的節(jié)點(diǎn)root.left.next = root.rightif root.next is not None:root.right.next = root.next.leftself.connect(root.left)self.connect(root.right)return root

3.將二叉樹按先根順序展開成鏈表(即只有右子節(jié)點(diǎn)的樹)

題目要求:

每個(gè)節(jié)點(diǎn)應(yīng)該把自己的左右子樹拉直,并把拉直的左子樹放到原來(lái)右子樹的位置,把拉直的右子樹接在拉直的左子樹下面。

# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def flatten(self, root):""":type root: TreeNode:rtype: None Do not return anything, modify root in-place instead."""# 遞歸出口if root is None:return None# 先拉平左右子樹left_flatten = self.flatten(root.left)right_flatten = self.flatten(root.right)# 后根遍歷,處理根節(jié)點(diǎn)的位置# 按照先根遍歷順序,將左子樹的結(jié)果,拼接在根節(jié)點(diǎn)的右邊,并將右子樹的結(jié)果追加在后面root.right = left_flattenroot.left = Noneif (left_flatten is None):root.right = right_flattenelse:while (left_flatten.right is not None):left_flatten = left_flatten.rightleft_flatten.right = right_flattenreturn root

4.根據(jù)數(shù)組構(gòu)建最大二叉樹

  • 最大二叉樹:左子樹是由數(shù)組中,最大元素左邊的數(shù)字構(gòu)成的最大二叉樹。
  • 先根遍歷,思想類似于快速排序。

還是要明白每個(gè)節(jié)點(diǎn)該干什么,什么時(shí)候干。
每個(gè)節(jié)點(diǎn)應(yīng)該找到數(shù)組的最大元素,將左右數(shù)組分別送給左右子樹。

class Solution(object):def constructMaximumBinaryTree(self, nums):""":type nums: List[int]:rtype: TreeNode"""if len(nums) == 0:return None# 尋找最大值下標(biāo)max_idx = nums.index(max(nums))return TreeNode(nums[max_idx], self.constructMaximumBinaryTree(nums[: max_idx]), self.constructMaximumBinaryTree(nums[max_idx + 1: ]))

5.通過(guò)前序和中序遍歷結(jié)果構(gòu)造二叉樹

  • 前序的第一個(gè)元素為整棵樹的根節(jié)點(diǎn),中序遍歷中,根節(jié)點(diǎn)左側(cè)元素構(gòu)成左子樹,右側(cè)元素構(gòu)成右子樹,遞歸構(gòu)造即可。
    知道這個(gè)規(guī)律后很簡(jiǎn)單,和4幾乎完全一致。
# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def buildTree(self, preorder, inorder):""":type preorder: List[int]:type inorder: List[int]:rtype: TreeNode"""# 遞歸出口length = len(preorder)if length == 0:return None# 確定左右子樹的前序、中序序列root_val = preorder[0]root_inoreder_index = inorder.index(root_val)left_node_num = root_inoreder_index # 左子樹的節(jié)點(diǎn)數(shù)# 構(gòu)造左右子樹left_tree = self.buildTree(preorder[1:left_node_num+1], inorder[:root_inoreder_index])right_tree = self.buildTree(preorder[1+left_node_num:], inorder[root_inoreder_index+1:])# 指向左右子樹return TreeNode(val=root_val, left=left_tree, right=right_tree)

6.尋找相同子樹——序列化*

  • 大致思路是,采用后根遍歷,自底向上進(jìn)行(因?yàn)橐戎赖讓拥慕Y(jié)構(gòu),才能判斷有無(wú)相同子樹)。
  • 既然比較“相同”,需要設(shè)置備忘錄,記錄已經(jīng)見過(guò)的樹的結(jié)構(gòu)。
  • 最后通過(guò)的做法,引入序列化,字符串比較替換遞歸的節(jié)點(diǎn)比較。
class Solution(object):def findDuplicateSubtrees(self, root):""":type root: TreeNode:rtype: List[TreeNode]"""# 尋找重復(fù)子樹,需要自底向上進(jìn)行,采用后根遍歷# 每個(gè)節(jié)點(diǎn)需要將自己的左右子樹記錄待查,如果重復(fù)則添加到輸出結(jié)果res = [] # 最終結(jié)果,存放(樹,次數(shù),節(jié)點(diǎn))self.find(root, res)subtrees = []for i in range(len(res)):if res[i][1] > 1:subtrees.append(res[i][2])return subtreesdef find(self, node, result):# 遞歸出口if node is None:returnself.find(node.left, result)self.find(node.right, result)# 后根# 判斷是否見過(guò)該子樹node_sequence = self.transferToSequence(node)for i in range(len(result)):if result[i][0] == node_sequence:old_time = result[i][1]result[i] = (node_sequence, old_time+1, node)return# 沒(méi)見過(guò),將其加入到字典中result.append((node_sequence, 1, node))# 序列化二叉樹def transferToSequence(self, node):if node is None:return "#"return str(node.val) + "," + self.transferToSequence(node.left) + "," + self.transferToSequence(node.right)

7.BST中第k大的元素

凡提及BST,一定用到的思路是:
BST左子樹的節(jié)點(diǎn)都小于當(dāng)前節(jié)點(diǎn),右子樹節(jié)點(diǎn)都大于當(dāng)前節(jié)點(diǎn)。
BST的中序遍歷是升序序列。

class Solution(object):cnt = 0def kthLargest(self, root, k):""":type root: TreeNode:type k: int:rtype: int"""self.cnt = 0def findK(node, k):if node is None:return Noner = findK(node.right, k)if r is not None: # 右子樹某節(jié)點(diǎn)為第k大return rself.cnt += 1if self.cnt == k: # 當(dāng)前節(jié)點(diǎn)數(shù)為第k大return node.vall = findK(node.left, k) # 左子樹某節(jié)點(diǎn)為第k大 return lreturn findK(root, k)

8.BST轉(zhuǎn)換為累加樹

  • 題目要求:給出BST的根節(jié)點(diǎn),該樹的節(jié)點(diǎn)值各不相同,請(qǐng)你將其轉(zhuǎn)換為累加樹,使每個(gè)節(jié)點(diǎn) node 的新值等于原樹中大于或等于 node.val 的值之和。
  • 從題目得知,累加操作要從最大的元素開始,直到最小的元素。
  • 很快想到要用 右子樹->根節(jié)點(diǎn)->左子樹 的中根遍歷順序解決問(wèn)題。
class Solution(object):temp = 0def convertBST(self, node):""":type root: TreeNode:rtype: TreeNode"""# 對(duì)于根節(jié)點(diǎn),首先處理右子樹,改變根節(jié)點(diǎn)值,再處理左子樹# 左子樹需要根節(jié)點(diǎn)的信息!所以需要先右再左if node is None:return Noneself.convertBST(node.right)self.temp += node.valnode.val = self.tempself.convertBST(node.left)return node

9.判斷BST是否合法

最簡(jiǎn)單的思路是中序遍歷檢查是否遞增,只需記錄前一個(gè)節(jié)點(diǎn)的值
需要自底向上進(jìn)行,后根遍歷。
對(duì)于每個(gè)節(jié)點(diǎn),保證自己的左右子樹為BST,同時(shí)節(jié)點(diǎn)大于左子樹最大值,小于右子樹最小值。

class Solution(object):def isValidBST(self, root):""":type root: TreeNode:rtype: bool"""# 保證每個(gè)節(jié)點(diǎn)大于左子樹最大值,小于右子樹最小值def findLeftMax(node):if node is None or node.left is None:return Nonenode = node.leftwhile (node.right is not None):node = node.rightreturn node.valdef findRightMin(node):if node is None or node.right is None:return Nonenode = node.rightwhile (node.left is not None):node = node.leftreturn node.valif root is None:return Trueelse:l = findLeftMax(root)r = findRightMin(root)l = (root.val - 1) if l is None else lr = (root.val + 1) if r is None else r return l < root.val and r > root.val and self.isValidBST(root.left) and self.isValidBST(root.right)

10.刪除BST指定節(jié)點(diǎn)**

對(duì)于不具有子節(jié)點(diǎn)的待刪除點(diǎn),直接刪除即可。
具有單個(gè)子節(jié)點(diǎn),用子節(jié)點(diǎn)替換。
具有兩個(gè)子節(jié)點(diǎn),需要用左子樹的最大節(jié)點(diǎn)/右子樹的最小節(jié)點(diǎn)替換。

利用節(jié)點(diǎn)作為返回值,減少冗余代碼。

# Definition for a binary tree node. # class TreeNode(object): # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution(object):def deleteNode(self, root, key):""":type root: TreeNode:type key: int:rtype: TreeNode"""# 不存在待刪除節(jié)點(diǎn)if root is None:return None# 先根遍歷# 分情況討論:待刪節(jié)點(diǎn)無(wú)子節(jié)點(diǎn)、有一個(gè)子節(jié)點(diǎn)、有兩個(gè)子節(jié)點(diǎn)elif root.val == key:if root.left is None and root.right is None:return Noneelif root.left is not None and root.right is None:return root.leftelif root.left is None and root.right is not None:return root.rightelse:# 有兩個(gè)子節(jié)點(diǎn)時(shí),讓左側(cè)最大或右側(cè)最小的節(jié)點(diǎn)替代該節(jié)點(diǎn)# 這里選擇用左側(cè)最大的節(jié)點(diǎn)left_node = root.leftleft_node_father = rootwhile (left_node.right is not None):left_node_father = left_nodeleft_node = left_node.rightroot.val = left_node.valroot.left = self.deleteNode(root.left, root.val) # ***精髓***# 當(dāng)前節(jié)點(diǎn)不是待刪節(jié)點(diǎn),交給子樹處理elif root.val > key:root.left = self.deleteNode(root.left, key)else:root.right = self.deleteNode(root.right, key)return root

11.路徑總和III

給定一個(gè)二叉樹的根節(jié)點(diǎn) root ,和一個(gè)整數(shù) targetSum ,求該二叉樹里節(jié)點(diǎn)值之和等于 targetSum 的 路徑 的數(shù)目。
路徑 不需要從根節(jié)點(diǎn)開始,也不需要在葉子節(jié)點(diǎn)結(jié)束,但是路徑方向必須是向下的(只能從父節(jié)點(diǎn)到子節(jié)點(diǎn))。

  • 使用DFS+前綴和的思路。DFS的一個(gè)明顯好處是,每條正在搜索的路徑一定符合題目中對(duì)路徑的要求
  • 將 path[0]設(shè)置為0,可以方便統(tǒng)計(jì)從根節(jié)點(diǎn)到某個(gè)節(jié)點(diǎn)的前綴和
class Solution(object):res = 0def pathSum(self, root, targetSum):""":type root: TreeNode:type targetSum: int:rtype: int"""self.res = 0path = [0] # 記錄當(dāng)前路徑的前綴和def dfs(node, targetSum):# 出口if node is None:return False# 一般情況path.append(node.val + path[-1])for i in range(len(path) - 1):if path[-1] - path[i] == targetSum:self.res += 1# 執(zhí)行選擇并撤銷if dfs(node.left, targetSum):path.pop()if dfs(node.right, targetSum):path.pop()return Truedfs(root, targetSum)return self.res--------------------------------------這樣也是可以的-----------------------------------class Solution(object):res = 0def pathSum(self, root, targetSum):""":type root: TreeNode:type targetSum: int:rtype: int"""self.res = 0path = [0] # 記錄當(dāng)前路徑的前綴和def dfs(node, targetSum):# 出口if node is None:return# 一般情況path.append(node.val + path[-1])for i in range(len(path) - 1):if path[-1] - path[i] == targetSum:self.res += 1dfs(node.left, targetSum)dfs(node.right, targetSum)path.pop()dfs(root, targetSum)return self.res

12.合并二叉樹

合并的規(guī)則是如果兩個(gè)節(jié)點(diǎn)重疊,那么將他們的值相加作為節(jié)點(diǎn)合并后的新值,否則不為 NULL 的節(jié)點(diǎn)將直接作為新二叉樹的節(jié)點(diǎn)。

class Solution(object):def mergeTrees(self, root1, root2):""":type root1: TreeNode:type root2: TreeNode:rtype: TreeNode"""if root1 is None and root2 is None:return Noneelif root1 is not None and root2 is None:return root1elif root1 is None and root2 is not None:return root2else:return TreeNode(root1.val + root2.val, self.mergeTrees(root1.left, root2.left), self.mergeTrees(root1.right, root2.right))

13.BST轉(zhuǎn)雙向有序循環(huán)鏈表*

  • 利用中序遍歷BST得到遞增序列的規(guī)則,使用全局的遍歷 head 記錄鏈表頭,pre 記錄之前的節(jié)點(diǎn)
  • 一個(gè)比較巧妙的思想:遞歸結(jié)束時(shí) pre 是最后的節(jié)點(diǎn),和 head 首尾相連
class Solution(object):head = Nonepre = Nonedef treeToDoublyList(self, root):""":type root: Node:rtype: Node"""if root is None:return Noneself.head = Noneself.pre = None# 中序遍歷樹,并執(zhí)行連接def midorder(node):# 遞歸出口if node is None:return None# 中序遍歷midorder(node.left)if self.pre is None: # 記錄首節(jié)點(diǎn)self.head = nodeelse:self.pre.right = nodenode.left = self.preself.pre = nodemidorder(node.right)midorder(root)self.head.left = self.preself.pre.right = self.headreturn self.head

14.樹的子結(jié)構(gòu)

  • 判斷判斷B是不是A的子結(jié)構(gòu)
  • 最后一行是核心:分別判斷 pRoot2 是否是以 pRoot1、pRoot1.left、pRoot1.right 為根的樹的子結(jié)構(gòu)
    HasSubTree(a, b):a中是否包含b,a不一定是首節(jié)點(diǎn)
    find(a, b):從節(jié)點(diǎn)a和b開始,a是否包含b
class Solution:def HasSubtree(self, pRoot1, pRoot2):def find(n1, n2):if not n2:return True elif not n1:return Falseelif n1.val != n2.val:return Falseelse:return find(n1.left, n2.left) and find(n1.right, n2.right)if not pRoot1 or not pRoot2:return Falsereturn find(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)

總結(jié)

以上是生活随笔為你收集整理的数据结构 - 二叉树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。