代码随想录算法训练营第13天 | 复习二叉树基础
2024年7月15日
二叉树
前序遍历,前就是指根在前,递归要注意判断节点为空。
如果不用递归,就用一个栈来保存节点。
/**
* 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<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
return first(root,list);
}
public List<Integer> first(TreeNode root, List<Integer> list){
if(root==null){
return list;
}
list.add(root.val);
if(root.left!=null){
list = first(root.left,list);
}
if(root.right!=null){
list = first(root.right,list);
}
return list;
}
}
后序,就是根最后。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
return back(root,list);
}
public List<Integer> back(TreeNode root, List<Integer> list){
if(root==null){
return list;
}
if(root.left!=null){
list = back(root.left,list);
}
if(root.right!=null){
list = back(root.right,list);
}
list.add(root.val);
return list;
}
}
中序,就是根节点在中间。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
return med(root,list);
}
public List<Integer> med(TreeNode root, List<Integer> list){
if(root==null){
return list;
}
if(root.left!=null){
list = med(root.left,list);
}
list.add(root.val);
if(root.right!=null){
list = med(root.right,list);
}
return list;
}
}
迭代遍历
前序,就要先把root加入,然后进入while循环,每次循环先取一个,如果不空,就加入结果并压入右和左(返回来压才是左先出)。
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
//用一个栈存放节点
//前序遍历就是根左右
//队列实现,先放左再放右
//从队列取出来的时候就是遍历其右子树
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
// res.add(root.val);
TreeNode q = root.left;
while(!stack.isEmpty()){
q = stack.pop();
if(q!=null){
res.add(q.val);
stack.push(q.right);
stack.push(q.left);
}
}
return res;
}
}
中序遍历
左根右,那么就是先将right,root和left依次入栈,然后进入循环,每次先取出,如果不为空,就再次将right,root和left依次入栈;如果为空,就说明左侧到终点了。此时首先判断栈是否为空,如果不为空就先取出一个,并放入结果,然后continue即可。
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
//中序就是左根右
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root.right);
stack.push(root);
stack.push(root.left);
TreeNode q;
while(!stack.isEmpty()){
q = stack.pop();
if(q!=null){
stack.push(q.right);
stack.push(q);
stack.push(q.left);
}else{
if(!stack.isEmpty()){
q = stack.pop();
res.add(q.val);
}
}
}
return res;
}
}
后序遍历
左右根,首先按照根右左的顺序压root及其右左,然后将root的左右指针设置为null,这么做的目的是让后序循环不会反复上下死循环。然后进入循环取出q,判断其是为空。如果不为空,就再次判断其是否同时没有左右子树。如果都没有,就输出其,并continue;否则再次按照q及其右左子树压入栈,并将左右指针设null。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
//后序就是左右根
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
stack.push(root.right);
stack.push(root.left);
root.left=null;
root.right=null;
TreeNode q;
while(!stack.isEmpty()){
q = stack.pop();
if(q!=null){
if(q.left==null && q.right==null){
res.add(q.val);
continue;
}
else{
stack.push(q);
stack.push(q.right);
stack.push(q.left);
q.left=null;
q.right=null;
}
}
}
return res;
}
}
题102. 二叉树的层序遍历
用height记录,递归遍历的时候用前序遍历就是从左到右,遍历的同时记录即可。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
return res;
}
public List<List<Integer>> digui(List<List<Integer>> res,int height,TreeNode p){
if(res.size()<height+1){
List<Integer> res1 = new ArrayList<>();
res.add(res1);
}
int val = p.val;
res.get(height).add(val);
if(p.left!=null){
res = digui(res,height+1,p.left);
}
if(p.right!=null){
res = digui(res,height+1,p.right);
}
return res;
}
}
题107. 二叉树的层次遍历II
可以用头插法,也可以直接倒序。
题199. 二叉树的右视图
可以用层序遍历之后,取出每一层的最后一个元素即可。
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> res2 = new ArrayList<>();
if(root==null){
return res2;
}
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
for(List<Integer> v:res){
res2.add(v.get(v.size()-1));
}
return res2;
}
public List<List<Integer>> digui(List<List<Integer>> res,int height,TreeNode p){
if(res.size()<height+1){
List<Integer> res1 = new ArrayList<>();
res.add(res1);
}
int val = p.val;
res.get(height).add(val);
if(p.left!=null){
res = digui(res,height+1,p.left);
}
if(p.right!=null){
res = digui(res,height+1,p.right);
}
return res;
}
}
题637. 二叉树的层平均值
使用层序遍历后即可求平均。
题429. N叉树的层序遍历
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return res;
}
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
return res;
}
public List<List<Integer>> digui(List<List<Integer>> res,int height,Node p){
if(res.size()<height+1){
List<Integer> res1 = new ArrayList<>();
res.add(res1);
}
int val = p.val;
res.get(height).add(val);
for(Node p1:p.children){
res = digui(res,height+1,p1);
}
return res;
}
}
题515. 在每个树行中找最大值
继续使用层序遍历的模板。
记住API是Integer.MIN_VALUE。
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> res2 = new ArrayList<>();
if(root==null){
return res2;
}
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
for(List<Integer> v:res){
int max = Integer.MIN_VALUE;
for(int i=0;i<v.size();i++){
if(v.get(i)>max){
max = v.get(i);
}
}
res2.add(max);
}
return res2;
}
public List<List<Integer>> digui(List<List<Integer>> res,int height,TreeNode p){
if(res.size()<height+1){
List<Integer> res1 = new ArrayList<>();
res.add(res1);
}
int val = p.val;
res.get(height).add(val);
if(p.left!=null){
res = digui(res,height+1,p.left);
}
if(p.right!=null){
res = digui(res,height+1,p.right);
}
return res;
}
}
题116. 填充每个节点的下一个右侧节点指针
题117. 填充每个节点的下一个右侧节点指针 II
先使用层序遍历记下每个节点,然后遍历每一层并加上指针即可,两个题可以用一样的代码。
class Solution {
public Node connect(Node root) {
List<List<Node>> res = new ArrayList<>();
if(root==null){
return root;
}
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
for(List<Node> list:res){
for(int i=0;i<list.size();i++){
if(i==list.size()-1){
list.get(i).next=null;
}else{
list.get(i).next=list.get(i+1);
}
}
}
return root;
}
public List<List<Node>> digui(List<List<Node>> res,int height,Node p){
if(res.size()<height+1){
List<Node> res1 = new ArrayList<>();
res.add(res1);
}
res.get(height).add(p);
if(p.left!=null){
res = digui(res,height+1,p.left);
}
if(p.right!=null){
res = digui(res,height+1,p.right);
}
return res;
}
}
题104. 二叉树的最大深度
层序遍历后返回list长度即可,注意判断root为空就返回0。
题111. 二叉树的最小深度
用一个属性来记录,当左右子树都为null时,就记录当前高度。如果更小,就记下来。
class Solution {
public int minHeight;
public int minDepth(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if(root==null){
return 0;
}
minHeight=Integer.MAX_VALUE;
//用根左右遍历,每次记录高度
int height=0;
res = digui(res,height,root);
return minHeight;
}
public List<List<Integer>> digui(List<List<Integer>> res,int height,TreeNode p){
if(res.size()<height+1){
List<Integer> res1 = new ArrayList<>();
res.add(res1);
}
int val = p.val;
res.get(height).add(val);
if(p.left==null && p.right==null){
if(minHeight>height+1){
minHeight=height+1;
}
return res;
}
if(p.left!=null){
res = digui(res,height+1,p.left);
}
if(p.right!=null){
res = digui(res,height+1,p.right);
}
return res;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端