LeetCode --- 不同的二叉搜尋樹 解題思路與疑惑
阿新 • • 發佈:2020-07-24
題目:
提示: 0 <= n <= 8
BST:
二叉搜尋樹(Binary Search Tree,BST),又稱為二叉排序樹(Binary Sort Tree,BST),具有以下性質:
- 若左子樹不為空,則左子樹上所有節點的值均小於等於根節點值。
- 若右子樹不為空,則右子樹上所有節點的值均大於等於根節點值。
- 左、右子樹也分別是BST。
BST資料結構:
下面二叉搜尋樹的資料結構:
class TreeNode: def __init__(self, val=0): self.val = val self.left = None self.right = None
BST基本操作的程式設計(很多操作此程式用不到):
class OperationTree: # 二叉搜尋樹插入操作 def insert(self, root, val): if root == None: root = TreeNode(val) elif val < root.val: root.left = self.insert(root.left, val) elif val > root.val: root.right = self.insert(root.right, val) return root # 查詢二叉搜尋樹是否含有特定數字 def query(self, root, val): if root == None: return False elif root.val == val: return True elif val < root.val: return self.query(root.left, val) elif val > root.val: return self.query(root.right, val) # 尋找BST最小值 def findMin(self, root): if root.left: return self.findMin(root.left) else: return root # 尋找BST最大值 def findMax(self, root): if root.right: return self.findMax(root.right) else: return root # 刪除 BST的某個節點 def delNode(self, root, val): if root == None: #被刪除的節點不存在,不進行任何操作返回 #print("被刪除的節點:%d不存在!"%val) return # 左子樹遞迴刪除目標節點 if val < root.val: root.left = self.delNode(root.left, val) # 右子樹遞迴刪除目標節點 elif val > root.val: root.right = self.delNode(root.right, val) else: # 既有左子樹,又有右子樹,則需找到右子樹中的最小值節點 if root.left and root.right: temp = self.findMin(root.right) root.val = temp.val root.right = self.delNode(root.right, temp.val) # 左右子樹都為空 elif root.right == None and root.left == None: root = None # 只有左子樹 elif root.right == None: root = root.left # 只有右子樹 elif root.left == None: root = root.right return root # 中序遍歷、列印二叉搜尋樹:列印的是一個有序數列 def printTree(self, root): if root == None: return self.printTree(root.left) print(root.val, end = ' ') self.printTree(root.right)
從題目可以看到列印方式是層次優先的遍歷列印。下面是按層次遍歷列印二叉樹(包含了部分null節點的輸出)函式:
# 層次優先遍歷列印二叉樹 def LevelTree(self, root): result_list = [] # 如果根節點為空,則返回空列表 if root is None: return # 模擬一個佇列儲存節點 stack = [] # 首先將根節點入隊 stack.append(root) # 列表為空時,迴圈終止 while len(stack) != 0: length = len(stack) for i in range(length): # 判斷是否只剩下None if set(stack) == {None}: stack = [] break # 將同層節點依次出隊 top = stack.pop(0) if top is None: result_list.append('null') # print('null', end = ' ') continue if top.left is None: stack.append(None) elif top.left is not None: # 非空左孩子入隊 stack.append(top.left) if top.right is None: stack.append(None) elif top.right is not None: # 非空右孩子入隊 stack.append(top.right) result_list.append(top.val) # print(top.val, end = ' ') return result_list # 二叉樹水平遍歷的結構,儲存在列表中返回
可以寫個簡單的指令碼測試能否輸出正確的樹結構:
List = [1,2,3]
root = None
op = OperationTree()
for val in List:
root = op.insert(root, val)
print("按層次列印二叉搜尋樹:", end = ' ')
print(op.levelOrder(root))
主程式分析
後面寫的是主程式邏輯結構,思路是根據輸入的n值生成 n! 種[1,2,3,...,n]的不同的排序存入陣列,然後對陣列內每一個元素構建二叉樹並用LevelTree函式返回其結構,判斷這個結構是否已經存在過,不存在就擴充套件,存在就跳過(過濾重複輸出的結構)。
這句話的意思可以這樣理解:
n=3的情況下,[2,1,3]、[2,3,1]是二叉搜尋樹兩個不同的生成順序,但是生成的BST一樣的:
在n較大的時候,這種差別體現的尤其明顯。因此需要過濾判斷。
完整程式碼:
#coding=utf-8
import itertools
def permutation(li):
return list( itertools.permutations(li) )
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class OperationTree:
# 二叉搜尋樹插入操作
def insert(self, root, val):
if root == None:
root = TreeNode(val)
elif val < root.val:
root.left = self.insert(root.left, val)
elif val > root.val:
root.right = self.insert(root.right, val)
return root
# 層次優先遍歷列印二叉樹
def LevelTree(self, root):
result_list = []
# 如果根節點為空,則返回空列表
if root is None:
return
# 模擬一個佇列儲存節點
stack = []
# 首先將根節點入隊
stack.append(root)
# 列表為空時,迴圈終止
while len(stack) != 0:
length = len(stack)
for i in range(length):
# 判斷是否只剩下None
if set(stack) == {None}:
stack = []
break
# 將同層節點依次出隊
top = stack.pop(0)
if top is None:
result_list.append('null')
# print('null', end = ' ')
continue
if top.left is None:
stack.append(None)
elif top.left is not None:
# 非空左孩子入隊
stack.append(top.left)
if top.right is None:
stack.append(None)
elif top.right is not None:
# 非空右孩子入隊
stack.append(top.right)
result_list.append(top.val)
# print(top.val, end = ' ')
return result_list
class Solution:
def generateTrees(self, n):
op = OperationTree()
src_List = [i for i in range(1,n+1)]
tree_list = permutation(src_List) # n!個元素(輸入結構)
tree_print_list = [] # 輸出結構
for tree in tree_list:
root = None
for val in tree:
root = op.insert(root, val)
tree_print = op.LevelTree(root)
if tree_print not in tree_print_list:
tree_print_list.append(tree_print)
del root
return tree_print_list
if __name__ == "__main__":
n = int(input())
X = Solution()
print(X.generateTrees(n))
測試n=3:
測試n=4:
看起來應該是對的,可是提交leetcode遇到了麻煩:
輸出為什麼是空的而stdout是理想的輸出。。。
其次'null'與null有區別嗎。。。
最最最難受的是提交檢驗失敗了。