二叉树基础面试题练习:
- 二叉树的前序遍历。
- 二叉树中序遍历 。
- 二叉树的后序遍历 。
- 检查两颗树是否相同。
- 另一颗树的子树。
- 二叉树最大深度。
- 判断一颗二叉树是否是平衡二叉树。
- 对称二叉树。
- 深刻体会神奇的递归思想!!!
前序遍历,用List存
//二叉树的前序遍历 力扣144
//与之前不同的是此处要将遍历结果放在list中,之前是直接打印
public static List<Integer> preorderTraversal(TreeNode root){
//包装类 int=>Integer
// List<Integer> result=new List<Integer>() ;//List是个接口,不能直接实例化对象.应该用他的实现类ArrayList
List<Integer> result=new ArrayList<>();
if (root==null){//空树,返回一个空的List。注意:是 List里的元素个数为0,但不是null。
// List是个盒子,盒子里面没东西是空,连盒子都没有,是null
return null;
}
//访问根节点,这里访问也就是指将root的值add进List中
result.add(root.val);
//递归访问左子树,将左子树的值addall进list中
//addAll是将根的左子树的所有节点都加进list,List是一个长度可变的线性表
//每递归一次就会创建一个List(List的引用是result),将节点值加进List。最后将所有的List加进总的list中
result.addAll(preorderTraversal(root.left));
//递归遍历右子树,将右子树的节点加入List中
result.addAll(preorderTraversal(root.right));
return result;
}
中序,后序思路同前序遍历
//二叉树的中序遍历 力扣94
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root==null){
return result;
}
result.addAll (inorderTraversal(root.left));
result.add(root.val);
result.addAll(inorderTraversal(root.right));
return result;
}
//二叉树的后序遍历 力扣145
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer>result=new ArrayList<>();
if(root==null){
return result;
}
result.addAll(postorderTraversal(root.left));
result.addAll(postorderTraversal(root.right));
result.add(root.val);
return result;
}
4.检查两棵树是否相同
//检查两棵树是否相同 力扣100
//思路:先看根节点是否相同,再递归比较左子树和右子树是否相同
//思路2.先序+中序或者中序+后序的结果相同,则是相同的树
public boolean isSameTree(TreeNode p, TreeNode q) {
//可分为3种情况:1.pq都为空,相同
//2.pq只有一个为空,不相同
//3.pq都不为空,比较完根节点后,进入递归比较
if (p == null && q == null) {//两颗空树,肯定相同
return true;
}
// if ((p==null&&q!=null||(p!=null&&q==null)){}//其中一颗为空树,肯定不相同
//上述代码可简化成下面;
// 因为第一个if已经对pq=null进行过判断,所以当执行第二个if时,一定是pq只有一个为null
if (p == null || q == null) {
return false;
}
if (p.val == q.val) {//根节点相同时,递归比较左右子树,左右子树都相同才返回true
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
} else {
return false;
}
}
5.一棵树是另一颗树的子树
//一棵树是另一颗树的子树,思路同上 力扣572
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s==null&&t==null){//两棵空树,互为子树
return true;
}
if(s==null||t==null){//其中一颗为空树,则肯定为false
return false;
}
boolean ret=false;
if (s.val==t.val){
ret= isSameTree(s,t);//如果根节点相同,则看这两棵树是不是相同,相同就是子树
}
if (ret==false){//如果s,t不相同,那么就递归在s的左子树中找t。
ret=isSubtree(s.left,t);
}
if (ret==false){//如果在s的左子树中没找到,那就在右子树中找
ret=isSubtree(s.right,t);
}
return ret;
}
6.二叉树的最大深度
//二叉树的最大深度 力扣104
//二叉树的深度:根节点到最远叶子节点的最长路径上的节点数。
//叶子结点:没有子树的节点
//思路:最大深度=max(左子树的深度,右子树的深度)+1(1是根节点)
public int maxDepth(TreeNode root) {
if (root==null){
return 0;
}
if (root.right==null&&root.left==null){
return 1;
}
int result=Math.max(maxDepth(root.left),maxDepth(root.right))+1;
return result;
}
7.判断一棵树是否为平衡二叉树
//判断一棵树是否为平衡二叉树 力扣110
//本题中,一棵高度平衡二叉树定义为:
//一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。
//思路:一棵树是否平衡:
//1.自己的左右子树高度差是否<=1;
//2.&&左右子树是否分别为平衡二叉树(递归判断);
public boolean isBalanced(TreeNode root) {
if (root==null){
//空树认为是平衡的
return true;
}
if (root.left==null&&root.right==null){
//没有节点也认为是平衡的
return true;
}
//第一步:自己的左右子树高度差是否<=1;
int leftDepth=maxDepth(root.right);
int rightDepth=maxDepth(root.left);
if(leftDepth-rightDepth>1||leftDepth-rightDepth<-1){//记得是比较绝对值
return false;
}
//第二步:&&左右子树是否分别为平衡二叉树(递归判断)
return isBalanced(root.right)&&isBalanced(root.left);
}
8.对称二叉树,给定一个二叉树,检查它是否是镜像对称的
(一直不够理解递归,放一个在力扣上看到的大佬整理的思路,感觉挺清楚的)
@ haventmetyou
递归的难点在于:找到可以递归的点 为什么很多人觉得递归一看就会,一写就废。 或者说是自己写无法写出来,关键就是你对递归理解的深不深。
对于此题: 递归的点怎么找?从拿到题的第一时间开始,思路如下:
1.怎么判断一棵树是不是对称二叉树? 答案:如果所给根节点,为空,那么是对称。如果不为空的话,当他的左子树与右子树对称时,他对称
2.那么怎么知道左子树与右子树对不对称呢?在这我直接叫为左树和右树 答案:如果左树的左孩子与右树的右孩子对称,左树的右孩子与右树的左孩子对称,那么这个左树和右树就对称。
仔细读这句话,是不是有点绕?怎么感觉有一个功能A我想实现,但我去实现A的时候又要用到A实现后的功能呢?
当你思考到这里的时候,递归点已经出现了: 递归点:我在尝试判断左树与右树对称的条件时,发现其跟两树的孩子的对称情况有关系。
想到这里,你不必有太多疑问,上手去按思路写代码,函数A(左树,右树)功能是返回是否对称
def 函数A(左树,右树): 左树节点值等于右树节点值 且 函数A(左树的左子树,右树的右子树),函数A(左树的右子树,右树的左子树)均为真 才返回真
实现完毕。。。
写着写着。。。你就发现你写出来了。。。。。。
//给定一个二叉树,检查它是否是镜像对称的。力扣101
//思路:先判断root的左子树和右子树是否为镜像关系再判断左子树和右子树是否根节点值是否相同
//再判断左树的左孩子与右树的右孩子是否相同&&左树的右孩子和右树的左孩子是否相同
public boolean isSymmetric(TreeNode root) {
if (root==null){
return true;
}
return isMirror(root.left,root.right);//调用一个辅助方法
}
private boolean isMirror(TreeNode l, TreeNode r) {
//3种情况
//左右子树都为空
if (l==null&&r==null){
return true;
}
//左右子树只有一个为空的情况
if (l==null||r==null){
return false;
}
//如果左右子树的根节点值不同,那肯定不是镜像
if (l.val!=r.val){
return false;
}
//左右子树都不为空,递归比较左右子树的左右子树是否为镜像
return isMirror(l.left,r.right)&&isMirror(l.right,r.left);
}