leetcode
102 层序遍历(图论里广度优先搜索)
题目链接
二叉树本身结构是无法做到层序遍历的 因为又要保存元素的孩子元素 又要保存该元素所在层次——故利用队列来保存我们遍历过的元素
- 根结点6加入到队列中 队列中为6 size记录队列大小为1(也代表本层有几个元素)
- 6弹出队列 6的左右孩子入队列 队列为4 7 size=2
- 弹出两个元素 因为size为2 先弹出4 为6 4 size变为1 而后将4的左右孩子入队列 队列中7 1 3
- 弹出7 为6 4 7 size为0 而后将7的左右孩子入队列 队列中1 3 5 8 size为4
- 弹出1 3 5 8 因为已经是最后一层了
/**
* 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>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun02(root);
return resList;
}
//BFS--迭代方式--借助队列
public void checkFun02(TreeNode node) {
// 判断有无根结点
if (node == null) return;
// 创建队列
Queue<TreeNode> que = new LinkedList<TreeNode>();
// 将根结点存入队列中
que.offer(node);
// 队列为空 那就意味着没有元素添加进来了 层序遍历就结束了
while (!que.isEmpty()) {
// 用一个一维数组来存放每一层的元素 一层一个数组 最后返回的结果应该是个二维数组
List<Integer> itemList = new ArrayList<Integer>();
// 记录当前层结点的个数 用来控制队列里弹出结点的个数
int len = que.size();
// 遍历每一层的元素 那么size大小应该>0
while (len > 0) {
// 获取队列的第一个元素
TreeNode tmpNode = que.poll();
// 把元素存入数组中
itemList.add(tmpNode.val);
// 将结点的左右孩子加入队列中
if (tmpNode.left != null) que.offer(tmpNode.left);
if (tmpNode.right != null) que.offer(tmpNode.right);
len--;
}
// 存入二维数组中
resList.add(itemList);
}
}
}
226.翻转二叉树
题目链接
应该用递归还是用层序?递归的话用前中后哪一种——用前序或者后序是最方便的
- 确实递归函数的返回值和参数:返回值是结点定义 参数就是传入的根结点
- 确定终止条件:碰到空结点的时候
- 处理逻辑:
前序:根左右——要处理的是交换root的左右孩子 swap(root.left,root.right) (root指的是遍历的每一个结点 不一定是树的根结点) 而后向左 向右遍历invertTree(root.left); invertTree(root.right);
后序:和前序逻辑类似 只是最后invertTree顺序不一致
但是中序——如果将swap放在invertTree左右之中 因为先左孩子交换孩子 再根交换孩子(做完后,右孩子已经变成了原来的左孩子) 再右孩子交换孩子(此时其实是对原来的左孩子做交换)若要用中序可以写成处理两次invertTree左边
/**
* 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;
}
invertTree(root.left);
invertTree(root.right);
swapChildren(root);
return root;
}
private void swapChildren(TreeNode root) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
101.对称二叉树
题目链接
思路:
- 本质上是判断二叉树根结点的左右子树是否可以相互翻转
- 如何判断左右子树能否翻转呢——比较的是外侧的结点是否相等 + 内侧的结点是否相等
应该用递归还是用层序?递归的话用前中后哪一种
- 只能使用后序:后序是根左右 因为要不断收集左右孩子的信息返回给上一个结点 这样才能知道是否可以互相翻转
- 假设如果使用中序:左根右 那么左子树处理完了 返回给中结点了 右子树还不知道具体如何了
- 假设如果使用前序:根左右 那么一上来就处理左右字数了 不知道到底能不能翻转
要收集孩子信息 并向上一层返回 必须要用后序遍历
/**
* 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);
}
private boolean compare(TreeNode left, TreeNode right) {
// 左结点为空 右结点不为空 不能翻转
if (left == null && right != null) {
return false;
}
// 左结点不为空 右结点为空 不能翻转
if (left != null && right == null) {
return false;
}
// 左右都为空
if (left == null && right == null) {
return true;
}
// 左右值不相等
if (left.val != right.val) {
return false;
}
// 左右结点都不为空 且值相等 那就要继续遍历下去
// 是从最下面开始比较的
// 比较外侧 左结点的左孩子vs右结点的右孩子
boolean compareOutside = compare(left.left, right.right);
// 比较内侧
boolean compareInside = compare(left.right, right.left);
// 告诉父结点 是否对称
return compareOutside && compareInside;
}
}