目录
226.翻转二叉树
题目
给你一棵二叉树的根节点 root
,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
代码(前序递归)
class Solution {
public TreeNode invertTree(TreeNode root) {
preOrder(root);
return root;
}
//前序递归,一边遍历一边反转左右孩子指针
public void preOrder(TreeNode root){
//终止条件
if(root == null){
return;
}
//单层逻辑
swap(root); //遍历到该节点就翻转左右指针
preOrder(root.left); //遍历左子树
preOrder(root.right); //遍历右子树
}
//翻转左右孩子的指针
public void swap(TreeNode root){
TreeNode tmp = new TreeNode();
tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
代码(后序递归)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
postOrder(root);
return root;
}
//后序递归,一边遍历一边反转左右孩子指针
public void postOrder(TreeNode root){
//终止条件
if(root == null){
return;
}
//单层逻辑
postOrder(root.left); //遍历左子树(左)
postOrder(root.right); //遍历右子树(右)
swap(root); //遍历到该节点就翻转左右指针(中)
}
//翻转左右孩子的指针
public void swap(TreeNode root){
TreeNode tmp = new TreeNode();
tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
代码(前序迭代)
class Solution {
public TreeNode invertTree(TreeNode root) {
//前序迭代遍历+遍历时翻转左右孩子指针
Stack<TreeNode> stack = new Stack<>();
if(root == null){
return root;
}
stack.push(root); //根节点入栈
while(!stack.isEmpty()){
TreeNode cur = stack.pop(); //出栈==遍历节点
swap(cur); //交换左右孩子指针
if(cur.right != null){
stack.push(cur.right);
}
if(cur.left != null){
stack.push(cur.left);
}
}
return root;
}
//翻转左右孩子的指针
public void swap(TreeNode root){
TreeNode tmp = new TreeNode();
tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
代码(层序迭代)
class Solution {
public TreeNode invertTree(TreeNode root) {
//层序迭代遍历+遍历时翻转左右孩子指针
Queue<TreeNode> que = new ArrayDeque<>();
if(root == null){
return root;
}
que.offer(root); //根节点入队
while(!que.isEmpty()){
int size = que.size();
while(size-- > 0){
TreeNode cur = que.poll(); //出队==遍历
swap(cur); //交换左右孩子指针,要先交换再把孩子加到队列里
if(cur.left != null){
que.offer(cur.left);
}
if(cur.right != null){
que.offer(cur.right);
}
}
}
return root;
}
//翻转左右孩子的指针
public void swap(TreeNode root){
TreeNode tmp = new TreeNode();
tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
总结
翻转二叉树可以用前序、后序、层序遍历,一边遍历时一边翻转当前遍历节点的左右指针即可。对比单纯的遍历二叉树,就是把遍历节点值add到result的操作,修改为swap(cur)即可。所以只要熟练二叉树的递归和迭代遍历,加上想清楚这道题在遍历时增加什么操作即可。核心算法还是二叉树的遍历。
101.对称二叉树
题目
给你一个二叉树的根节点 root
, 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3] 输出:true
代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
return compare(root.left,root.right);
}
//比较左右子树是否相互翻转(后序,左右中+右左中)
public boolean compare(TreeNode left,TreeNode right){
//终止条件(left和right这一层先比较)
if(left == null && right != null){
return false; //左空右不空
}
else if(left != null && right == null){
return false; //左不空右空
}
else if(left == null && right == null){
return true; //左右都为空
}
//这里的左右节点都不会为空了,可以获取val
else if(left.val != right.val){
return false; //不为空,但是左右节点值不同
}
//当面的终止条件,如果没终止,说明left和right的值一样,要继续往下一层遍历
//单层逻辑,对于左子树遍历左右中,对于右子树,遍历右左中
boolean outside = compare(left.left,right.right); //比较外侧节点
boolean inside = compare(left.right,right.left); //比较内侧节点
return outside&&inside;
}
}
100.相同的树
题目
给你两棵二叉树的根节点 p
和 q
,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
示例 1:
输入:p = [1,2,3], q = [1,2,3] 输出:true
代码
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
boolean result = compare(p,q);
return result;
}
public boolean compare(TreeNode p,TreeNode q){
//终止条件
if(p != null && q == null){
return false; //左不空右空
}
else if(p == null && q != null){
return false; //左空右不空
}
else if(p == null && q == null){
return true; //左右都空
}
else if(p.val != q.val){
return false; //左右都不空但是节点值不一样
}
//如果上面终止条件都不满足,没有return,说明左右的节点值一样,要继续往后面判断
//单层逻辑,后序遍历左右中
boolean left = compare(p.left,q.left); //比较左边
boolean right = compare(p.right,q.right); //比较右边
return left && right;
}
}
572.另一棵树的子树
题目
给你两棵二叉树 root
和 subRoot
。检验 root
中是否包含和 subRoot
具有相同结构和节点值的子树。如果存在,返回 true
;否则,返回 false
。
二叉树 tree
的一棵子树包括 tree
的某个节点和这个节点的所有后代节点。tree
也可以看做它自身的一棵子树。
示例 1:
输入:root = [3,4,5,1,2], subRoot = [4,1,2] 输出:true
代码(前序迭代)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
Stack<TreeNode> stack = new Stack<>();
if(subRoot == null){
return true;
}
//核心逻辑是,前序遍历root,不断判断是否和subroot树相同
stack.push(root); //根节点入栈
boolean result = fase; //初始reslut
//result == false,是只要compare返回true,说明存在包含关系,就可以不用继续判断了
while(!stack.isEmpty() && result == false){
TreeNode cur = stack.pop();
//比较cur和subroot树是否相同,如果返回true直接结束循环
result = compare(cur,subRoot);
//如果不相同,继续前序遍历
if(cur.right != null){
stack.push(cur.right); //右子树进栈
}
if(cur.left != null){
stack.push(cur.left); //左子树进栈
}
}
return result;
}
//compare用于判断两个数是否相同
public boolean compare(TreeNode p,TreeNode q){
//终止条件
if(p != null && q == null){
return false; //左不空右空
}
else if(p == null && q != null){
return false; //左空右不空
}
else if(p == null && q == null){
return true; //左右都空
}
else if(p.val != q.val){
return false; //左右都不空但是节点值不一样
}
//如果上面终止条件都不满足,没有return,说明左右的节点值一样,要继续往后面判断
//单层逻辑,后序遍历左右中
boolean left = compare(p.left,q.left); //比较左边
boolean right = compare(p.right,q.right); //比较右边
return left && right;
}
}
代码(层序迭代)
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
Queue<TreeNode> que = new ArrayDeque<>();
que.offer(root);
while(!que.isEmpty()){
int len = que.size();
while(len-- > 0){
TreeNode cur = que.poll();
boolean res = compare(cur,subRoot);
if(res == true){
return true;
}
if(cur.left != null){
que.offer(cur.left);
}
if(cur.right != null){
que.offer(cur.right);
}
}
}
return false;
}
//compare用于判断两个数是否相同
public boolean compare(TreeNode p,TreeNode q){
//终止条件
if(p != null && q == null){
return false; //左不空右空
}
else if(p == null && q != null){
return false; //左空右不空
}
else if(p == null && q == null){
return true; //左右都空
}
else if(p.val != q.val){
return false; //左右都不空但是节点值不一样
}
//如果上面终止条件都不满足,没有return,说明左右的节点值一样,要继续往后面判断
//单层逻辑,后序遍历左右中
boolean left = compare(p.left,q.left); //比较左边
boolean right = compare(p.right,q.right); //比较右边
return left && right;
}
}