本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。
点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励!
系列文章目录
拓展目录
手把手教你用 ArrayList 实现杨辉三角:从逻辑推导到每行代码详解
目录
目录
前言
小编作为新晋码农一枚,会定期整理一些写的比较好的代码,作为自己的学习笔记,会试着做一下批注和补充,如转载或者参考他人文献会标明出处,非商用,如有侵权会删改!欢迎大家斧正和讨论!
本节,我将分享一下二叉树的习题部分,以及思路详解,在力扣 的运行环境,每一题将会附上练题链接,大家点击即可练习!
1.相同的树
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
题目链接:
https://leetcode.cn/problems/same-tree/description/


提示:
- 两棵树上的节点数目都在范围
[0, 100]内 -104 <= Node.val <= 104
严格按照:先结构 → 后值
步骤
- 判断结构
- 都空 → 结构相同 ✅
- 一个空一个不空 → 结构不同 ❌
- 判断值
- 值不同 → 树不同 ❌
- 递归判断左右子树
java
/**
* 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 {
//假设p的节点树为m,q的节点数为n
//时间复杂度O(min(m,n))
public boolean isSameTree(TreeNode p, TreeNode q) {
//1.先判断结构是否是一样的
if(p!=null&&q==null||p==null&&q!=null){
return false;
}
//上述if语句如果没有执行 意味着两个引用同时为空或者同时不为空
if(p==null&&q==null){
return true;
}
//都不为空 判断值是否一样
if(p.val!=q.val){
return false;
}
//都不为空且值一样
return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
}
}
2.另一棵树的子树
给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
题目链接:
https://leetcode.cn/problems/subtree-of-another-tree/description/

子树 = 必须包含某个节点 + 它的所有后代 不能少一个,也不能多一个!
也就是说:子树的空节点,必须和主树某棵子树的空节点 完全对应!

但是,这个情况不是的:

前半部分确实一样!但 主树的 2 有右孩子 5,子树的 2 没有!
→ 结构不一样! → isSameTree 返回 false! → 不是子树!
java
//相同的树
//严格按照:先结构 → 后值
//步骤
//判断结构
//都空 → 结构相同 ✅
//一个空一个不空 → 结构不同 ❌
//判断值
//值不同 → 树不同 ❌
//递归判断左右子树
public boolean isSameTree(TreeNode root1,TreeNode root2){
if(root1==null&&root2==null){
return true;
}
if(root1==null||root2==null){
return false;
}
if(root1.val!=root2.val){
return false;
}
return isSameTree(root1.left,root2.left)&&isSameTree(root1.right,root2.right);
}
//给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。
// 如果存在,返回 true ;否则,返回 false 。
//二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
public boolean isSubTree(TreeNode root,TreeNode root1){
if(root==null&&root1==null){
return true;
}
if(isSameTree(root,root1)||isSameTree(root.left,root1.left)||isSameTree(root.right,root1.right)) return true;
return false;
}
3.翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
题目链接:
java
//给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
public TreeNode binaryTreeInversion(TreeNode root){
if(root==null){
return null;
}
TreeNode node=root.left;
root.left=root.right;
root.right=node;
binaryTreeInversion(root.left);
binaryTreeInversion(root.right);
return root;
}
4.平衡二叉树
给定一个二叉树,判断它是否是 平衡二叉树
题目链接:
https://leetcode.cn/problems/balanced-binary-tree/description/
- 写一个求高度方法
getHeight - 判空
- 算左右高度
- 差 >1 返回 false
- 递归判断左右子树
java
/**
* 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 int nodeHeight(TreeNode root){
if(root==null){
return 0;
}
int leftHeight=nodeHeight(root.left);
int rightHeight=nodeHeight(root.right);
return Math.max(leftHeight,rightHeight)+1;
}
//判断是否是平衡树
public boolean isBalanced(TreeNode root) {
if(root==null){
return true;
}
int leftheight=nodeHeight(root.left);
int rightheight=nodeHeight(root.right);
if(Math.abs(leftheight-rightheight)>1){
return false;
}
return isBalanced(root.left)&&isBalanced(root.right);
}
}
5.对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称。
题目链接:
- 空树对称 ✅
- 外侧对称(左 ↔ 右) ✅
- 内侧对称(右 ↔ 左) ✅
- 值必须相等 ✅
java
//是否是对称二叉树
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return isMirror(root.left,root.right);
}
public boolean isMirror(TreeNode root1,TreeNode root2){
if(root1==null&&root2==null){
return true;
}
if(root1==null||root2==null){
return false;
}
if(root1.val!=root2.val){
return false;
}
return isMirror(root1.left,root2.right)&&isMirror(root1.right,root2.left);
}
6.二叉树遍历
描述
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中"#"表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过100。
输出描述:
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。
- # = null
- 先序建树:根 → 左 → 右
- index 必须全局,每次输入重置为 0
java
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
//// 静态内部类(static修饰)
static class TreeNode{ //关键是static
public char val;
public TreeNode left;//存储左孩子的引用
public TreeNode right;//存储右孩子的引用
public TreeNode(char val){
this.val=val;
//this.left=null;
//this.right=null;
//默认是null
}
}
public static int index=0;
public static TreeNode createTree(String str){
char sc=str.charAt(index);
index++;
if(sc=='#'){
return null;
}
TreeNode curNode=new TreeNode(sc);
curNode.left=createTree(str);
curNode.right=createTree(str);
return curNode;
}
public static void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 多组字符串输入(正确写法)
while (in.hasNext()) {
String str = in.next();
index = 0; // 每次重置下标
TreeNode root = createTree(str);
inOrder(root);
System.out.println();
}
}
}
7.二叉树的层序遍历
描述
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

提示:
- 树中节点数目在范围
[0, 2000]内 -1000 <= Node.val <= 1000
java
/**
* 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 List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res=new ArrayList<>();
if(root==null){
return res;
}
// 1. 创建队列
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
// 2. 循环遍历
while(!queue.isEmpty()){
int size=queue.size();
List<Integer> curLevel=new ArrayList<>();
for(int i=0;i<size;i++){
// 取出队首节点
TreeNode cur=queue.poll();
curLevel.add(cur.val);
// 左孩子不为空,入队
if (cur.left != null) queue.offer(cur.left);
// 右孩子不为空,入队
if (cur.right != null) queue.offer(cur.right);
}
res.add(curLevel);
}
return res;
}
}
8.二叉树最近的公共祖先
描述
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。"

我们用这棵树
bash
A
/ \
B C
/
D
我们要找:D 和 C 的最近公共祖先 答案应该是:A
正式开始!跟着我走👇
函数入口:lowestCommonAncestor(A, D, C)
第一步:看 A
- A 不是 null,不是 D,不是 C
- 递归查左:
left = lowestCommonAncestor(B, D, C) - 递归查右:
right = lowestCommonAncestor(C, D, C)
先处理左边:lowestCommonAncestor(B, D, C)
-
B 不是 null,不是 D,不是 C
-
递归查左:
left = lowestCommonAncestor(D, D, C) -
递归查右:
right = lowestCommonAncestor(null, D, C)
再处理左边:lowestCommonAncestor(D, D, C)
- D == D
- 直接返回 D!
处理右边:lowestCommonAncestor(null, D, C)
- root == null
- 直接返回 null!
回到 B 节点
现在我们有:
- left = D
- right = null
判断:
- 不是两边都有
- 返回 left → D
现在回到 A 的右边:lowestCommonAncestor(C, D, C)
- C == C
- 直接返回 C!
最终回到 A 节点!
现在我们手里有:
- left = D
- right = C
java
if (left != null && right != null) {
return root;
}
- 左边 找到了
- 右边 找到了 → 返回 A!
流程结束
答案就是 A!
java
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||root==q||root==p){
return root;
}
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
if(left!=null&&right!=null){
return root;
}
return left!=null?left:right;
}
总结
以上就是今天要讲的内容,本文简单记录了java数据结构,仅作为一份简单的笔记使用,大家根据注释理解,您的点赞关注收藏就是对小编最大的鼓励!