柳小葱的力扣之路——树的遍历

x33g5p2x  于2022-02-07 转载在 其他  
字(3.4k)|赞(0)|评价(0)|浏览(388)

♦️今天我们来学习树的遍历,这几道题,主要涉及的树的遍历有前、中、后遍历层序遍历,今天我们来看看几道题,对往期内容感兴趣的同学可以查看👇:

  • 链接: 柳小葱的力扣之路——动态规划详解.

🍭今天我们主要讲中序遍历,因为中序遍历和二叉搜索树有着很大的联系,应用较为广泛,当然我也会演示如何实现前、后序遍历和层序遍历。

1. 前、中、后序遍历

1.1 力扣94. 二叉树的中序遍历

给定一个二叉树的根节点 root ,返回它的 中序 遍历。
输入:root = [1,null,2,3]
输出:[1,3,2]

题解(2种方式)

  1. 第一种,我们采用递归的方式,左右子树分别递归,进行中序遍历
  2. 第二种,我们采用栈的方式,根节点的左节点不为空,则押入栈中,直到左节点为空,出栈,接着判断该节点的右节点是否存在左子树,依次循环。
  1. #1. 递归实现中序
  2. def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
  3. res=[]
  4. if not root:#递归结束条件
  5. return res
  6. #左支
  7. res.extend(self.inorderTraversal(root.left))#写在类里要加self.
  8. #中间节点
  9. res.append(root.val)
  10. #右支
  11. res.extend(self.inorderTraversal(root.right))
  12. return res
  13. #2. 栈实现中序
  14. def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
  15. stack=[]
  16. res=[]
  17. #当栈内有节点或根节点不为空,则继续循环。
  18. while stack or root:
  19. #节点不为空时一直找左子树最左边的元素。
  20. while root:
  21. stack.append(root)
  22. root=root.left
  23. #找到后出栈加入数组作为第一个元素
  24. root=stack.pop()
  25. res.append(root.val)
  26. #然后看该节点是否有右支。
  27. root=root.right
  28. return res

在这道题中,我们顺便说一下递归方式实现二叉树的前序和后续遍历。(其实就是换一下位置)

  1. #前序遍历
  2. def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
  3. res=[]
  4. if not root:#递归结束条件
  5. return res
  6. #中间节点
  7. res.append(root.val)
  8. #左支
  9. res.extend(self.inorderTraversal(root.left))#写在类里要加self.
  10. #右支
  11. res.extend(self.inorderTraversal(root.right))
  12. return res
  13. #后续遍历
  14. def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
  15. res=[]
  16. if not root:#递归结束条件
  17. return res
  18. #左支
  19. res.extend(self.inorderTraversal(root.left))#写在类里要加self.
  20. #右支
  21. res.extend(self.inorderTraversal(root.right))
  22. #中间节点
  23. res.append(root.val)
  24. return res

1.1 力扣98. 验证二叉搜索树

根据树的遍历,我们顺势可以做完下面这道题:
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:

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

这道题我们换个角度想,既然要验证是否为有效二叉树,那就是该树的中序遍历是一个严格递增的序列,问题就变成只要判断该树的中序遍历是否严格递增即可。

题解(2种方式)

  1. 根据中序遍历的结果进行判断
  2. 在中序遍历的过程中进行判断
  1. #方法一:对中序遍历的结果进行升序排列,如果升序前和升序后结果一样,就为true
  2. def isValidBST(self, root: TreeNode) -> bool:
  3. def midorder(root):#中序遍历部分
  4. res=[]
  5. if not root:
  6. return []
  7. res.extend(midorder(root.left))
  8. res.append(root.val)
  9. res.extend(midorder(root.right))
  10. return res
  11. result=midorder(root)#返会中序遍历的对象
  12. a=result[:]#这里是用a保留一份result的副本
  13. result.sort()#result排序
  14. if len(set(a))!=len(result):#中序排序如果有重复元素则为fales
  15. return False
  16. if result==a:#如果中序排序的结果和升序排序一样,则为true
  17. return True
  18. else:#否则为false
  19. return False
  20. #方法二:在中序遍历的过程中进行判断是否是升序
  21. def isValidBST(self, root: TreeNode) -> bool:
  22. stack=[]
  23. inorder=float('-inf')
  24. #上部分的中序遍历
  25. while stack or root:
  26. while root:
  27. stack.append(root)
  28. root = root.left
  29. root = stack.pop()
  30. # 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
  31. if root.val <= inorder:
  32. return False
  33. inorder = root.val
  34. root = root.right
  35. return True

2. 层序遍历

来到层序遍历,和前中后遍历方式不一样的地方在于,一个是树的广度遍历,一个是数的深度遍历。

2.1 力扣 102. 二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

题解

  • 这里的解题思路是将每层的节点放入队列中,然后每次输出该层节点个数的队列元素即可。这里有个技巧就是在将节点出队列的过程中,也将该节点的左右节点加入队列进行下一层的遍历。
  1. def levelOrder(self, root: TreeNode) -> List[List[int]]:
  2. res=[]
  3. queue=[root]
  4. if not root:#根节点为空,直接返回[]
  5. return res
  6. #队列不为空时
  7. while queue:
  8. n=len(queue)
  9. alist=[]
  10. for i in range(n):#遍历该层个数的节点
  11. node=queue.pop(0)
  12. alist.append(node.val)
  13. #同时加入下一层的左右节点。
  14. if node.left:
  15. queue.append(node.left)
  16. if node.right:
  17. queue.append(node.right)
  18. res.append(alist)
  19. resturn res

103. 二叉树的锯齿形层序遍历

给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

这道题是不是和上面普通的层序遍历很像呢?大家可以思考一下哦,给点提示:从如何实现奇数偶数层不同方向遍历开始。

题解

  1. # 利用计时器来判断遍历到哪一层了。
  2. def zigzagLevelOrder(self, root: TreeNode) -> List[List[int]]:
  3. res=[]
  4. queue=[root]
  5. j=1#初始化计数器j
  6. if not root:
  7. return res
  8. while queue:
  9. alist=[]
  10. l=len(queue)
  11. for i in range(l):
  12. node=queue.pop(0)
  13. alist.append(node.val)
  14. if node.left:
  15. queue.append(node.left)
  16. if node.right:
  17. queue.append(node.right)
  18. if j%2==1:#奇数层正常遍历
  19. res.append(alist)
  20. else:#偶数层返回遍历的逆序
  21. alist.reverse()
  22. res.append(alist)
  23. j+=1#层数+1
  24. return res

3. 参考资料

  • 力扣官网(LeetCode)
  • 算法小抄
  • python数据结构

相关文章