代码随想录算法训练营第15天 | 层序遍历 ,226.翻转二叉树 (优先掌握递归) ,101. 对称二叉树 (优先掌握递归)
102.二叉树的层序遍历
- 因为二叉树无法遍历到一层一层 所以需要借助队列
- 每一层的循环时 用一个变量size去存 这一层节点的数量 这样才可以做到每一层存入一个数组
- 然后每次弹出一个节点时 添加这个节点的 左右节点进入队列 等到这一层全部pop掉 那么size就会重新统计下一次的元素数量
- 注意点 判断是否有左右节点时 要用2个if 意思为都要去判断 而不是用else if
- 还有 一定要用size去存下每一层的元素个数 而不是用queue.size()因为它一直会变 会加入下一层的元素
/**
* 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) {
Deque<TreeNode> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
List<List<Integer>> res = new ArrayList<>();
while(!que.isEmpty()){
int size = que.size();
List<Integer> arr = new ArrayList<>();
while(size--!=0){
TreeNode node = que.pollFirst();
arr.add(node.val);
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
// size--;
}
res.add(arr);
}
return res;
}
}
107.二叉树的层次遍历 II
- 此题需要从底向上 层序遍历二叉树 可以先从上到下遍历 然后将结果数组 反转
- 字符串的反转方法 为头尾双指针交换值
- 数组的反转方法 再新建一个数组 然后从后向前遍历原数组 添加至新数组
/**
* 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>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Deque<TreeNode> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
List<Integer> arr = new ArrayList<>();
while(size--!=0){
TreeNode node = que.pollFirst();
arr.add(node.val);
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
res.add(arr);
}
List<List<Integer>> result = new ArrayList<>();
for(int i = res.size()-1;i>=0;i--){
result.add(res.get(i));
}
return result;
}
}
199.二叉树的右视图
- 层序遍历的时候判断是否已经遍历到当前层的最后一个节点 如果是就加入结果数组
/**
* 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> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
while(size--!=0){
TreeNode node = que.pollFirst();
if(size==0){
res.add(node.val);
}
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
}
return res;
}
}
637.二叉树的层平均值
- 层序遍历 每一层遍历的时候求和 然后遍历结束的时候求 平均值
/**
* 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<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
Deque<TreeNode> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
int size2 = size;
Double sum=0.0;
while(size--!=0){
TreeNode node = que.pollFirst();
sum+=node.val;
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
Double avg = sum/size2;
res.add(avg);
}
return res;
}
}
429. N 叉树的层序遍历
- 一个节点可能有多个孩子 当添加节点的子节点时 去遍历子节点的数组 判断是否存在 并加入结果数组即可
- 定义n叉树的 构造器里面每个Node有可能有children数组 里面存他的子节点
/*
// 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<>();
Deque<Node> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
List<Integer> arr = new ArrayList<>();
while(size--!=0){
Node node = que.pollFirst();
arr.add(node.val);
//构造器里面每个Node有可能有children数组 里面存他的子节点
for(Node child:node.children){
if(child!=null){
que.addLast(child);
}
}
}
res.add(arr);
}
return res;
}
}
515.在每个树行中找最大值
- Integer.MAX_VALUE 默认的最大值 Integer.MIN_VALUE 默认的最小值
- 每一层遍历 比出一个最大值 赋给结果数组
/**
* 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> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int max = Integer.MIN_VALUE;
int size = que.size();
while(size--!=0){
TreeNode node = que.pollFirst();
max = Math.max(max,node.val);
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
res.add(max);
}
return res;
}
}
116.填充每个节点的下一个右侧节点指针
- 双指针的思路 来建立每一层的链表指向
- 在每一层中用node作为新pop出来的节点作为下一个需要被指向的节点 然后nodepre作为前一个没有被更新的节点
- 然后用Nodepre指向Node 最后每一层结束 用Nodepre 指向Null
- 然后每一层刚开始 的第一个节点 Node 和 nodepre都赋值 第一个pop出的节点 然后都需要
- 然后同样 每次pop出新节点后 也是要看看新节点有没有 左右子节点 有的话 就加在队列的最后段 然后用size控制着每一层的遍历循环
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
Deque<Node> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
Node nodepre = new Node();
Node node = new Node();
for(int i = 0;i<size;i++){
if(i==0){
nodepre = que.pollFirst();
node = nodepre;
//node = nodepre;
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}else{
node = que.pollFirst();
nodepre.next = node;
nodepre = nodepre.next;
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
}
nodepre.next = null;
}
return root;
}
}
117.填充每个节点的下一个右侧节点指针II
- 此题与上一题类似 同样是用指针指向右边
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
Deque<Node> que = new LinkedList<>();
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
Node prenode = new Node();
Node node = new Node();
for(int i = 0; i<size;i++){
if(i==0){
prenode = que.pollFirst();
node = prenode;
}else{
node = que.pollFirst();
prenode.next = node;
prenode = prenode.next;
}
if(node.left!=null){
que.addLast(node.left);
}
if(node.right!=null){
que.addLast(node.right);
}
}
prenode.next = null;
}
return root;
}
}
104.二叉树的最大深度
- 每一层遍历完 depth++
/**
* 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 maxDepth(TreeNode root) {
Deque<TreeNode> que = new LinkedList<>();
int depth = 0;
if(root!=null){
que.addLast(root);
}
while(!que.isEmpty()){
int size = que.size();
while(size--!=0){
TreeNode node = que.pollFirst();
if(node.left!=null) que.addLast(node.left);
if(node.right!=null) que.addLast(node.right);
}
depth++;
}
return depth;
}
}
111.二叉树的最小深度
- 在每一层遍历中加上判断左节点和右节点是否存在 若都不存在 就直接返回 mindepth
- 初始化 Mindepth=1 root存在时
/**
* 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 minDepth(TreeNode root) {
Deque<TreeNode> que = new LinkedList<>();
int mindepth = 1;
if(root!=null){
que.addLast(root);
}else{
return 0;
}
while(!que.isEmpty()){
int size = que.size();
while(size--!=0){
TreeNode node = que.pollFirst();
if(node.left==null && node.right==null) return mindepth;
if(node.left!=null) que.addLast(node.left);
if(node.right!=null) que.addLast(node.right);
}
mindepth++;
}
return mindepth;
}
}
226.翻转二叉树
- 思路比较清楚 就是去遍历每一个节点 让每一个节点交换左右子节点
- 前中后递归遍历 通过自己模拟一遍流程 发现 前后序遍历可以翻转 但是 中序遍历翻转较为麻烦
- 此外就是递归三部曲
- 参数传入 节点
- 结束条件 当节点为空 开始返回
- 逻辑操作 为前序或者后序
前序递归
/**
* 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 TreeNode invertTree(TreeNode root) {
// if(root==null) return root;
preorder(root);
return root;
}
public void preorder(TreeNode node){
if(node==null) return;
//中左右
//交换左右子节点
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
preorder(node.left);
preorder(node.right);
}
}
广度优先遍历 层序遍历
- 每一层都反转他们的子节点 也可以 这样也能遍历完所有节点
/**
* 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 TreeNode invertTree(TreeNode root) {
//广度优先搜索 层序遍历 用一个辅助队列
Deque<TreeNode> que = new LinkedList<>();
if(root!=null) que.addLast(root);
while(!que.isEmpty()){
int size = que.size();
while(size--!=0){
TreeNode node = que.pollFirst();
swap(node);
if(node.left!=null) que.addLast(node.left);
if(node.right!=null) que.addLast(node.right);
}
}
return root;
}
public void swap(TreeNode node){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}
}
101. 对称二叉树
- 要相对于中轴线 比较 外侧节点是否相等 内侧节点是否相等 外侧节点 为左边子树的左节点 右边子树的右节点
- 遍历方式选择 后序遍历 因为这样才可以处理判断完 两个左右子节点 是否相等 然后再return
- 创建一个compare函数 判断有哪些情况为true false 左为空 右不为空 false 左不为空 右为空 false 左边右边值不相等 false
- 递归三部曲中 传入的参数 为根节点的左子树和 根节点的右子树 就是比较他们是否对称
- 终止条件
- 左为空 右不为空 false
- 左不为空 右为空 false
- 左为空 右为空 true 因为下面没有节点可以继续向下遍历了 所以直接return
- 左不为空 右不为空 但是值不相等 false
- 左不为空 右不为空 值相等不能作为终止条件 因为这种情况还要继续向下面遍历 是递归三部曲的第三部
- 递归的第三步 逻辑操作 后序遍历顺序 左右中 获取到外侧 和 内侧 的返回值 然后 判断外侧和内侧是否都true 然后往上面返回 即左右中 左右就是继续往下面遍历 中就是处理当前节点的情况
/**
* 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 boolean isSymmetric(TreeNode root) {
return compare(root.left,root.right);
}
public boolean compare(TreeNode left,TreeNode right){
//终止条件return
if(left==null && right!=null) return false;
if(right==null && left!=null) return false;
if(left==null && right==null) return true;
if(left.val!=right.val) return false;
boolean outside = compare(left.left,right.right);
boolean inside = compare(left.right,right.left);
return outside && inside;
}
}