代码随想录 (programmercarl.com)
二叉树层序遍历
102.二叉树的层序遍历
队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
关键:如何确定一层已经遍历完了?
答:先按层存入队列,再记录队列大小,后面依次弹出队列。
!需要注意:tmp必须要在每次循环中都新定义一次,这样结果才正确。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Deque<TreeNode> deque = new LinkedList<>();
if (root == null){
return res;
}
deque.offer(root);
while (!deque.isEmpty()){
List<Integer> tmp = new ArrayList<>();
int size = deque.size(); //记录当前层的节点数量
while (size-- > 0){
TreeNode node = deque.poll();
tmp.add(node.val);
if (node.left != null){
deque.offer(node.left);
}
if (node.right != null){
deque.offer(node.right);
}
}
res.add(tmp);
}
return res;
}
}
107.二叉树的层序遍历Ⅱ
res.add(0, tmp);//表示每次tmp都插入到第一个位置上,这样就能得到倒序的结果
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Deque<TreeNode> dq = new LinkedList<>();
if (root == null){
return res;
}
dq.offer(root);
while (!dq.isEmpty()){
List<Integer> tmp = new ArrayList<>();
int size = dq.size();
while (size > 0){
TreeNode node = dq.poll();
tmp.add(node.val);
if (node.left != null){
dq.offer(node.left);
}
if (node.right != null){
dq.offer(node.right);
}
size--;
}
res.add(0, tmp);//表示每次tmp都插入到第一个位置上,这样就能得到倒序的结果
}
return res;
}
}
199.二叉树的右视图
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> dq = new LinkedList<>();
if (root == null){
return res;
}
dq.offer(root);
while (!dq.isEmpty()){
int size = dq.size();
for (int i = 0; i < size; i++) {
TreeNode node = dq.poll();
if (node.left != null) {
dq.offer(node.left);
}
if (node.right != null) {
dq.offer(node.right);
}
if (i == size - 1){
//将当前层的最后一个节点放入结果列表中
res.add(node.val);
}
}
}
return res;
}
}
637.二叉树的层平均值
注意:此处的sum一开始就要定义为double类型,否则计算出错。
假设计算9,20平均值
int sum = 0;
result.add((double)sum/size);
此时:double(29/2)=14.00000,而不是期望得到的14.50000。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> result = new ArrayList<>();
Deque<TreeNode> dq = new LinkedList<>();
if (root == null){
return result;
}
dq.offer(root);
while (!dq.isEmpty()){
int size = dq.size();
double sum = 0;
for (int i = 0; i < size; i++) {
TreeNode node = dq.poll();
sum += node.val;
if (node.left != null){
dq.offer(node.left);
}
if (node.right != null){
dq.offer(node.right);
}
}
result.add(sum/size);
}
return result;
}
}
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<>();
Deque<Node> dq = new LinkedList<>();
if (root == null) {
return res;
}
dq.offerLast(root);
while (!dq.isEmpty()) {
List<Integer> tmp = new ArrayList<>();
int size = dq.size();
while(size-- > 0) {
Node node = dq.pollFirst();
tmp.add(node.val);
List<Node> children = node.children;
if (children == null || children.size() == 0) {
continue;
}
for (Node child : children) {
if (child != null) {
dq.offerLast(child);
}
}
}
res.add(tmp);
}
return res;
}
}
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针Ⅱ
104.二叉树的最大深度
注意: TreeNode node = dq.poll();在循环内部,需要循环弹出。
class Solution {
public int maxDepth(TreeNode root) {
int res = 0;
Deque<TreeNode> dq = new LinkedList<>();
if(root == null){
return res;
}
dq.offer(root);
while (!dq.isEmpty()){
int size = dq.size();
while (size-- > 0){
TreeNode node = dq.poll();
if (node.left != null){
dq.offer(node.left);
}
if (node.right != null){
dq.offer(node.right);
}
}
res++;
}
return res;
}
}
111.二叉树的最小深度
使用广度优先搜索的方法,遍历整棵树。
当我们找到一个叶子节点时,直接返回这个叶子节点的深度。广度优先搜索的性质保证了最先搜索到的叶子节点的深度一定最小。
!注意:res++;的位置在一层遍历之后+1
class Solution {
public int minDepth(TreeNode root) {
int res = 1;
Deque<TreeNode> dq = new LinkedList<>();
if(root == null){
return 0;
}
dq.offer(root);
while (!dq.isEmpty()){
int size = dq.size();
while (size-- > 0){
TreeNode node = dq.poll();
if (node.left == null && node.right == null){
return res;
}
if (node.left != null){
dq.offer(node.left);
}
if (node.right != null){
dq.offer(node.right);
}
}
res++;
}
return res;
}
}
226.翻转二叉树(面试常见)
前序遍历和后序遍历的区别在于:
swapChildren(root);
invertTree(root.left);
invertTree(root.right);
此处为前序遍历,将swap放最后,是后序遍历。
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null){
return root;
}
swapChildren(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
public void swapChildren(TreeNode root){
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
101. 对称二叉树
只能使用后序遍历:收集孩子信息,向上一层返回
递归三部曲
- 确定递归函数的参数和返回值
- 确定终止条件
- 确定单层递归的逻辑
确定终止条件
节点为空的情况有:
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
节点不为空的情况有:
- 左右都不为空,比较节点数值,不相同就return false
确定单层递归的逻辑
单层递归的逻辑,单层递归的逻辑就是处理左右节点都不为空,且数值相同的情况。
- 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
- 比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
- 如果左右都对称就返回true ,有一侧不对称就返回false 。
-
class Solution { public boolean isSymmetric(TreeNode root) { return symmetric(root.left,root.right); } public boolean symmetric(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 compareOutside = symmetric(left.left, right.right); //比较内测 boolean compareInside = symmetric(left.right, right.left); return compareOutside && compareInside; } }