Leecode刷题笔记 二叉树

本文详细介绍了二叉树的各种操作,包括中序遍历实现、求解最大深度的两种方法(DFS和BFS)、验证二叉搜索树的正确性以及判断对称二叉树的递归与队列策略。此外,还阐述了如何进行二叉树的层序遍历,以及有序数组转化为高度平衡二叉搜索树的算法。这些内容涵盖了二叉树的基本操作和深度探索,有助于理解和掌握二叉树的性质和算法实现。
摘要由CSDN通过智能技术生成

二叉树的中序遍历

这种方法是首先从头走到尾,把根节点和各层左儿子节点全部走一遍,走到头之后此时root已经是None了。这时候再从栈里弹出一个点给root,该点其实就是root上一个访问的点,也是最底层的那个左节点。此时再看该节点是否有右儿子,如果有就把该点入栈,再看该点是否有左儿子 如果没有就再弹出一个点交给root 看他是否有右儿子 这个右儿子又是否有左儿子…总之就是先纵向访问所有左儿子,之后自底向上一个一个找其右儿子
详见https://blog.csdn.net/weixin_44033136/article/details/88636944

		temp=[]
        ans=[]
        while root or temp:
            while root: #只要节点非空
                temp.append(root) #这里要加入的是树,不是树的值
                root=root.left
            root=temp.pop()
            ans.append(root.val) #树才有val和right
            root=root.right #左节点寻找完毕
        return ans
  1. 二叉树的最大深度
    给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

说明: 叶子节点是指没有子节点的节点。

示例:
给定二叉树 [3,9,20,null,null,15,7],
在这里插入图片描述
返回它的最大深度 3 。
思路
DFS
采用递归,一直递归左右子树深度的最大值+1,递归终止条件是根节点等于0,此时return0

# 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:
     def maxDepth(self, root):
         if root==None:
             return 0
         else:
             l_h=self.maxDepth(root.left)
             r_h=self.maxDepth(root.right)
             return max(l_h,r_h) + 1

BFS
广度优先搜索,代码如下

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root:#如果root=None
            return 0
        queue = collections.deque([root])
        depth = 0
        while queue:
            n = len(queue)
            for i in range(n):
                node = queue.popleft()#从左边出栈 如果是pop()就是从右边出栈
                if node.left:
                    queue.append(node.left)#从右边入栈
                if node.right:
                    queue.append(node.right)
            depth += 1
        return depth


首先BFS是根节点进栈,再出栈,并且出栈前把该根节点的左右孩子依次进栈。再出栈一个点,以此类推。
以一棵树为[3,9,20,7,8,15,6]即3是根节点,9是3的左孩子,20是3的右孩子,7是9的左孩子,8是9的右孩子…
while的每一轮循环就遍历了一层的点。
这里首先建立队列,最开始的时候是把根节点,也就是这里的3入栈(存入queue中),此时n=1。所以此时i的取值为[0,1),接下来进入for循环,这里的意义是判断当前这一层有几个点,for就循环几次。此时令node=queue从左边出栈一个点。即nede=3 。此时queue为空。因为3有左右孩子,所以分别对queue入栈9,20。现在queue为[9,20]。此时depth+=1,depth=1。接下来进入第二轮while循环,现在在第二层。n=2,i取值为[0,2) for循环两次(即分别对3的左右孩子9 和20 进行遍历)。首先i=0,把9出栈,Node=9,再把9的左右孩子入栈,此时queue=[20,7,8] 接下来i=1,进行第二次for循环,把20出栈,Node=20,再把20的左右孩子15,6入栈,此时queue=[7,8,15,6]。此时第二轮while循环结束,depth++,depth=2.
此时第三次执行while判断,因为queue不为空,所以执行下一轮while循环,分别对[7,8,15,6]出栈后queue为空,while循环结束,输出depth=3

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

在这里插入图片描述
思路
1.递归
如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左右子树也为二叉搜索树。

这里注意上下界,以上图的样例为例,[5,1, 4,NULL,NULL,3,6]这里的4应该大于5,同时4的左儿子3不仅要小于4,同时还要大于5,因为3在根节点的右边,如果3只小于3而不大于5这棵树就不成立。具体的讲解见题解。

class Solution(object):
    def isValidBST(self, root):
        def VaildBST(root,minv=float('-inf'),maxv=float('inf')):#如果minv或maxv没有赋值就按照这里给的值赋初值
            if not root:
                return True
            val=root.val
            if val>=maxv or val<=minv: #先比较当前点的值再递归到下一层进行比较
                return False
            if not  VaildBST(root.left,minv,val):
                return False
            if not VaildBST(root.right,val,maxv):
                return False
            return True

        return VaildBST(root) #上面定义了函数 从这里开始调用该该函数 即这里是递归的开始

2.中序遍历

可以想象把二叉树的每一行横着排列,如果是二叉搜索树,后一个单元的数字一定小于前一个单元,不小于就不是二叉搜索树。所以只需要将前序遍历稍微改一下即可

Class Solution(Object):
	def isBST(self,root):
		tmp=[]#建立栈
		index=float('-inf')	#用于存储上一个元素的变量,初始为负无穷,因为是当前值要大于上一个
		while root and tmp:#如果root和tmp都为空,即根节点空了栈也空了说明整个树遍历完了
			while root:#如果root还有值说明还没遍历到树的最深处叶节点,所以一直循环向下寻找
				tmp.append(root)
				root=root.left
			root=tmp.pop()
			if root.val<=index:
				return False
			index=root.val
			root=root.right
		return True	

对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
在这里插入图片描述

方法1:递归
如果是对称的,那么这棵树的left.left一定等于right.right 同时 left.right一定等于right.left

class Solution(object):
    def isSymmetric(self, root):
        #因为每次要同时比较左右子树 所以要重写一个递归函数
        if not root:
            return True
        def compare(left,right):#因为这里牵扯到值的比较 不是单纯的true false 所以只能把递归步骤放在return 每次return 节点,就可以比较节点的值
            if not (left or right):
                return True #如果两个都为空,也是对称的,返回True
            if not (left and right):
                return False
            if left.val!=right.val:
                return False    
            return compare(left.left,right.right) and compare(left.right,right.left)
        return  compare(root.left,root.right)

方法2:队列方法
在这里插入图片描述
注意:迭代的时候空节点也会被压进去,也会占据队的Size,比如:
在这里插入图片描述
这种的,根节点会将两个null放入队列,再次遍历时就会弹出两个空,于是就不会继续往下走了,对应就是continue
如果是一个孩子节点为空,一个孩子不为空也是一样的,对应就是返回False
那么由于continue是继续下一次循环,这样循环会不会一直继续,一直append空值进来?
叶子节点的子节点都是null,所以加入队列后,再拿出来都是空的
此时会做为空判断,也就是continue 这句,但不会一直循环的
continue之后,就拿出下一个节点,然后发现下一个节点也是空的,继续continue
直到队列中所有的节点都被拿出了,队列为空,跳出循环
所以不会出现死循环
也就是说虽然循环到叶节点的时候回加入None进队,但是再继续加的话None的子节点就是不存在的,所以什么也加不进队列,循环到队列空了就结束了

class Solution(object):
	def isSymmetric(self, root):
            if not root or not (root.left or root.right):
                return True
            queue=[root.left,root.right]
            while queue:
                left=queue.pop(0) 
                right=queue.pop(0)
                if not(left or right):
                    continue
                if left.val != right.val:
                    return False
                if not (left and right):
                    return False
                queue.append(left.left)
                queue.append(right.right)
                queue.append(left.right)
                queue.append(right.left)
            return True

102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
思路
采用BFS 由于每一层都要输出,所以在循环过程中需要两个列表。tmp用于存储每层的结果,以便添加到l中,而queue是用于进出的队列。列表l用于存储最终要输出的结果。

class Solution(object):
    def levelOrder(self, root):
        if not root:
            return []
        l=[]#用于存储最终结果
        queue=collecitons.deque()
        queue.append(root)
        while queue:
            tmp=[]
            for _ in range(len(queue)):
                a=queue.popleft() #这里不能写成pop(),pop(0)是每次从0位置弹出,就是队列,pop()就是堆栈了
                tmp.append(a.val)
                if a.left:
                    queue.append(a.left)
                if a.right:
                    queue.append(a.right)
            l.append(tmp)   #append()可以一次append一个列表
        return l

108. 将有序数组转换为二叉搜索树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

在这里插入图片描述
思路
可以看出这里的数组是中序遍历的结果,只需要对中序遍历的数组还原成树即可,核心思想是整个数组的终点是整棵树的根节点,之后根节点的左右节点一定是该点两侧的子数组的中点
代码

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
        def helper(left, right):
            if left > right:
                return None

            # 总是选择中间位置左边的数字作为根节点
            mid = (left + right) // 2

            root = TreeNode(nums[mid])
            root.left = helper(left, mid - 1)#首先从这里一直往里递归,一直到走到最深处的左儿子的左儿子的左儿子......此时root.left收到return None 然后再执行当前递归层的下一行,也就是执行跟最深处的左儿子的左儿子的左儿子......在同一层的右儿子,先找该右儿子的左儿子,再找该右儿子的右儿子,直到return None,此时继续返回上一层,找倒数第二深处的右儿子。 也就是说因为root.left = helper(left, mid - 1)写在前面,所以是一直执行该递归到尽头,再倒回来一直执行root.right = helper(mid + 1, right)递归(当然这过程中也有一些节点有左儿子,所以中间也执行了root.left=...)总体来说哪个写在前面 ,就先执行哪个递归,因为是中序遍历,所以应该左节点的递归写在前面。
            root.right = helper(mid + 1, right)
            return root#不知道返回什么就看要什么,上一步root。right=返回值,所以只能是返回一个点,然后拼起来,所以只能返回root

        return helper(0, len(nums) - 1)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值