文章目录
前言
最近一直在学习数据结构,学习的过程中不禁感叹编程真是一个神奇的东西,当我学习完二叉树后,彻底拜倒在递归的石榴裙下,脑子里只剩下一句话——多么神奇的递归啊!尤其是在写各种面试题时,这里就记录一下和二叉树有关的面试题吧!
一、相同的树
OJ链接:100. 相同的树
题目描述如下:
给你两棵二叉树的根节点p和q,编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
解题思路:
- 先判断根节点的值是否相同,再递归判断左子树和右子树。
代码如下:
/**
* 相同的树
*/
public class Num100_isSameTree {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p==null&&q==null){
return true;
}
if (p==null||q==null){
return false;
}
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
}
二、另一颗树的子树
OJ链接:572. 另一棵树的子树
题目描述如下:
给你两棵二叉树 root 和 subRoot ,检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点,tree 也可以看做它自身的一棵子树。
解题思路:
- 首先判断root和subRoot是否是相同的树,然后判断root的左子树中是否包含subRoot,最后判断root的右子树中是否包含subRoot。
代码如下:
/**
* 另一颗树的子树
*/
public class Num572_isSubtree {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root==null&&subRoot==null){
return true;
}
if (root==null||subRoot==null){
return false;
}
//先判断root和subRoot是否是相同的树||左树是否包含||右树是否包含
return isSameTree(root,subRoot)||isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
}
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p==null&&q==null){
return true;
}
if (p==null||q==null){
return false;
}
return p.val==q.val&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
}
三、二叉树的最大深度
OJ链接:104. 二叉树的最大深度
题目描述如下:
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
代码如下:
/**
* 求二叉树深度
*/
public class Num104_maxDepth {
public int maxDepth(TreeNode root) {
if (root==null){
return 0;
}
//只有根节点
if (root.left==null&&root.right==null){
return 1;
}
return 1+Math.max(maxDepth(root.left),maxDepth(root.right));
}
}
四、平衡二叉树
OJ链接:110. 平衡二叉树
题目描述如下:
给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
解题思路:
- 判断一棵二叉树是否是平衡二叉树,判断以root为根节点的二叉树左右子树高度差小于等于1,并且左子树也是平衡二叉树,右子树也是平衡二叉树。
代码如下:
import java.util.HashMap;
import java.util.Map;
/**
* 平衡二叉树
*/
public class Num110_isBalanced {
//2.改良版
private Map<TreeNode,Integer> map=new HashMap<>();
public boolean isBalanced(TreeNode root){
if (root==null){
return true;
}
int left=0;
int right=0;
//此时左树的高度已经被计算过了,直接从map中取出节点值对于的高度
if (map.containsKey(root.left)){
left=map.get(root.left);
}else{
//左树高度还没被计算过,所有用Height计算出来
left=Height(root.left);
map.put(root.left,left);
}
//同理
if (map.containsKey(root.right)){
right=map.get(root.right);
}else{
right=Height(root.right);
map.put(root.right,right);
}
int ret=Math.abs(left-right);
if (ret>1){
return false;
}
return isBalanced(root.left)&&isBalanced(root.right);
}
//1.普通做法
// public boolean isBalanced(TreeNode root) {
// if (root==null){
// return true;
// }
// int left=Height(root.left);
// int right=Height(root.right);
// int ret=Math.abs(left-right);
// if (ret>1){
// return false;
// }
// return isBalanced(root.left)&&isBalanced(root.right);
// }
//计算二叉树高度
private int Height(TreeNode root) {
if (root==null){
return 0;
}
return 1+Math.max(Height(root.left),Height(root.right));
}
}
五、对称二叉树
OJ链接:101. 对称二叉树
题目描述如下:
给你一个二叉树的根节点 root
, 检查它是否轴对称。
示例:
解题思路:
- 判断左树t1和右树t2是否是镜像关系,就需要判断左树的节点值和右树的节点值是否相等,并且左树的左子树和右树的右子树是否镜像相等,左树的右子树和右树的左子树是否镜像相等。
代码如下:
递归算法:
/**
* 对称二叉树
*/
public class Num101_isSymmetric {
public boolean isSymmetric(TreeNode root) {
if (root==null){
return true;
}
return isMirror(root.left,root.right);
}
/**
* 判断left和right是否是镜像相等
* @param left
* @param right
* @return
*/
private boolean isMirror(TreeNode left, TreeNode right) {
if (left==null&&right==null){
return true;
}
if (left==null||right==null){
return false;
}
if (left.val!=right.val){
return false;
}
return isMirror(left.left,right.right)&&isMirror(left.right,right.left);
}
}
非递归算法:
import java.util.LinkedList;
import java.util.Queue;
/**
* 使用层序遍历来解决问题
*/
public class Num101_IsSymmetricTreeNonRecursion {
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> queue=new LinkedList<>();
//将根节点的左右子树入队
queue.offer(root.left);
queue.offer(root.right);
while(!queue.isEmpty()){
//取出根节点的左右子树
TreeNode t1=queue.poll();
TreeNode t2=queue.poll();
if (t1==null&&t2==null){
continue;
}
if (t1==null||t2==null){
return false;
}
if (t1.val!=t2.val){
return false;
}
//此时t1和t2都不为空,且两个节点值都相等,接着判断t1.left和t2.right、t1.right和t2.left
queue.offer(t1.left);
queue.offer(t2.right);
queue.offer(t1.right);
queue.offer(t2.left);
}
return true;
}
}
六、二叉树的最长直径
OJ链接:二叉树的直径
题目描述如下:
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
解题思路:
- 从根节点root开始不断的去求每个节点的左右子树高度之和,最大值即为最长路径。这个题就是求树的高度而衍生出来的题,在求树的高度的时候,顺便就求出了树的最大直径。
代码如下:
public class Num543_DiameterOfBinaryTree {
//存储二叉树的最长路径
private static int max=0;
public static int diameterOfBinaryTree(TreeNode root) {
if (root==null||(root.left==null&&root.right==null)){
return 0;
}
height(root);
return max;
}
public static int height(TreeNode root) {
if (root==null){
return 0;
}
//左子树高度
int l=height(root.left);
//右子树高度
int r=height(root.right);
max=Math.max(max,(l+r));
//返回值是树的深度
return 1+Math.max(l,r);
}
}
七、二叉树转字符串
OJ链接:二叉树转字符串
题目描述如下:
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
解题思路:
- 如果节点的左右子树都为空,则不需要加括号,如果左子树为空,右子树不为空,就需要加一个括号来占位,如果左子树不为空而右子树为空时,不需要加括号。
代码如下:
/**
* 根据二叉树创建字符串
*/
public class Num606_Tree2str {
private StringBuilder sb=new StringBuilder();
public String tree2str(TreeNode root) {
if (root==null){
return null;
}
//root不为空时,将root的值拼接进字符串
sb.append(root.val);
//左子树不为空,递归处理左子树
if (root.left!=null){
sb.append("(");
tree2str(root.left);
sb.append(")");
}else{
//此时左子树为空,右子树不为空
if (root.right!=null){
sb.append("()");
}
}
//右子树不为空
if (root.right!=null){
sb.append("(");
tree2str(root.right);
sb.append(")");
}
return sb.toString();
}
}
总结
二叉树的基础面试题就总结到这里,越是基础越是不能忽略,要认真对待,有很多细节问题可能会在面试的时候问到,所以大家要认真对待!
创作不易,你是否有收获呢?如果有收获的话就留下你的👍吧!!!