● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉树 2
层序遍历
1.思路
队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上
2.代码实现
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res= new ArrayList<List<Integer>>();
if(root==null)
return res;
Queue<TreeNode> que=new LinkedList<TreeNode>();
que.offer(root);
while(!que.isEmpty()){
List<Integer> itemList = new ArrayList<Integer>();
int len=que.size();
while(len--!=0){
TreeNode node=que.poll();
itemList.add(node.val);
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
res.add(itemList);
}
return res;
}
}
3.二叉树的层次遍历II
给定一个二叉树,返回其节点值自底向上的层次遍历。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
思路:
相对于102.二叉树的层序遍历,就是最后把result数组反转一下就可以了。
/**
* 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<>();
if(root==null)
return res;
Queue<TreeNode> que=new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
List<Integer> list=new ArrayList<>();
int len=que.size();
while(len--!=0){
TreeNode node= que.poll();
list.add(node.val);
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
res.add(list);
}
List<List<Integer>> res1= new ArrayList<>();
for(int i=res.size()-1;i>=0;i--){
res1.add(res.get(i));
}
return res1;
}
}
199.二叉树的右视图
链接: 题目
思路:
层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res= new ArrayList<>();
if(root==null)
return res;
Queue<TreeNode> que= new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
int len=que.size();
for(int i=0;i<len;i++){//遍历每一层
TreeNode node= que.poll();
if(i==len-1)
res.add(node.val);
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
}
return res;
}
}
637.二叉树的层平均值
链接: 题目
思路:
本题就是层序遍历的时候把一层求个总和在取一个均值。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res= new ArrayList<>();
if(root==null)
return res;
Queue<TreeNode> que= new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){
int len=que.size();
double sum=0;
for(int i=0;i<len;i++){//遍历每一层
TreeNode node= que.poll();
sum+=node.val;
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
sum/=len;
res.add(sum);
}
return res;
}
}
429.N叉树的层序遍历
链接: 题目
给定一个 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<List<Integer>>();
if(root==null)
return res;
Queue<Node> que=new LinkedList<Node>();
que.offer(root);
while(!que.isEmpty()){
List<Integer> itemList = new ArrayList<Integer>();
int len=que.size();
while(len--!=0){
Node node=que.poll();
itemList.add(node.val);
for(int i=0;i<node.children.size();i++){
if(node.children.get(i)!=null)
que.offer(node.children.get(i));
}
}
res.add(itemList);
}
return res;
}
}
515.在每个树行中找最大值
链接: 题目
思路:
层序遍历,取每一层的最大值
/**
* 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<Integer>();
if(root==null)
return res;
Queue<TreeNode> que=new LinkedList<TreeNode>();
que.offer(root);
while(!que.isEmpty()){
int len=que.size();
int maxValue=Integer.MIN_VALUE;
while(len--!=0){
TreeNode node=que.poll();
maxValue=Math.max(maxValue,node.val);
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
res.add(maxValue);
}
return res;
}
}
117.填充每个节点的下一个右侧节点指针II
链接: 题目
思路:
这道题目说是二叉树,但116题目说是完整二叉树,其实没有任何差别,一样的代码一样的逻辑一样的味道
/*
// 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) {
if(root==null)
return root;
Queue<Node> que=new LinkedList<Node>();
que.offer(root);
while(!que.isEmpty()){
int len=que.size();
Node node=null;
Node nodepre=null;
for(int i=0;i<len;i++){//遍历一层里的每一个结点
if(i==0){
nodepre=que.poll();
node=nodepre;
}
else{
node=que.poll();
nodepre.next=node;
nodepre=node;
}
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
}
return root;
}
}
104.二叉树的最大深度
链接: 题目
思路:
使用迭代法的话,使用层序遍历是最为合适的,因为最大的深度就是二叉树的层数,和层序遍历的方式极其吻合。
在二叉树中,一层一层的来遍历二叉树,记录一下遍历的层数就是二叉树的深度,
/**
* 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) {
if(root==null)
return 0;
Queue<TreeNode> que= new LinkedList<>();
que.offer(root);
int depth=0;
while(!que.isEmpty()){
depth++;
int len=que.size();
while(len--!=0){
TreeNode node=que.poll();
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
}
}
return depth;
}
}
111.二叉树的最小深度
链接: 题目
相对于 104.二叉树的最大深度 ,本题还也可以使用层序遍历的方式来解决,思路是一样的。
需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点
/**
* 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) {
if(root==null)
return 0;
Queue<TreeNode> que=new LinkedList<>();
que.offer(root);
int depth=0;
while(!que.isEmpty()){
int len=que.size();
depth++;
while(len--!=0){
TreeNode node=que.poll();
if(node.left!=null)
que.offer(node.left);
if(node.right!=null)
que.offer(node.right);
if(node.left==null && node.right==null)
return depth;
}
}
return depth;
}
}
● 226.翻转二叉树
1.思路
方法一:递归
方法二:用栈模拟深度优先遍历
方法三:层序遍历
就写了递归其他两种没写
2.代码实现
递归
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null)
return null;
swapchildren(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
private void swapchildren(TreeNode root){
TreeNode tmp= root.left;
root.left=root.right;
root.right=tmp;
}
}
● 101.对称二叉树 2
1.思路
首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!
对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了其实我们要比较的是两个树(这两个树是根节点的左右子树),所以在递归遍历的过程中,也是要同时遍历两棵树。
那么遍历的顺序应该是什么样的呢?
本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。
正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
但都可以理解算是后序遍历,尽管已经不是严格上在一个树上进行遍历的后序遍历了。
递归法
1.确定递归函数的参数和返回值
因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。
返回值自然是bool类型。
2.确定终止条件
要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。
节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
左节点为空,右节点不为空,不对称,return false
左不为空,右为空,不对称 return false
左右都为空,对称,返回true
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:
左右都不为空,比较节点数值,不相同就return false
此时左右节点不为空,且数值也不相同的情况我们也处理了。
注意左右节点都不为空,且数值相同的情况,这种情况下才会进入单层循环逻辑,判断下一层的树是否相同。
3.确定单层递归的逻辑
此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。
比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。
2.代码实现
class Solution {
public boolean compare(TreeNode left,TreeNode right){
if(left==null && right!=null)
return false;
else if(right==null && left!=null)
return false;
else if(left==null && right==null)
return true;
else if(left.val!=right.val)
return false;
//左右相等才会做下一层的判断
boolean outside,inside;
outside=compare(left.left,right.right);
inside=compare(left.right,right.left);
boolean isSame=outside && inside;
return isSame;
}
public boolean isSymmetric(TreeNode root) {
if(root==null)
return true;
return compare(root.left,root.right);
}
}