leetcode-zgd-day15-102.二叉树层序遍历/226.翻转二叉树/101.对称二叉树

204 阅读2分钟

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;
     }
 }