二叉树的问题大多是以递归思想求解,也可以利用迭代思想利用队列实现,熟练运用递归对于解决二叉树问题十分重要,本篇博客为一些基础的二叉树问题,对于理解二叉树的结构以及递归思想有着很大的帮助.
本篇文章所有的代码已上传至gitee中:二叉树OJ练习
目录
树的重要概念总结
①结点的度:一个结点含有子树的个数称为该结点的度;
②树的度:一棵树中,所有结点度的最大值称为树的度;
③叶子结点或终端结点:度为0的结点;
④根结点:一棵树中没有双亲的结点;
⑤结点的层次:从根开始定义起,根为第一层,根的子节点为第二层,以此类推;
⑥树的高度或深度:树中结点的最大层次
相同的树
题目链接: 相同的树
题目描述:给你两颗二叉树的根节点p和q,编写一个函数来检验这两颗二叉树是否相同。如果两个树在树结构上相同,并且节点具有相同的值,则认为它们是相同的.
例如:
解题思路:
1.首先判断根节点,两棵树若都为空,则返回true;
2.判断两个根节点是否有一个为空,若有,则返回false;
3.判断根节点的值是否相同,若不相同,返回false;
4.递归遍历两颗树的左右子树.
具体实现:
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) {
return true;
}
if(p == null || q == null) {
return false;
}
if(p.val != q.val) {
return false;
}
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
另一颗树的子树
题目链接:另一棵树的子树
题目描述: 给你两棵二叉树root和subRoot.检测root中是否包含和subRoot具有相同结构和节点值的子树.如果存在,返回true,否则返回false.
例如:
解题思路:
本题的解决利用了上一个题目“相同的树”的方法:
将root和subRoot传入isSameTree方法,如果相同,则直接返回true,若不相同,分别将root.left和root.right传入判断.
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if(root == null) {
return false;
}
return isSameTree(root, subRoot) || isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);
}
private boolean isSameTree(TreeNode p, TreeNode q) {
if(p == null && q == null) {
return true;
}
if(p == null || q == null) {
return false;
}
if(p.val != q.val) {
return false;
}
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
二叉树的最大深度
题目链接:二叉树的最大深度
题目描述:给定一棵二叉树,找出其最大深度.二叉树的深度为根节点到最远叶子节点的最长路径上的节点数.
例如:
解题思路:
依次递归求左子树和右子树的高度,最终返回左子树/右子树的高度+1
代码实现:
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
int leftH = maxDepth(root.left);
int rightH = maxDepth(root.right);
return leftH > rightH ? (leftH+1) : (rightH+1);
}
平衡二叉树
题目链接:平衡二叉树
题目描述:给定一棵二叉树,判断其是否为高度平衡二叉树。
一棵高度平衡二叉树定义为:一个二叉树每个结点的左右两棵子树的高度差的绝对值不超过1
例如:
解题思路:
编写一个方法:一边求二叉树的高度,一边判断平衡,如果该子树平衡,则返回其高度,反之返回-1.
代码如下:
public boolean isBalanced(TreeNode root) {
return maxDepth(root) >= 0;//等于0是因为当二叉树为空时,返回true
}
private int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
int leftH = maxDepth(root.left);
int rightH = maxDepth(root.right);
if(leftH >= 0 && rightH >= 0 && Math.abs(leftH - rightH) <= 1) {
return Math.max(leftH,rightH) + 1;
} else {
return -1;
}
}
对称二叉树
题目链接:对称二叉树
题目描述:给你一个结点root,判断它是否为对称轴.
例如:
解题思路:
有两种方法可以实现:①迭代;②递归.
迭代实现(利用队列实现)
如上图所示,利用队列完成判断该二叉树是否为对称二叉树,首先判断root是否为null,若为null直接返回true,否则进行如下操作:
1.将root的左孩子和右孩子分别入队
2.利用while语句判断队列目前是否为空,若不为空则一直进行循环操作:
①利用TreeNode定义p和q,用来接收出队的两个结点,若这两个结点均为null,则继续循环
②若p和q中只有一个为空或者p.val != q.val,则返回false;
③先将p的左孩子和q的右孩子入队,再将p的右孩子和q的左孩子入队.
3.如果上述操作完成,且未跳出,则返回true
具体代码实现:
public boolean isSymmetric(TreeNode root) {
if(root == null) {
return true;
}
return check(root.left, root.right);
}
private boolean check(TreeNode p, TreeNode q) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(p);
queue.offer(q);
while(!queue.isEmpty()) {
p = queue.poll();
q = queue.poll();
if(p == null && q == null) {
continue;
}
if(p == null || q == null || p.val != q.val) {
return false;
}
queue.offer(p.left);
queue.offer(q.right);
queue.offer(p.right);
queue.offer(q.left);
}
return true;
}
递归实现
该方法的时间复杂度为O(n),其check方法的主要思想为:
1.如果p和q都为null则对称;
2.如果p和q有一个为空或者q.val != p.val,则返回false;
3.递归遍历check(p.left,q.right) && check(p.right,q.left)
public boolean isSymmetric(TreeNode root) {
if(root == null) {
return true;
}
return check(root.left, root.right);
}
private boolean check(TreeNode p, TreeNode q) {
if(p == null && q == null) {
return true;
}
if(p == null || q == null || p.val != q.val) {
return false;
}
return check(p.left,q.right) && check(p.right,q.left);
}
二叉树的层次遍历
题目链接:二叉树的层次遍历
题目描述: 给你二叉树的根节点root,返回其结点值的层序遍历(即逐层的,从左到右访问所有节点).
例如:
解题思路:
根据题目给出的初始模板,可以看出本题意在利用顺序表解决问题.
以上述例子为例,可以抽象出实现该问题需要如下的顺序表
首先将根节点入队,之后判断如下几个条件:
①该节点左孩子是否为空,若不为空,则将其加入队列,若为空则不做处理;
②再判断其右孩子是否为空,若不为空,则将其加入队列,若为空则不做处理;
③以size来作为每一层结点结束的标志,当size为0时,结束该层的循环,进入下一层的循环.
具体代码实现:
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<>();
if(root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
List<Integer> curRow = new ArrayList<>();
int size = queue.size();
while(size != 0) {
TreeNode cur = queue.poll();
curRow.add(cur.val);
if(cur.left != null) {
queue.offer(cur.left);
}
if(cur.right != null) {
queue.offer(cur.right);
}
size--;
}
ret.add(curRow);
}
return ret;
}