BM 36 判断是不是平衡二叉树

url:牛客 BM36

考察知识点:二叉树遍历,递归

平衡二叉树的定义:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

诀窍:自顶向下递归时传递深度,避免向上合并时重复计算深度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param pRoot TreeNode类
# @return bool布尔型
#
class Solution:
def IsBalanced_Tree(self, left: TreeNode, right: TreeNode, current_depth: int):
if left is None and right is None:
return True, current_depth

left_depth = current_depth
right_depth = current_depth

if left is not None:
isbalanced_tree, left_depth = self.IsBalanced_Tree(left.left, left.right, current_depth+1)
if not isbalanced_tree:
return False, current_depth

if right is not None:
isbalanced_tree, right_depth = self.IsBalanced_Tree(right.left, right.right, current_depth+1)
if not isbalanced_tree:
return False, current_depth

# 判断左右子树深度是否符合要求
if abs(left_depth - right_depth) > 1:
return False, current_depth
else:
return True, max(left_depth, right_depth)

def IsBalanced_Solution(self , pRoot: TreeNode) -> bool:
# write code here
if pRoot is None:
return True

result, depth = self.IsBalanced_Tree(pRoot.left, pRoot.right, 0)
return result

BM 38 在二叉树中找到两个节点的最近公共祖先

url:牛客 BM38

建议和BM 37 在二叉搜索树中找到两个节点的最近公共祖先结合起来做。二叉搜索树由于可以提前预测节点大致位置,因此不需要对树做深度/广度的搜索。但相反如果是普通二叉树,要找某个节点就非得使用搜索技术不可。这里可以使用深度优先为代表的前序遍历来分别搜索两个节点,并获取路径。实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param root TreeNode类
# @param o1 int整型
# @param o2 int整型
# @return int整型
#
class Solution:
def getPath(self, root: TreeNode, target: int):
# 用前序遍历查询路径
stack = [root]
pre = {root.val: None}

while len(stack) > 0:
node = stack.pop()

if node.val == target:
break

if node.right is not None:
pre[node.right.val] = node.val
stack.append(node.right)

if node.left is not None:
pre[node.left.val] = node.val
stack.append(node.left)

# 获取路径
path = []
cur = target
while cur is not None:
path.append(cur)
cur = pre[cur]
path.reverse()
return path


def lowestCommonAncestor(self , root: TreeNode, o1: int, o2: int) -> int:
# write code here
path1 = self.getPath(root, o1)
path2 = self.getPath(root, o2)

min_length = min(len(path1), len(path2))

i = 0
while path1[i] == path2[i]:
i += 1
if i >= min_length:
break

return path1[i-1]

当然,要是使用广度优先搜索也能搜索到节点并且得到路径。对二叉树的广度优先搜索即层次遍历,依赖队列实现。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param root TreeNode类
# @param o1 int整型
# @param o2 int整型
# @return int整型
#
class Solution:
def getPath(self, root: TreeNode, target: int):
# 用层次遍历查询路径
queue = [root]
pre = {root.val: None}

while len(queue) > 0:
node = queue.pop(0)

if node.val == target:
break

if node.left is not None:
pre[node.left.val] = node.val
queue.append(node.left)

if node.right is not None:
pre[node.right.val] = node.val
queue.append(node.right)


# 获取路径
path = []
cur = target
while cur is not None:
path.append(cur)
cur = pre[cur]
path.reverse()
return path


def lowestCommonAncestor(self , root: TreeNode, o1: int, o2: int) -> int:
# write code here
path1 = self.getPath(root, o1)
path2 = self.getPath(root, o2)

min_length = min(len(path1), len(path2))

i = 0
while path1[i] == path2[i]:
i += 1
if i >= min_length:
break

return path1[i-1]

值得注意的是,二叉树知道子节点并不能直接访问父节点,但是要知道路径的话在搜索到该节点之后非得要往上访问父节点才能求得路径。因此,在搜索时预先设定一个字典记录一下子节点到父节点的路径会让导出路径变得简单。

最后,这个找两个节点的最近公共祖先就变成了找路径上最后一个相同的节点了。