102.二叉树的层序遍历
文章链接:代码随想录 (programmercarl.com)
思路:层序遍历应该使用前序遍历(思路出错,层序遍历可不是三种遍历方式,不一样),此外还需要每时每刻都记录一下当前栈里的元素个数(为每个树层的元素个数),这样才能达到层序遍历(不能用栈!)
看完文章的反思:不应该用栈!要用队列,因为是要每个树层从左向右遍历,用栈会出错;其余思路正确
代码实现出现的问题:
(1)LinkedList<Integer> path = new LinkedList<>();作为全局变量了,这样就导致只有一个path,应该将其放在while循环里,即每到一个树层就新建一个path开始存储
(2)应该用队列
Java代码:
/**
* 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 {
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
//先判断特殊情况
if(root == null){
return result;
}
Queue<TreeNode> st = new LinkedList<>();
st.offer(root);
while(!st.isEmpty()){
//size代表每个树层的元素个数
int size = st.size();//记录当前队列中的元素个数
LinkedList<Integer> path = new LinkedList<>();//只有LinkedList才有removeLast()方法
while(size > 0){//进队列中左右
TreeNode cur = st.poll();
path.add(cur.val);
if(cur.left != null){
st.offer(cur.left);
}
if(cur.right != null){
st.offer(cur.right);
}
size--;
}
//该树层遍历完,且都加入到path中后
result.add(path);
}
//当栈为空,说明该树已经全部遍历完
return result;
}
}
226.翻转二叉树
文章链接:代码随想录 (programmercarl.com)
思路:
(1)递归法思路:本质就是交换左右孩子(深度遍历,由叶子节点开始交换,逐步向上返回),使用递归,需要自己定义一个交换左右孩子的方法
(2)迭代法思路:就是在正常三种遍历方式中加入一行交换左右孩子的代码,之前前序遍历迭代法是加入到list这一操作,现在这一步就应该变成操作节点,交换左右孩子
看完文章后的反思:为什么不可以使用中序遍历,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)
226. 翻转二叉树 - 力扣(Leetcode)里有个动画很形象,非常有助于理解
Java递归代码(前序遍历):
/**
* 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 null;
}
//确定单层逻辑
swapChildren(root);
invertTree(root.left);
invertTree(root.right);
return root;
}
private void swapChildren(TreeNode root){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
Java迭代法代码(前序遍历):
/**
* 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 null;
}
Stack<TreeNode> st = new Stack<>();
st.push(root);
while(!st.isEmpty()){
TreeNode cur = st.pop();
//之前前序遍历迭代法到这一步是加入到list这一操作
//现在这一步就应该变成操作节点,交换左右孩子
swapChildren(cur);
if(cur.right != null){
st.push(cur.right);
}
if(cur.left != null){
st.push(cur.left);
}
}
return root;
}
private void swapChildren(TreeNode root){
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
101.对称二叉树
文章链接:代码随想录 (programmercarl.com)
思路:
(1)递归法思路:比较外层的值是否相等,然后比较内层的值是否相等,后面就没思路了
(2)迭代法思路:无思路
看完文章后的反思:
(1)本题使用后续遍历:因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
(2)递归中确定终止条件时,要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。节点为空的情况有:(注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点)
- 左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
- 左右都不为空,比较节点数值,不相同就return false
(3)确定单层递归的逻辑:此时才进入单层递归的逻辑,单层递归的逻辑就是处理 左右节点都不为空,且数值相同的情况。
- 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
- 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
- 如果左右都对称就返回true ,有一侧不对称就返回false 。
(4)迭代法:使用普通队列
Java递归代码:
/**
* 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 isSameLR(root.left,root.right);
}
//传入的两个参数表示的是左子树节点和右子树节点
private boolean isSameLR(TreeNode left,TreeNode right){
//(2)确定终止条件,为空指针的情况
if(left == null && right != null){
return false;
}
else if(left != null && right == null){
return false;
}
else if(left == null && right == null){
return true;
}
//不为空,但值不相同
else if(left.val != right.val){
return false;
}
//(3)确定单层逻辑(左右中)
boolean outside = isSameLR(left.left,right.right);
boolean inside = isSameLR(left.right,right.left);
return outside && inside;
}
}
Java迭代法代码:
/**
* 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 {
Queue<TreeNode> que = new LinkedList<>();
public boolean isSymmetric(TreeNode root) {
//使用迭代法,先判断特殊情况
if(root == null){
return true;
}
que.offer(root.left);
que.offer(root.right);
while(!que.isEmpty()){
TreeNode leftnode = que.poll();
TreeNode rightnode = que.poll();
//开始判断
if(leftnode == null && rightnode == null){
continue;
}
if(leftnode == null || rightnode == null || leftnode.val != rightnode.val){
return false;
}
que.offer(leftnode.left);
que.offer(rightnode.right);
que.offer(leftnode.right);
que.offer(rightnode.left);
}
return true;
}
}