文章目录
此文总结树中和深度优先遍历(DFS)和广度优先遍历(BFS)相关的问题.
1. LeetCode 144. 二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
//递归版本
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
//递归终止条件
if(root == null) return res;
res.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
return res;
}
//迭代版本
public List<Integer> preorderTraversal(TreeNode root) {
//迭代做法:申请一个stack,现将head压入;当stack不为空时,
//弹出树节点即为当前遍历所得,并且判断树节点是否存在右子节点,
//存在则压栈;再判断是否存在左子节点,存在则压栈
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode pop = stack.pop();
res.add(pop.val);
if (pop.right != null) stack.push(pop.right);
if (pop.left != null) stack.push(pop.left);
}
return res;
}
2. LeetCode 589. N叉树的前序遍历
给定一个 N 叉树,返回其节点值的前序遍历。
例如,给定一个 3叉树 :
返回其前序遍历: [1,3,5,6,2,4]。
说明: 递归法很简单,你可以使用迭代法完成此题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
List<Integer> res = new ArrayList<>();
public List<Integer> preorder(Node root) {
//递归做法,和二叉树的前序遍历相似,
//不过需要使用for循环来获取到每个孩子节点
if (root == null) return res;
res.add(root.val);
for (int i = 0; i < root.children.size(); i++) {
Node node = root.children.get(i);
preorder(node);
}
return res;
}
public List<Integer> preorder(Node root) {
//迭代的做法,和二叉树的前序遍历迭代做法相似,
//也是需要一个栈,不过需要使用for循环来获取到每个孩子节点
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
Node pop = stack.pop();
res.add(pop.val);
for (int i = pop.children.size() - 1; i >= 0; i--) {
//从右侧开始入栈
stack.push(pop.children.get(i));
}
}
return res;
}
3. LeetCode 94. 二叉树的中序遍历
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
//递归终止条件
if (root == null) return res;
inorderTraversal(root.left);
res.add(root.val);
inorderTraversal(root.right);
return res;
}
public List<Integer> inorderTraversal(TreeNode root) {
//迭代做法,思路是创建一个栈,当栈不为空或当前节点不为空时,存在以下判断:
//当节点不为空,此时将该节点压入栈中,并且将该节点置为其左节点(下移过程)
//当节点为空时,弹栈出来的节点即为遍历结果,并且将当前节点置为弹栈节点的右子节点(上移过程)
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null) {
if (root != null) {
//压栈
stack.push(root);
//置为左子节点
root = root.left;
} else {
//弹栈
TreeNode pop = stack.pop();
res.add(pop.val);
//将当前节点置为弹栈节点的右子节点
root = pop.right;
}
}
return res;
}
4. LeetCode 145.二叉树的后序遍历
List<Integer> res = new ArrayList<Integer>();
public List<Integer> postorderTraversal(TreeNode root) {
//递归过程
if (root == null) return res;
postorderTraversal(root.left);
postorderTraversal(root.right);
res.add(root.val);
return res;
}
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) return res;
//stack1用以当中'中转站'
Stack<TreeNode> stack1 = new Stack<>();
//stack2用以保存遍历结果
Stack<TreeNode> stack2 = new Stack<>();
stack1.push(root);
while (!stack1.isEmpty()) {
//弹栈即为遍历结果
root = stack1.pop();
stack2.push(root);
//stack1压入左子节点
if (root.left !=null) stack1.push(root.left);
//stack1压入右子节点
if (root.right !=null) stack1.push(root.right);
}
//将stack2的结果取出
while (!stack2.isEmpty()) {
res.add(stack2.pop().val);
}
return res;
}
5. LeetCode 590. N叉树的后序遍历
List<Integer> res = new ArrayList<>();
public List<Integer> postorder(Node root) {
//递归终止条件
if (root == null) return res;
for (int i = 0; i < root.children.size(); i++) {
postorder(root.children.get(i));
}
res.add(root.val);
return res;
}
public List<Integer> postorder(Node root) {
//采用迭代的方法,思路是创建两个栈stack1和stack2,
//其中stack1作为中转栈,stack2作为保存结果栈,
//一开始现将root压入stack1中,当stack1不为空时,弹栈并放入stack2中,
//将弹栈节点由左至右压入stack1中
//当stack1为空时,将stack2依次弹栈则得遍历结果
List<Integer> res = new ArrayList<Integer>();
if (root == null) return res;
//stack1用以当中'中转站'
Stack<Node> stack1 = new Stack<>();
//stack2用以保存遍历结果
Stack<Node> stack2 = new Stack<>();
stack1.push(root);
while (!stack1.isEmpty()) {
Node pop = stack1.pop();
stack2.push(pop);
for (int i = 0; i < pop.children.size(); i++) {
stack1.push(pop.children.get(i));
}
}
//获取结果
while (!stack2.isEmpty()) {
res.add(stack2.pop().val);
}
return res;
}
6. LeetCode 102. 二叉树的层次遍历
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new ArrayList<>();
ArrayList<List<Integer>> res = new ArrayList<>();
//FIFO队列
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
ArrayList<Integer> levelNodes = new ArrayList<>();
int len = queue.size();
//遍历存储这一层的值
for (int i = 0; i < len; i++) {
TreeNode poll = queue.poll();
//出队的即为遍历结果
levelNodes.add(poll.val);
//如果出队的节点含有左子节点则添加进队列
if (poll.left != null) queue.offer(poll.left);
//如果出队的节点含有右子节点则添加进队列
if (poll.right != null) queue.offer(poll.right);
}
//添加这一层的结果进res中
res.add(levelNodes);
}
return res;
}
7. LeetCode 102. N叉树的层序遍历
public List<List<Integer>> levelOrder(Node root) {
// TODO: 19-7-12 思考过程类似102题二叉树的层次遍历
ArrayList<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
LinkedList<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
ArrayList<Integer> levelNodes = new ArrayList<>();
int len = queue.size();
for (int i = 0; i < len; i++) {
//存储层次
Node poll = queue.poll();
//出队的即为遍历结果
levelNodes.add(poll.val);
List<Node> childrens = poll.children;
//孩子节点从左至右入队
for (int j = 0; j < childrens.size(); j++) {
queue.offer(childrens.get(j));
}
}
//存储当前层次的结果
res.add(levelNodes);
}
return res;
}
8. LeetCode 102. N叉树的层序遍历
给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回锯齿形层次遍历如下:
[
[3],
[20,9],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
int depth = 0;
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int len = queue.size();
ArrayList<Integer> oneRes = new ArrayList<>();
for (int i = 0; i < len; i++) {
TreeNode poll = queue.poll();
//判断是奇数层还是偶数层,奇数层从左往右收集节点值,偶数层则从右往左收集节点值
if (depth % 2 == 0) {
//奇数层
oneRes.add(poll.val);
} else {
//偶数层
oneRes.add(0, poll.val);
}
if (poll.left != null) queue.offer(poll.left);
if (poll.right != null) queue.offer(poll.right);
}
res.add(oneRes);
depth++;
}
return res;
}
9. LeetCode 108. 将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/
-3 9
/ /
-10 5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode sortedArrayToBST(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
private TreeNode helper(int[] nums, int left, int right) {
//递归终止条件
if (left > right) return null;
//递归过程
//求出当前中间节点,并且递归地连接左右子树
int middle = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[middle]);
root.left = helper(nums, left, middle - 1);
root.right = helper(nums, middle + 1, right);
return root;
}
10. LeetCode 105. 从前序与中序遍历序列构造二叉树
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public TreeNode buildTree(int[] preorder, int[] inorder) {
Map<Integer, Integer> inorder_map = new HashMap<>();
int n = inorder.length;
for (int i = 0; i < n; i++) inorder_map.put(inorder[i], i);
return helper(preorder, 0, n, inorder, 0, n, inorder_map);
}
private TreeNode helper(int[] preorder, int pre_start, int pre_end, int[] inorder, int in_start, int in_end, Map<Integer, Integer> inorder_map) {
if (pre_start == pre_end) return null;
//从先序遍历中取当前根节点
TreeNode root = new TreeNode(preorder[pre_start]);
//从map中取当前根节点对于中序遍历数组的索引位置
int loc = inorder_map.get(preorder[pre_start]);
//划分成左右两个子树去构建
root.left = helper(preorder, pre_start + 1, pre_start + loc - in_start + 1, inorder, in_start, loc - 1, inorder_map);
root.right = helper(preorder, pre_start + loc - in_start + 1, pre_end, inorder, loc + 1, in_end, inorder_map);
return root;
}
还有一种基于Arrays.copyOfRange的写法,这种写法更加地直观和简单:
import java.util.*;
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return rebuild(preorder, inorder);
}
private TreeNode rebuild(int[] preorder, int[] inorder) {
if (preorder.length == 0 || inorder.length == 0) {
return null;
}
//当前根节点
TreeNode root = new TreeNode(preorder[0]);
//找到当前根节点位于中序遍历的索引
int rootIndex = findIndex(inorder, preorder[0]);
//递归
root.left = rebuild(Arrays.copyOfRange(preorder, 1, rootIndex + 1),
Arrays.copyOfRange(inorder, 0, rootIndex));
root.right = rebuild(Arrays.copyOfRange(preorder, rootIndex + 1, preorder.length),
Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length));
return root;
}
private int findIndex(int[] array, int target) {
for (int i = 0; i < array.length; i++) {
if (array[i] == target) return i;
}
return -1;
}
}
未完持续…