大家好!我是未来村村长,就是那个“请你跟我这样做,我就跟你这样做!”的村长👨🌾!
||Algorithm Day||
未来村村长正推出一系列【Algorithm Day】文章,该系列文章重在提高本人的算法能力,希望能在刷题过程中总结一般方法,提高个人的逻辑思维能力和解题能力。该系列文章以天数为轴,从一个个算法中逐步强化算法相关知识点。
”算法之路,任重而道远。“🌱|day 6|🌾
文章目录
[声明:以下题目的内容或部分解法来自牛客网或Leetcode,为个人学习总结和记录,也方便大家学习和查阅]
一、二叉树先中后序遍历
1、题目描述
(1)描述
给定一棵二叉树,分别按照二叉树先序,中序和后序打印所有的节点。
(2)示例
2、思路分析
前中后序遍历在代码实现上相似,都使用了递归的方法,递归方法比较基础,建议《全文背诵》。
3、Java实现
import java.util.*;
public class Solution {
public int[][] threeOrders (TreeNode root) {
//建立三个ArrayList作为装载容器
Lsit<Integer> prelist = new ArrayList<>();
Lsit<Integer> inlist = new ArrayList<>();
Lsit<Integer> postlist = new ArrayList<>();
//调用相关遍历方法
preOrder(list,root);
inOrder(list,root);
postOrder(list,root);
//建立结果集返回结果
int res[][] = new int[3][prelist.size()];
for(int i = 0;i<prelist.size();i++){
res[0][i] = prelist.get(i);
res[1][i] = inlist.get(i);
res[2][i] = postlist.get(i);
}
return res;
}
//前序遍历方法
public static void preOrder(List list,ListNode root){
//凡是递归都要记得return
if(root == null) return;
list.add(root.val);
preOrder(list,root.left);
preOrder(list,root.right);
}
//中序遍历方法
public static void inOrder(List list,ListNode root){
//凡是递归都要记得return
if(root == null) return;
list.add(root.val);
inOrder(list,root.left);
inOrder(list,root.right);
}
//后序遍历方法
public static void postOrder(List list,ListNode root){
//凡是递归都要记得return
if(root == null) return;
list.add(root.val);
postOrder(list,root.left);
postOrder(list,root.right);
}
}
4、相关知识补充
树的先中后序遍历是数据结构常考知识点,一般在选择题出现,给你一个先序后序,让你求个中序啥的,要记住不管是中序还是后序,都是先左再右,变的只是中间节点(双亲节点的输出位置)。
二、二叉树层序遍历
1、题目描述
(1)描述
给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历)
(2)示例
2、思路分析
利用队列的先进先出进行层序遍历,因为层序遍历的顺序就是从根结点开始逐层从左到右进行遍历输出,我们需要按如下顺序将树节点加入到队列中:
- 队列先加入根节点
- 取出根节点,将根节点的val放到list中
- 如果根节点有左子节点,队列加入左子节点
- 如果根节点有右子节点,队列加入右子节点
- 将队列的第一个节点视为根节点,继续执行
3、Java实现
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
//建立结果集
ArrayList<ArrayList<Integer>> res = new ArrayList();
//错误判断
if(root == null) return res;
//建立一个队列
Queue<TreeNode> queue = new ArrayDeque<>();
//先加入头节点
queue.add(root);
//迭代
while(!queue.isEmpty()){
//建立容器装载每一层的结果
ArrayList<Integer> row = new ArrayList<>();
//queue的大小
int size = queue.size();//有几个就输出几个
for(int i=0;i<size;i++){
TreeNode cur = queue.poll();//取出队列的头节点
row.add(cur.val);//加入到row中
if(cur.left!=null) queue.add(cur.left);
if(cur.right!=null) queue.add(cur.right);
}
res.add(row);
}
return res;
}
}
4、相关知识补充
树的层序遍历又叫做树的广度优先遍历(BFS),即从上往下逐层从左往右遍历,推荐使用上述的队列实现。
三、二叉树的最大深度
1、题目描述
(1)描述
求给定二叉树的最大深度,
深度是指树的根节点到任一叶子节点路径上节点的数量。
最大深度是所有叶子节点的深度的最大值。
(2)示例
2、思路分析
如下图(来源牛客网)所示:
因为是二叉树,我们可以从两边进行递归,直到叶子节点时,开始进行返回。每返回一层我们就进行加1,并比较左右两边子树的大小,返回较大值到上一层,最终可以获得最大深度。该递归的三要素为:
- 终止条件:当节点为null时,返回0
- 返回值:返回左右子树的深度的较大值
- 每级任务:向下遍历左右子树
3、Java实现
public class Solution {
public int maxDepth (TreeNode root) {
if(root==null) return 0;
return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1;
}
}
4、相关知识补充
(1)递归相关
使用递归我们要考虑以下三个要素:
- 终止条件:即什么时候开始返回到上一层
- 返回值:返回什么样的结果(递归如何执行)
- 每级任务:每层递归要做点什么,才开始进入下一级递归
(2)树的深度优先遍历
这题是取到最大深度采用了深度优先遍历的思想,深度优先遍历的代码如下
private void dfs(TreeNode root){
if (root!=null){
System.out.print(root.value);
dfs(root.left);
dfs(root.right);
}
}
我们发现这和前序遍历一模一样,确实,因为前序遍历和后序遍历都属于树的深度优先遍历。都是先顺着一条路走到底,然后再返回上一级再继续走。
四、合并二叉树
1、题目描述
(1)描述
已知两棵二叉树,将它们合并成一棵二叉树。合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。
(2)示例
2、思路分析
这里是将两个二叉树进行合并,这里的合并不是节点的合并,而是值的合并,都有则合并,一方有则用一方。合并的思路是使用前序遍历进行合并,具体的递归三要素为:
- 终止条件:当遍历到叶子节点,进行返回值返回
- 返回值:三种返回情况,一是返回新的合并节点,二是当二叉树t1对应节点为null使返回t2节点,三是当t2对应节点为null时返回t1节点【返回的值是节点】
- 本级任务:一是合并两个节点的值为新的节点,二是赋值节点的左节点和右节点为下一级递归返回
3、Java实现
public class Solution {
public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
//返回值
if(t1==null) return t2;
if(t2==null) return t1;
//本级任务
TreeNode cur = new TreeNode(t1.val+t2.val);
cur.left = mergeTrees(t1.left,t2.left);
cur.right = mergeTrees(t1.right,t2.right);
//返回值
return cur;
}
}
五、总结
(1)树的遍历
树的遍历有:前(中/后)序遍历、广度优先遍历(层序遍历)、深度优先遍历【前序遍历或后序遍历】。
(2)递归
之前我们主要强调要记得给递归设定终止条件并返回,这次总结了编写递归函数的三要素:
- 终止条件:执行到最后停止的条件
- 返回值:每层递归返回时向上返回的值
- 本级任务:每层递归一般要做两件事,一个是进入下一层递归,另一个是做一点坏事
如果有返回值,则说明是使用了分治的思想,即使用递归将问题逐步拆分,在返回时进行结果的合并。如果没有返回值只是为了干坏事,那只需要考虑终止条件和本级任务即可。