LeetCode --- 不同的二叉搜索树 解题思路与疑惑

题目:

提示: 0 <= n <= 8

BST:

二叉搜索树(Binary Search Tree,BST),又称为二叉排序树(Binary Sort Tree,BST),具有以下性质:

  1. 若左子树不为空,则左子树上所有节点的值均小于等于根节点值。
  2. 若右子树不为空,则右子树上所有节点的值均大于等于根节点值。
  3. 左、右子树也分别是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有区别吗。。。
最最最难受的是提交检验失败了。

posted @ 2020-07-24 15:44  爱吃砂糖橘的白龙  阅读(313)  评论(0编辑  收藏  举报