102.二叉树层序遍历
题目链接:102. 二叉树的层序遍历 - 力扣(LeetCode)
层序遍历的模板写法,深度优先搜索使用栈,广度优先搜索则使用队列来辅助实现:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
// 栈是深度优先遍历,队列则是层序优先遍历
Queue<TreeNode> que = new LinkedList<>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();
if(root == null) return ans;
que.offer(root);
while(!que.isEmpty()){
ArrayList<Integer> arrayList = new ArrayList<>();
int size = que.size();
while(size-- > 0){
TreeNode cur = que.poll();
arrayList.add(cur.val);
if(cur.left != null) que.offer(cur.left);
if(cur.right != null) que.offer(cur.right);
}
ans.add(arrayList);
}
return ans;
}
}
递归法解题:
增加了一个深度用来记录当前遍历的元素所在的二叉树的深度。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
// 递归写法?
ArrayList<List<Integer>> ans = new ArrayList<List<Integer>>();
levOrder(root, ans, 0);
return ans;
}
void levOrder(TreeNode root, List<List<Integer>> list, int depth){
if(root == null) return;
depth++;
if(depth > list.size()){
ArrayList<Integer> iList = new ArrayList<Integer>();
list.add(iList);
}
list.get(depth - 1).add(root.val);
levOrder(root.left, list, depth);
levOrder(root.right, list, depth);
}
}
226.翻转二叉树
题目链接:Loading Question... - 力扣(LeetCode)
递归解法:还是想好递归的结束条件以及每一层需要做的事情。以及做的处理和改变用什么去保存。这个题最终需要的是树的根节点,而不是数组之类的东西,所以递归的时候除了根节点以外并不需要携带额外的参数。
class Solution {
public TreeNode invertTree(TreeNode root) {
// 递归解法
swapTreeNode(root);
return root;
}
void swapTreeNode(TreeNode root){
// 结束条件
if(root == null) return;
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
swapTreeNode(root.right);
swapTreeNode(root.left);
}
}
层序遍历迭代求解:
在层序遍历的同时夹带私货将交换的操作放进去即可。
class Solution {
public TreeNode invertTree(TreeNode root) {
// 层序遍历一个一个翻转 借助队列实现
if(root == null) return root;
Queue<TreeNode> que = new LinkedList<>();
que.offer(root);
while(!que.isEmpty()){ // 队列不为空时
int size = que.size();
while(size-- > 0){
TreeNode cur = que.peek();
que.poll();
TreeNode tmp = cur.left;
cur.left = cur.right;
cur.right = tmp;
if(cur.left != null) que.offer(cur.left);
if(cur.right != null) que.offer(cur.right);
}
}
return root;
}
}
迭代法前序遍历方式翻转二叉树:
class Solution {
public TreeNode invertTree(TreeNode root) {
// 先序遍历翻转二叉树
if(root == null) return root;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
stk.pop();
if(cur.right != null) stk.push(cur.right);
if(cur.left != null) stk.push(cur.left);
TreeNode tmp = cur.left;
cur.left = cur.right;
cur.right = tmp;
}
return root;
}
}
迭代法中序遍历方式翻转二叉树:
关键点是为什么while里的if和else最后的cur指针都指向了cur的左孩子。这个需要思考清楚
class Solution {
public TreeNode invertTree(TreeNode root) {
// 中序遍历翻转二叉树
if(root == null) return root;
Stack<TreeNode> stk = new Stack<>();
TreeNode cur = root;
while(cur != null || !stk.isEmpty()){
if(cur != null){
stk.push(cur);
cur = cur.left;
}else{
cur = stk.pop();
TreeNode tmp = cur.left;
cur.left = cur.right;
cur.right = tmp;
cur = cur.left; // 这里因为前面进行了交换,原本处理好了的当前节点的左孩子变成了右孩子,所以还应该继续去处理交换后的左孩子
}
}
return root;
}
}
迭代法后续遍历因为是前序遍历的变种,这里就不进行代码编写了。可参考前序遍历的代码
统一迭代法:
以先序遍历为例,左右孩子交换的时机其实放在if里也可以放在else里也可以,只要保证每个节点都只被交换一次即可。
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root == null) return root;
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.isEmpty()){
TreeNode cur = stk.peek();
if(cur == null){
stk.pop();
TreeNode node = stk.pop();
TreeNode tmp = node.left;
node.left = node.right;
node.right = tmp;
}else{
TreeNode node = stk.pop();
if(node.right != null) stk.push(node.right); // 右
if(node.left != null) stk.push(node.left); // 左
stk.push(node); // 中
stk.push(null);
}
}
return root;
}
}
101.对称二叉树
题目链接:101. 对称二叉树 - 力扣(LeetCode)
递归解法如下:
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return compare(root.left, root.right);
}
public boolean compare(TreeNode left, TreeNode right){
if(left == null && right == null) return true;
else if(left == null && right != null) return false;
else if(left != null && right == null) return false;
else if(left.val != right.val) return false;
else{
return compare(left.left,right.right) && compare(left.right,right.left);
}
}
}
迭代法:
使用队列或者使用栈实现是一样的,因为判断的顺序是没有关系的,不管用神那么数据结构存储,只要每次弹出的是对应的两个元素即可。
栈和队列在这里只是存储节点的数据结构不同,api不同,再无其他不同,所以栈的就不单独实现了。
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
Queue<TreeNode> que = new LinkedList<>();
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(rightNode.right);
que.offer(leftNode.left);
que.offer(rightNode.left);
que.offer(leftNode.right);
}
return true;
}
}