二叉树层序遍历
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。
需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。
使用队列实现二叉树广度优先遍历,动画如下:
##Python代码
from collections import deque
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
result = []
que = deque([root])
if not root:
return result
while que:
n = len(que)
vec = []
for i in range(n):
node = que.popleft()
vec.append(node.val)
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
result.append(vec)
return result
二叉树的翻转
思路
注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果
这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了
那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!
Python代码
递归前序翻转:
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
root.left,root.right = root.right,root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root
递归后序翻转:
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
self.invertTree(root.left)
self.invertTree(root.right)
root.left,root.right = root.right,root.left
return root
迭代法:深度优先遍历(前序遍历):
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return root
st = []
st.append(root)
while st:
node = st.pop()
node.left, node.right = node.right, node.left #中
if node.right:
st.append(node.right) #右
if node.left:
st.append(node.left) #左
return root
层序遍历
from collections import deque
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
que = deque([root])
while que:
n = len(que)
for i in range(n):
cur = que.popleft()
cur.left ,cur.right = cur.right , cur.left
if cur.left:
que.append(cur.left)
if cur.right:
que.append(cur.right)
return root
对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称
思路(递归和迭代)
递归
首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。
比较的是两个子树的里侧和外侧的元素是否相等
正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
Python 程序实现
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
return self.compare(root.left, root.right)
def compare(self, left, right):
#首先排除空节点的情况
if left == None and right != None: return False
elif left != None and right == None: return False
elif left == None and right == None: return True
#排除了空节点,再排除数值不相同的情况
elif left.val != right.val: return False
#此时就是:左右节点都不为空,且数值相同的情况
#此时才做递归,做下一层的判断
outside = self.compare(left.left, right.right) #左子树:左、 右子树:右
inside = self.compare(left.right, right.left) #左子树:右、 右子树:左
isSame = outside and inside #左子树:中、 右子树:中 (逻辑处理)
return isSame
迭代
这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。
这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历)
#使用队列
通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等,如动画所示:、
Python 代码
import collections
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
if not root:
return True
queue = collections.deque()
queue.append(root.left) #将左子树头结点加入队列
queue.append(root.right) #将右子树头结点加入队列
while queue: #接下来就要判断这这两个树是否相互翻转
leftNode = queue.popleft()
rightNode = queue.popleft()
if not leftNode and not rightNode: #左节点为空、右节点为空,此时说明是对称的
continue
#左右一个节点不为空,或者都不为空但数值不相同,返回false
if not leftNode or not rightNode or leftNode.val != rightNode.val:
return False
queue.append(leftNode.left) #加入左节点左孩子
queue.append(rightNode.right) #加入右节点右孩子
queue.append(leftNode.right) #加入左节点右孩子
queue.append(rightNode.left) #加入右节点左孩子
return True