算法训练营第十五天| 102. 二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

86 阅读4分钟

102. 二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

image.png

思路

递归法和迭代法都是DFS,而层序遍历是BFS。我们可以借助队列来实现,队列是先进先出符合广度优先 遍历。具体思路如下:
假设我们有以下这棵树:

image.png

image.png 我们维护一个队列 以及一个 size,这个size代表的是当前层数还剩多少个元素没有弹出;如上图第一步,6 是头节点的元素,头节点这层只有一个元素,因此size = 1; 再如第三步,7 是第二层的最后一个元素,因此第二层只有一个元素没有弹出,因此 size = 1
了解了以上两点之后,我们具体描述一下我们的操作步骤:

  1. 首先将头节点插入队列,更新 size = 1
  2. 然后弹出队列的头节点,并把该节点加入list,并将其所有孩子节点以从左到右的顺序插入队列尾部,并更新 size--,直至当前层数的所有节点被弹出,这时size = 0;同时队列里存在的所有节点都是下一层的节点(例如图内第四步),因此更新 size = queue.size()并且创建一个新的列表list = new ArrayList<>()用于储存新的一层的元素。
  3. 重复这个过程直至所有节点都被遍历。
  4. 最后我们就得到了结果集。

代码实现

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> levelOrder(TreeNode root) {
        if (root == null) return res;
        Queue<TreeNode> dq = new LinkedList<>();
        dq.offer(root);
        while (!dq.isEmpty()) {
            int len = dq.size();
            List<Integer> list = new ArrayList<>();
            while (len > 0) {
                TreeNode node = dq.poll();
                list.add(node.val);
                if (node.left != null) {
                    dq.offer(node.left);
                } 
                if (node.right != null) {
                    dq.offer(node.right);
                }
                len--;
            }
            res.add(list);
        }
        return res;
    }
}

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

image.png

思路

依次翻转每个节点的左右节点,直至叶子节点为止。

可以使用前序遍历和后续遍历完成。

代码实现

class Solution {
    public TreeNode invertTree(TreeNode root) {
        recursion(root);
        return root;

    }

    private void recursion(TreeNode root) {
        if (root == null) return;
        // 对当前结点的处理逻辑
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        if (root.left != null) recursion(root.left);
        if (root.right != null) recursion(root.right);
        
    }

}

补充

在做二叉树相关的题目的时候,首先思考的是我们遍历时应该用何种遍历方法,前,中,后序遍历亦或者是层序遍历?

  • 涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
  • 求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
  • 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。

注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,二叉树:找所有路径 (opens new window)也用了前序,这是为了方便让父节点指向子节点。

所以求普通二叉树的属性还是要具体问题具体分析。

摘自代码随想录

101. 对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

image.png

思路一:

使用广度优先算法,求出每一层的所有的元素。然后使用双指针来判断每一层是否是回文。

代码实现-思路一

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return bfs(root);

    }

    boolean bfs(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        Queue<TreeNode> que = new LinkedList<>();
        que.offer(root);
        
        while (!que.isEmpty()) {
            int len = que.size();
            List<Integer> list = new ArrayList<>();
            while (len-- > 0) {

                TreeNode node = que.poll();
                if (node != null) {
                    que.offer(node.left);
                    que.offer(node.right);
                    list.add(node.val);
                } else {
                    list.add(null);
                }
                 
                
            }
            res.add(list);
        }

        boolean ans = false;
        for (List<Integer> list: res) {
            ans = isSym(list);
            if (ans == false) {
                return false;
            }
        }
        return ans;

    }

    boolean isSym(List<Integer> list) {
        // System.out.println(list);
        int l = 0;
        int r = list.size() - 1;
        while (l <= r) {
            if (list.get(l) != list.get(r)) return false;
            l++;
            r--;
        }
        return true;
    }
}

思路二

使用后序遍历。

要比较是否对称,我们要比较的是两个子树的内侧和外侧节点是否相等,如下图:

image.png

通过这张图我们可以得知我们的递归三要素:

  1. 确定递归函数的参数和返回值

因为要比较的是根节点的左子树与右子树是否是对称的,因此参数为根节点的左右节点,返回值为 bool 类型

  1. 确定终止条件

首先要判断是什么时候返回 false,什么时候返回 true

  • 左节点为空,右节点不为空,返回 false
  • 左节点不为空,右节点为空,返回 false
  • 左节点为空,右节点也为空,返回 true
  • 左右节点都不为空,但是左右节点数值不同, 返回 false 此时左右节点不为空,且数值也不相同的情况我们也处理了。 代码如下
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;
  1. 单层递归逻辑

此时左右节点都不为空,且左右节点的值都相同;

  • 此时我们就要比较二叉树外侧是否对称,要比较的是左节点的左孩子和右节点的右孩子
  • 二叉树内侧是否相同,要比较的是左节点的右孩子和右节点的左孩子
  • 如果内外侧都相同则返回 true 否则返回 false

代码实现为:

 boolean outside = compare(left.left, right.right);
 boolean inside = compare(left.right, right.left);
 return outside && inside;

代码实现-思路二

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        boolean recursion = compare(root.left, root.right);
        return recursion;

    }

    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 outside = compare(left.left, right.right);
        boolean inside = compare(left.right, right.left);
        return outside && inside;

    }
}