1. 基础部分
该部分的基本思想为层次遍历(循环结构)。
1.1 二叉树的对称性
首先要明确,二叉树的对称性是指整棵树的结构上的对称性,而不仅仅是一个节点的左右两节点对称。因此,这种对称性不要求一个节点如果有左节点,就必须有右节点;只是要求整体上对称,有几种情况如下,
图1. 对称二叉树
判断一棵树是否是对称二叉树,不仅要考虑每个节点的val是否对称,也要考虑结构是否对称。栈,具有后进先出的特性,在遇到对称位置的元素时,如果是对称的元素,那么弹出栈,否则返回即可。因此,判断一棵二叉树是否为对称二叉树的关键点在于,补齐二叉树,并根据对称位置的元素判断,是否对称。如下,
对每层初始化一个栈stack,list
(1)对每一层,在树的左半部分,即该层遍历的下表i<2*(n-1).
如果有左/又子节点,则list.append(val),否则,list.append(None)
(2)在树的右半部分,如果对应位置的元素=stack[-1],则最后元素匹配,弹出栈,否则,返回False。
若每一层遍历结束后stack=[],返回True。
1.2 二叉树的深度
最大深度
按照层次遍历,每当遍历一层,二叉树的最大深度+1.
最小深度
最小深度为从根节点到最邻近的叶子节点的层数。而叶子节点是指既没有左子节点,也没有右子节点的节点,当遇到这样的节点时,返回当前的深度即可。(注意,不是说,一层中不满就是最小深度,如下)
图2. 二叉树的最小深度
在结构2中,不是说第二层不满,那么min_llevel = 2.同时,结构1中第二层满了,但是其min_level为2.因此,关键为判断一个节点是否为叶子节点。关键代码如下,
if node.left == None and node.right== None:
return r
树的节点数
同样根据层次遍历的思路,按层一次访问数的节点,得到树的节点数。
2. LeetCode代码
2.1 LeetCode101,对称二叉树
题目来源:力扣
给你一个二叉树的根节点 root
, 检查它是否轴对称。
图3. 对称二叉树示例
2.2 LeetCode104,二叉树的最大深度
题目来源:力扣
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
图4. 二叉树的最大深度示例
2.3 LeetCode111. 二叉树的最小深度
题目来源:力扣
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
图5. 二叉树的最小深度示例
2.4 LeetCode222. 完全二叉树的节点个数
题目来源:力扣
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
图6. 完全二叉树的节点个数
2.5 代码
代码如下,
# 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
def set_left(self, left):
self.left = left
def set_right(self, right):
self.right = right
class Solution(object):
def isSymmetric(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
# 一层一层地判断
if root == None:
return True
elif root.left == None and root.right == None:
return True
elif root.left != None and root.right == None or root.left == None and root.right != None:
return False
else:
node = [root.left, root.right]
stack = []
level = 1
while set(node) != {None}:
tmp_node = []
for i in range(len(node)):
if node[i] == None:
tmp_node.append(None)
tmp_node.append(None)
else:
if node[i].left != None:
tmp_node.append(node[i].left)
else:
tmp_node.append(None)
if node[i].right != None:
tmp_node.append(node[i].right)
else:
tmp_node.append(None)
if i < 2**(level-1):
if node[i] != None:
stack.append(node[i].val)
else:
stack.append(None)
else:
if node[i] != None:
if node[i].val == stack[-1]:
stack.pop(-1)
else:
return False
else:
if stack[-1] == None:
stack.pop(-1)
else:
return False
if stack != []:
return False
node = tmp_node
level += 1
return True
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
r = 0
if root == None:
return r
current = [root]
while current != []:
r += 1
tmp = []
for node in current:
if node.left != None:
tmp.append(node.left)
if node.right != None:
tmp.append(node.right)
current = tmp
return r
def minDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
r = 0
if root == None:
return r
current = [root]
while current != []:
r += 1
tmp = []
for node in current:
if node.left == None and node.right== None:
return r
if node.left != None:
tmp.append(node.left)
if node.right != None:
tmp.append(node.right)
current = tmp
return r
def countNodes(self, root):
"""
:type root: TreeNode
:rtype: int
"""
r = 0
if root == None:
return r
r += 1
current = [root]
while current != []:
tmp = []
for node in current:
if node.left != None:
tmp.append(node.left)
r += 1
if node.right != None:
tmp.append(node.right)
r += 1
current = tmp
return r
if __name__ == '__main__':
root = [1, 2, 2, 3, 4, 4, 3]
root = [1, 2, 3]
node1 = TreeNode(1)
node2 = TreeNode(2)
node3 = TreeNode(2)
node4 = TreeNode(3)
node5 = TreeNode(4)
node6 = TreeNode(4)
node7 = TreeNode(3)
node1.set_left(node2)
node1.set_right(node3)
node2.set_left(node4)
node2.set_right(node5)
node3.set_left(node6)
node3.set_right(node7)
sol = Solution()
# r = sol.preorderTraversal(node1)
r = sol.isSymmetric(node1)
level = sol.maxDepth(node1)
n_node = sol.countNodes(node1)
print(r)
print(level)
print(n_node)