今日刷题重点—二叉树的对称性

​226. 翻转二叉树​

翻转一棵二叉树。

示例:

输入:

4
/ \
2 7
/ \ / \
1 3 6 9
输出:

4
/ \
7 2
/ \ / \
9 6 3 1

思路分析

反转二叉树:

LeetCode刷题day34_算法


本质就是:把每一个结点的左右孩子互换一下,除了叶子结点所有的都要进行这样的操作.

方法一:递归法(以先序为例)

递归三要素

  • 递归参数:每次要交换的根节点(交换的是其左右节点)
  • 结束条件:当root为null时.
  • 确定单层递归的逻辑
    因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

LeetCode刷题day34_二叉树_02

参考代码1

//递归 
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) {
return NULL;
}
swap(root->left,root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}

迭代法1(栈模拟)

用栈来模拟,因为递归的底层使用的就是栈.

参考代码2

//迭代法
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) {
return NULL;
}
stack<TreeNode*> tab;
tab.push(root);
while(!tab.empty()) {
TreeNode* node = tab.top();//中
tab.pop();
swap(node->left,node->right);
if(node->left!=NULL) { //右
tab.push(node->left);
}
if(node->right!=NULL) { //左
tab.push(node->right);
}
}
return root;
}

迭代法2(队列模拟)

用层次遍历的思路也是可以的.

参考代码3

TreeNode* invertTree(TreeNode* root) {
if(root==NULL) {
return NULL;
}
queue<TreeNode*> Q;
Q.push(root);
while(!Q.empty()) {
int size = Q.size();
for(int i = 0;i<size;i++){
TreeNode* node = Q.front();
Q.pop();
swap(node->left,node->right);
if(node->left){
Q.push(node->left);
}
if(node->right){
Q.push(node->right);
}
}
}
return root;
}

注意: 递归的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。

​101. 对称二叉树​

给定一个二叉树,检查它是否是镜像对称的。

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

1
/ \
2 2
/ \ / \
3 4 4 3

但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

1
/ \
2 2
\ \
3 3

思路分析

首先要清楚对称二叉树比较的是哪两个节点,要比较的可不是左右节点!
对于是否对称,要比较的是根节点的左右子树是否可以反转. 理解了这一点就知道,其实我们要比较的是两棵树,所以在递归遍历过程中要同时遍历这两棵树.

那么如何进行比较呢?

如下图,我们只需要外侧和外侧进行对比,内侧和内侧进行比较即可.

LeetCode刷题day34_ide_03

方法一:递归

递归三部曲:

  • 确定参数和返回值:参数是左右子树,返回值是bool
  • 确定终止条件

首先要把两个节点为空的情况弄清楚! 否则后面比较数值的时候就会操作空指针了。

节点为空的情况有:

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return false
  • 左右都为空,对称,返回true

左右节点不为空:

  • 左右都不为空,比较节点数值,不相同就return false

剩下的一种情况就是,左右节点都不为空,而且其节点值相等.(我们后序在处理)

//先进行判空操作
if(!left&&right || left&&!right) {
return false;
}
if(!left&&!right) {
return true;
}

//在进行 根节点值不同的情况
if(left->val!=right->val) {
return false;
}
  • 确定单层递归的逻辑

单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。
//当前两个根节点的值相同,开始比较其树上的其他节点
bool outSide = isCompare(left->left,right->right);
bool inSide = isCompare(left->right,right->left);

return outSide&&inSide;

参考代码1

//递归..
bool isCompare(TreeNode* left,TreeNode* right) {
//先进行判空操作
if(!left&&right || left&&!right) {
return false;
}
if(!left&&!right) {
return true;
}

//在进行 根节点值不同的情况
if(left->val!=right->val) {
return false;
}

//当前两个根节点的值相同,开始比较其树上的其他节点
bool outSide = isCompare(left->left,right->right);
bool inSide = isCompare(left->right,right->left);

return outSide&&inSide;

}

bool isSymmetric(TreeNode* root) {
if(root==NULL) {
return true;
}
return isCompare(root->left,root->right);

}

方法二: 迭代法(使用队列)

可以使用队列来判断左右节点及其子树是否对称.

LeetCode刷题day34_算法_04

参考代码2

bool isSymmetric(TreeNode* root) {
if(root==NULL){
return true;
}
queue<TreeNode*> Q;
Q.push(root->left);
Q.push(root->right);
while(!Q.empty()){
TreeNode* node1 = Q.front();
Q.pop();
TreeNode* node2 = Q.front();
Q.pop();
//进行判空操作
if(node1&&!node2 || !node1&&node2){
return false;
}
if(!node1&&!node2){//都为空说明是对称的,继续往下判断.
continue;
}
if(node1->val!=node2->val){
return false;
}
//说明此刻当前俩节点值相等,继续判断其树上的节点是否相等.
Q.push(node1->left);
Q.push(node2->right);
Q.push(node1->right);
Q.push(node2->left);
}
return true;
}

方法三:使用栈

方法二,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的。

参考代码3

bool isSymmetric(TreeNode* root) {
if (root == NULL) return true;
stack<TreeNode*> st; // 这里改成了栈
st.push(root->left);
st.push(root->right);
while (!st.empty()) {
TreeNode* leftNode = st.top(); st.pop();
TreeNode* rightNode = st.top(); st.pop();
if (!leftNode && !rightNode) {
continue;
}
if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {
return false;
}
st.push(leftNode->left);
st.push(rightNode->right);
st.push(leftNode->right);
st.push(rightNode->left);
}
return true;
}

​100. 相同的树​

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

LeetCode刷题day34_二叉树_05

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:

LeetCode刷题day34_ide_06

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:

LeetCode刷题day34_ide_07

输入:p = [1,2,1], q = [1,1,2]
输出:false

思路分析

上题是对称,这个题是相等,只需要修改下比较的两个节点的顺序即可.
也有递归,迭代(通过队列),迭代(通过栈)

参考代码1

bool isSameTree(TreeNode* left, TreeNode* right) {
//先进行判空操作
if(!left&&right || left&&!right) {
return false;
}
if(!left&&!right) {
return true;
}

//在进行 根节点值不同的情况
if(left->val!=right->val) {
return false;
}

//当前两个根节点的值相同,开始比较其树上的其他节点
bool outSide = isSameTree(left->left,right->left);
bool inSide = isSameTree(left->right,right->right);

return outSide&&inSide;

}

参考代码2

bool isSameTree(TreeNode* left, TreeNode* right) {
//先进行判空操作
if(!left&&right || left&&!right) {
return false;
}
if(!left&&!right) {
return true;
}

//在进行 根节点值不同的情况
if(left->val!=right->val) {
return false;
}

//当前两个根节点的值相同,开始比较其树上的其他节点
bool outSide = isSameTree(left->left,right->left);
bool inSide = isSameTree(left->right,right->right);

return outSide&&inSide;

}

572. 另一棵树的子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

LeetCode刷题day34_递归_08

输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true

示例 2:

LeetCode刷题day34_leetcode_09

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false

思路分析

这个题判断两个树是否是树A和子树B的关系.
只需要遍历A上的每一个子树,判断和B是否相等,如果相等,则返回true.当A上的所有结点遍历完了还没找到则说明不存在,返回false.

参考代码

bool isSameTree(TreeNode* left, TreeNode* right) {
//先进行判空操作
if(!left&&right || left&&!right) {
return false;
}
if(!left&&!right) {
return true;
}

//在进行 根节点值不同的情况
if(left->val!=right->val) {
return false;
}

//当前两个根节点的值相同,开始比较其树上的其他节点
bool outSide = isSameTree(left->left,right->left);
bool inSide = isSameTree(left->right,right->right);

return outSide&&inSide;

}

bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root==NULL){//我 root树都已经遍历完了还没找到则直接返回false
return false;
}
//进行递归判断,只要有一个为真即为真.
return isSameTree(root,subRoot)||isSameTree(root->left,subRoot) ||isSameTree(root->right,subRoot);
}