zoukankan      html  css  js  c++  java
  • 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有区别吗。。。
    最最最难受的是提交检验失败了。

  • 相关阅读:
    记ByteCTF中的Node题
    Hooks中的useState
    IntersectionObserver对象
    Service Worker的应用
    使用 SpringBoot 构建一个RESTful API
    创业和技术有什么相通的“底层逻辑”?
    SpringBoot Profiles 多环境配置及切换
    SpringBoot Logback 日志配置
    应用分层和领域模型规约
    SpringBoot 整合 MyBatis,实现 CRUD 示例
  • 原文地址:https://www.cnblogs.com/Higgerw/p/13372308.html
Copyright © 2011-2022 走看看