#LeetCode每日一题【二叉树专题】
-
经常涉及到一些二叉树跟层数相关的题目,例如需要对树每一层的节点做些逻辑处理、求层数(高度)等,类似于这类题目,都可以使用广度优先搜索的层次遍历去实现,大致模板如下
if (root == null) { return; } Deque<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { // 当前队列元素全部出队列,使用size保证是一个层级的出队列,即当前长度的元素同一层级的都出队列 for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.pop(); // TODO 逻辑处理啥的 // 将其左右节点继续放到队列中 if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } }
主要就是在于,将同一层的所有节点一起出队
-
可适用于LeetCode102二叉树的层序遍历、LeetCode103二叉树的锯齿形层序遍历、LeetCode107二叉树的层序遍历 II、LeetCode116填充每个节点的下一个右侧节点指针、LeetCode117填充每个节点的下一个右侧节点指针 II、 LeetCode199二叉树的右视图、LeetCode104二叉树的最大深度、LeetCode111二叉树的最小深度 等
-
将每一层节点放到一个List中
public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> ans = new ArrayList<>(); if (root == null) { return ans; } Deque<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { List<Integer> res = new ArrayList<>(); // 当前队列元素全部出队列,使用size保证是一个层级的出队列,即当前长度的元素同一层级的都出队列 for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.pop(); // 将其左右节点继续放到队列中 if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); res.add(node.val); } ans.add(res); } return ans; }
-
类似于102,只不过每层放到集合中,一次头插一次尾插,即一次从左至右一次从右至左
public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> ans = new LinkedList<>(); if (root == null) return ans; Deque<TreeNode> queue = new LinkedList<>(); queue.add(root); boolean left = true; while (!queue.isEmpty()) { LinkedList<Integer> res = new LinkedList<>(); for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.poll(); if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); // 入结果集调整顺序 if (left) { // 尾插 res.add(node.val); } else { // 头插 res.addFirst(node.val); } } left = !left; ans.add(res); } return ans; }
-
还是类似于102,只不过入最后结果集的时候,采用的是头插法,即层次遍历从底至上
public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> ans = new LinkedList<>(); if (root == null) { return ans; } Queue<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { List<Integer> res = new LinkedList<>(); for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.poll(); res.add(node.val); if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } ans.add(0, res); } return ans; }
-
需要将每层节点之间建立next关系,可以考虑广度优先搜索实现,层次遍历给每层节点建立关系
// 广度优先,层次遍历(一层一层出队) public Node connect(Node root) { if (root == null) return null; Deque<Node> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { for (int i = 0, size = queue.size(); i < size; i++) { Node node = queue.poll(); // 使用peek检索到队列头部值是什么,建立next关系 if (i < size - 1) { node.next = queue.peek(); } if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } } return root; }
-
LeetCode117填充每个节点的下一个右侧节点指针 II
从广度优先的角度来考虑这题跟106没有任何区别,这里只做广度优先层次遍历的讲解
// 广度优先,层次遍历(一层一层出队) public Node connect(Node root) { if (root == null) return null; Deque<Node> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { for (int i = 0, size = queue.size(); i < size; i++) { Node node = queue.poll(); // 使用peek检索到队列头部值是什么,建立next关系 if (i < size - 1) { node.next = queue.peek(); } if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } } return root; }
-
简单剖析下题目含义,即拼接二叉树每层最右边的节点,很明显的层次遍历思路
public List<Integer> rightSideView(TreeNode root) { List<Integer> ans = new ArrayList<>(); if (root == null) return ans; Deque<TreeNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.poll(); // 取最右边节点 if (i == size - 1) { ans.add(node.val); } if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } } return ans; }
-
求最大深度,也即最大的层数
public int maxDepthBFS(TreeNode root) { if (root == null) { return 0; } Deque<TreeNode> queue = new LinkedList<>(); queue.add(root); int level = 0; while (!queue.isEmpty()) { for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.poll(); if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } // 一层节点全部出完队列,层数+1 level++; } return level; }
-
求最小深度,即第一次出现叶子节点的那一层为最小深度
public int minDepthBfs(TreeNode root) { if (root == null) return 0; Queue<TreeNode> queue = new LinkedList<>(); queue.add(root); int ans = 1; while (!queue.isEmpty()) { for (int i = 0, size = queue.size(); i < size; i++) { TreeNode node = queue.poll(); // 没有孩子节点了,即叶子节点,最小层数(深度)找到了 if (node.left == null && node.right == null) { return ans; } if (node.left != null) queue.add(node.left); if (node.right != null) queue.add(node.right); } ans++; } return ans; }
-
注
以上题目可能不止一种解法,广度优先搜索层次遍历只是其中的一种方法、也是最容易想到的方法,但并不代表是最优解
-
总结
处理跟层数相关的题目、或处理每层节点的题目,可以考虑使用该方法层次遍历解决