剑指offer 面试题28. 对称的二叉树(易)& LeetCode 101. 对称二叉树(易)

自定义一种新的遍历算法来解决

Question

请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

1
2
3
4
5
    1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
1
2
3
4
5
  1
/ \
2 2
\ \
3 3
示例 1:
1
2
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
1
2
输入:root = [1,2,2,null,3,null,3]
输出:false
限制:0 <= 节点个数 <= 1000

测试用例

功能测试(对称的二叉树;因结构而不对称的二叉树;结构对称但节点的值不对称的二叉树)。 特殊输入测试(二叉树的根节点为nullptr指针;只有一个节点的二叉树;所有节点的值都相同的二叉树)。

本题考点

考查应聘者对二叉树的理解。本题实质上是利用树的遍历算法解决问题。 考查应聘者的思维能力。树的对称是一个抽象的概念,应聘者需要在短时间内想清楚判断对称的步骤并转换为代码。应聘者可以通过画图把抽象的问题形象化,这有助于其快速找到解题思路。

Intuition

Snipaste_2020-05-09_11-03-12.png

针对前序遍历定义一种对称遍历算法,即先遍历父节点,再遍历它的右子节点,最后遍历它的左子节点。这样一来,如果一棵树是对称的,那么它的前序遍历和对称遍历的结果就会是一样的。图中的第一棵二又树, 则遍历序列是{8, 6, 5, 7, 6, 7, 5}。如果用我们定义的针对前序遍历的对称遍历算法, 则得到的对称遍历序列是{8, 6, 5, 7, 6, 7, 5}。我们注意到这两个序列是一样的,也就是说,第一棵树是镜像对称的。图中第二棵二叉树的前序遍历序列为{8, 6, 5, 7, 9, 7, 5}, 而相应的对称前序遍历序列为{8, 9, 5, 7, 6, 7, 5}。在这两个序列中, 第二步和第五步是不一样的,也就是说第二课树不是对称的。

陷阱

第三棵二又树有些特殊, 它所有节点的值都是一样的。它的前序遍历序列是{7, 7, 7, 7, 7, 7}, 前序遍历的对称遍历序列也是{7, 7, 7, 7, 7, 7}。这两个序列是一样的, 可显然第三棵二叉树不是对称的。怎样才能正确地判断这种类型的二叉树呢?只要我们在遍历二叉树时把遇到的 nullptr 指针也考虑进来就行了。

Code

C++

  • 递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
bool symmetricCompare(TreeNode* root1, TreeNode* root2){
if(root1 == NULL && root2 == NULL)
return true; // 同时到达叶子节点
if(root1 == NULL || root2 == NULL)
return false; // 未同时到达叶子节点

if(root1->val != root2->val)
return false;

// root1, left, righgt and root2, right, left
return symmetricCompare(root1->left, root2->right) && symmetricCompare(root1->right, root2->left);
}
bool isSymmetric(TreeNode* root) {
// 对称二叉树的中序遍历和逆中序遍历的结果是一样的
return symmetricCompare(root, root);
}
};
  • 循环
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
60
61
62
63
64
65
66
67
68
69
class Solution {
public:
vector<int> preOrder(TreeNode* pRoot){
if(pRoot==NULL){
vector<int> res = {0x7fffffff};
return res;
}
vector<TreeNode*> treeStack;
vector<int> output;
TreeNode* pNode = pRoot;
while(pNode !=NULL || treeStack.size() > 0){
while(pNode !=NULL){
treeStack.push_back(pNode); // 等效于 python 中的treeStack.append(pNode)
output.push_back(pNode->val);
pNode = pNode->left;
if(pNode==NULL){
output.push_back(0x7fffffff);
}
}
if(treeStack.size() > 0){
pNode = treeStack.back();
treeStack.pop_back();
pNode = pNode->right;
if(pNode==NULL){
output.push_back(0x7fffffff);
}
}
}
return output;
}

vector<int> mirrorPreOrder(TreeNode* pRoot){
if(pRoot==NULL){
vector<int> res = {0x7fffffff}; // 用0x7fffffff替代NULL
return res;
}
vector<TreeNode*> treeStack;
vector<int> output;
TreeNode* pNode = pRoot;
while(pNode !=NULL || treeStack.size() > 0){
while(pNode !=NULL){
treeStack.push_back(pNode);
output.push_back(pNode->val);
pNode = pNode->right;
if(pNode==NULL){
output.push_back(0x7fffffff);
}
}
if(treeStack.size() > 0){
pNode = treeStack.back();
treeStack.pop_back();
pNode = pNode->left;
if(pNode==NULL){
output.push_back(0x7fffffff);
}
}
}
return output;
}

bool isSymmetric(TreeNode* root) {
// 对称二叉树的中序遍历和逆中序遍历的结果是一样的
vector<int> preList = preOrder(root);
vector<int> mirrorList = mirrorPreOrder(root);
if(preList==mirrorList) // 两个vector<int>可以直接比较
return true;
return false;
}
};

python

  • 递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None

class Solution:
def symmetricCompare(self, root1, root2):
if root1 == None and root2 == None:
return True # 同时到达叶子节点

if root1 == None or root2 == None:
return False # 未同时到达叶子节点

if root1.val != root2.val:
return False

# root1,left,right and root2,right,left
return self.symmetricCompare(root1.left, root2.right) and self.symmetricCompare(root1.right, root2.left)


def isSymmetric(self, root: TreeNode) -> bool:
return self.symmetricCompare(root, root)
  • 循环
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
class Solution:
def isSymmetric(self, pRoot):
preList = self.preOrder(pRoot)
mirrorList = self.mirrorPreOrder(pRoot)
if preList == mirrorList:
return True
return False

def preOrder(self, pRoot):
if pRoot == None:
return [None]
treeStack = []
output = []
pNode = pRoot
while pNode or len(treeStack) > 0:
while pNode:
treeStack.append(pNode)
output.append(pNode.val)
pNode = pNode.left
if not pNode:
output.append(None)
if len(treeStack):
pNode = treeStack.pop()
pNode = pNode.right
if not pNode:
output.append(None)
return output

def mirrorPreOrder(self, pRoot):
if pRoot == None:
return [None]
treeStack = []
output = []
pNode = pRoot
while pNode or len(treeStack) > 0:
while pNode:
treeStack.append(pNode)
output.append(pNode.val)
pNode = pNode.right
if not pNode:
output.append(None)
if len(treeStack):
pNode = treeStack.pop()
pNode = pNode.left
if not pNode:
output.append(None)
return output