层序遍历

/**
 * 二叉树的层序遍历
 */
class QueueTraverse {
    /**
     * 存放一层一层的数据
     */
    public List<List<Integer>> resList = new ArrayList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {

        traverse(root, resList);
        return resList;

    }

    /**
     *  树的孩子节点可能有不止两个
     */
    public void traverse(TreeNode node, List<List<Integer>> resList) {
        // 判空
        if (node == null) {
            return;
        }
        // 准备
        ArrayDeque<TreeNode> que = new ArrayDeque<>();
        TreeNode cur;
        // 循环开始
        que.offer(node);
        while (!que.isEmpty()) {
            //len获取到的是每层一开始的数据大小
            int len = que.size();
            //对每一层的分别建立一个list存放本层数据
            List<Integer> subList = new ArrayList(len);

            while (len > 0) {
                //取出本层节点并删除
                cur = que.poll();
                len--;
                // visit
                subList.add(cur.val);

                if (cur.left != null) {
                    que.offer(cur.left);
                }
                if (cur.right != null) {
                    que.offer(cur.right);
                }
            }
            //一层的数据遍历添加完毕 开始下一层
            resList.add(subList);
        }
    }

    /**
     * 单纯遍历所有元素
     */
    public void visit(TreeNode root) {
        ArrayDeque<TreeNode> queue = new ArrayDeque<>();
        TreeNode p = root,temp = null;
        queue.offer(p);
        while (!queue.isEmpty()) {
            // visit 节点
            temp = queue.poll();
            System.out.println(temp.val);
            if (p.left != null) {
                queue.offer(temp.left);
            }
            if (p.right != null) {
                queue.offer(temp.right);
            }
        }
    }
}

LeetCode 226.翻转二叉树

分析1.0

仔细看题,题目中的翻转二叉树是整个树一起翻转,不是只翻转节点的左右孩子

选择遍历顺序-中序遍历(左子树翻转(左子树成了右子树),根树翻转,右子树翻转)左子树翻转了两次

class Solution {
    public TreeNode invertTree(TreeNode root) {
        preOrder(root);
        return root;
    }

    public void preOrder(TreeNode root){
        if(root == null){
            return;
        }
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        preOrder(root.left);
        preOrder(root.right);
        return;
    }
}

LeetCode 101.对称二叉树 2 

失误 对称二叉树比较的是子树,不光是子节点

比较每个节点的左右子树是否相等,树又是由节点组成的,就是同步遍历根节点左右两颗子树,比较节点是否相等

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){
            return false;
        }
        return visit(root.left, root.right);
    }

    public boolean visit(TreeNode node1, TreeNode node2){
        if(node1 == null && node2 != null){
            return false;
        }
        if(node2 == null && node1 != null){
            return false;
        }
        if(node1 == null && node2 == null){
            return true;
        }
        if(node1.val != node2.val){
            return false;
        }
        visit(node1.left,  node2.left);
        visit(node1.right, node2.right);
        return true;
    }
}

分析2.0

遍历子树并不是按照一样的逻辑顺序,左子树的左子树要和右子树的右子树相等 以此类推
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;
        }
        // 比较外侧
        boolean compareOutside = compare(left.left, right.right);
        // 比较内侧
        boolean compareInside = compare(left.right, right.left);
        return compareOutside && compareInside;
    }
}

总结

  1. 树类题目注意区别孩子节点子树
  2. 数组、字符串移除某个元素后,长度会发生变化,遍历中注意索引发生变化,树在遍历过程中的操作也会影响原本的遍历思路
  3. 不同的深度遍历顺序有不同的使用场景,注意具体问题具体分析
  4. 节点要非null才能进行操作 类似栈、队列非空才能操作一样

常用变量名增量更新

size、val、ans、cnt、cur、pre、next、left、right、index、gap、tar、res、src、len、start、end、flag、ch