目录
Leetcode - 102
需要和深度优先遍历区分的事,深度优先遍历会用到栈,但是广度优先遍历会用到队列 ,根节点入队后,出队,记录节点值,然后将左右子节点(若存在) 依次入队,这样反复循环直到队列为空即可。 但是102这题需要将每一层的节点区分出来,这里用的方法是记录当前队列的长度L,然后在队列做出队加子节点入队操作时,仅仅出队L次,然后单独记录,然后再重新记录队列长度,此时队列长度就是下一层的节点数目。
def levelOrder(root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
queue = deque()
queue.append(root)
res = []
while queue:
layer_length = len(queue)
temp = [0] *layer_length
for i in range(layer_length):
elem = queue.popleft()
temp[i] = elem.val
if elem.left:
queue.append(elem.left)
if elem.right:
queue.append(elem.right)
res.append(temp)
return res
还有类似的十题:
- 102.二叉树的层序遍历
- 107.二叉树的层次遍历II
- 199.二叉树的右视图
- 637.二叉树的层平均值
- 429.N叉树的层序遍历
- 515.在每个树行中找最大值
- 116.填充每个节点的下一个右侧节点指针
- 117.填充每个节点的下一个右侧节点指针II
- 104.二叉树的最大深度
- 111.二叉树的最小深度
这里需要单独拧出来说的是116 111
Leetcode - 116
这里需要关注的是,如何将一层的节点中,节点于其右边的节点产生联系,最后一个节点是否需要处理?
首先 每出队一个元素,此时队首元素就是与其相邻的元素,让出队的这个元素指向队首元素即可,到出队最后一个元素后直接break即可,因为其next指针域默认为None
且最后返回的是根节点 这里不要错了
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:
return root
res =[]
queue = deque()
queue.append(root)
while queue:
length = len(queue)
for i in range(length):
elem = queue.popleft()
if elem.left:
queue.append(elem.left)
if elem.right:
queue.append(elem.right)
if i == length -1:
break
elem.next = queue[0]
return root
Leetcode - 111
这题首先要找到第一个叶子节点,即左右子节点均为空,此时停止遍历,判断res的长度即为此时叶子节点所在的深度
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
queue = deque()
res = []
queue.append(root)
while queue:
length = len(queue)
temp = [0] * length
for i in range(length):
elem = queue.popleft()
temp.append(elem.val)
if not elem.left and not elem.right:
res.append(temp)
return len(res)
if elem.left:queue.append(elem.left)
if elem.right:queue.append(elem.right)
res.append(temp)
Leetcode - 226
这题一开始我用的是层次遍历去做的,每每从队列pop出一个节点的时候,只要其左右节点存在一个,就进行互换。
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
queue = deque()
queue.append(root)
while queue:
length = len(queue)
for i in range(length):
t = queue.popleft()
if t.left or t.right:
t.left,t.right = t.right,t.left
if t.left: queue.append(t.left)
if t.right: queue.append(t.right)
return root
这种方法其实比卡哥说的前序遍历后序遍历效率都要高
卡哥的方法就是,在前序遍历或者后序遍历的“中”操作的地方进行左右节点互换。
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
def swap(node):
if node == None:
return
node.left,node.right = node.right,node.left
swap(node.left)
swap(node.right)
swap(root)
return root
为啥不能中序,因为中序的话 左中右,先处理左边,然后互换,此时的右边就是原来的左右,此时再处理右边就等于又处理了一遍原来的左边,原来的右边其实没有处理的,若要写成中序,“右”操作的时候应该还是要处理左边才对
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
def swap(node):
if node == None:
return
swap(node.left)
node.left,node.right = node.right,node.left
swap(node.left)
swap(root)
return root
Leetcode - 101
这题要用的是后序遍历,因为只有对左边右边都处理完了之后才能返回结果
这里比较的是左右两侧,外侧和内侧都相同才能算对称,比如左边的左子树,右边的右子树相同,算外侧相同,左边的右子树,右边的左子树相同,算内侧相同。递归的参数,就是左右两子节点。终止条件?若左为空右不为空、右为空左不为空,左右不为空但不相等返回False,左右同时为空返回True,只有当左右均不为空,且值相同,才能继续下面的循环
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return False
def compare(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
outer = compare(left.left,right.right)
inner = compare(left.right,right.left)
return outer and inner
return compare(root.left,root.right)