513.寻找树左下角的值
思路:通过层序遍历比较简单,从左到右来遍历,记录最后一行第一个元素就是树左下角的值。递归遍历也可以,因为不需要处理中间节点,所以只需要保证先左后右的顺序就好,可以看作前序遍历。每次遍历到叶子节点,记录深度,如果深度比当前深度大,更新结果。
层序遍历实现
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
int res = 0;
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode cur = q.poll();
// 记录最后一行第一个元素
if (i == 0) {
res = cur.val;
}
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
return res;
}
}
递归遍历实现
class Solution {
// 记录二叉树的最大深度
int maxDepth = 0;
// 记录 traverse 递归遍历到的深度
int depth = 0;
TreeNode res = null;
public int findBottomLeftValue(TreeNode root) {
traverse(root);
return res.val;
}
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序遍历位置
depth++;
if (depth > maxDepth) {
// 到最大深度时第一次遇到的节点就是左下角的节点
maxDepth = depth;
res = root;
}
traverse(root.left);
traverse(root.right);
// 后序遍历位置
depth--;
}
}
112.路经总和
思路:采用递归遍历,当遍历到叶子节点的时候判断是否符合条件,符合条件返回true,不符合条件返回false。只要存在一条路径是true,结果就是true。(注意回溯的过程。)
class Solution {
/* 遍历二叉树的思路 */
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) return false;
hasPathSumHeplper(root, targetSum);
return found;
}
boolean found = false;
// 记录遍历过程中的路径和
int curSum = 0;
// 二叉树遍历函数
void hasPathSumHeplper(TreeNode root, int targetSum) {
if (root == null) return;
// 前序遍历位置
curSum += root.val;
if (root.left == null && root.right == null) {
if (curSum == targetSum) {
found = true;
}
}
hasPathSumHeplper(root.left, targetSum);
hasPathSumHeplper(root.right, targetSum);
// 后序遍历位置
curSum -= root.val;
}
}
113.路径总和II
思路:递归遍历,没有处理中节点的操作,(可以看成前序遍历)定义数组来记录路径,每当遍历到叶子节点的时候判断是否符合条件,符合条件就将路径加入到结果中。(注意回溯过程)
class Solution {
List<List<Integer>> res = new LinkedList<>(); // 结果
List<Integer> path = new LinkedList<>(); // 记录路径
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if (root == null) return res;
traverse(root, targetSum);
return res;
}
// 遍历二叉树的同时维护经过的路径,
// 在进入递归的时候要在 path 列表添加节点,结束递归的时候删除节点。
private void traverse(TreeNode root, int targetSum) {
if (root == null) return;
targetSum = targetSum - root.val;
if (root.left == null && root.right == null) {
if (targetSum == 0) {
// 找到一条路径
path.add(root.val);
res.add(new LinkedList<>(path));
path.remove(path.size() - 1);
}
return;
}
// 维护路径列表
path.add(root.val);
traverse(root.left, targetSum);
traverse(root.right, targetSum);
path.remove(path.size() - 1);
}
}
106.从中序与后序序列构造二叉树
思路:构造二叉树,第一件事一定是找根节点,然后想办法构造左右子树。后序遍历结果最后一个就是根节点的值,然后再根据中序遍历结果确定左右子树的节点。
class Solution {
// 存储 inorder 中值到索引的映射
HashMap<Integer, Integer> valToIndex = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
for (int i = 0; i < inorder.length; i++) {
valToIndex.put(inorder[i], i);
}
return build(inorder, 0, inorder.length - 1,
postorder, 0, postorder.length - 1);
}
/*
定义:
中序遍历数组为 inorder[inStart..inEnd],
后序遍历数组为 postorder[postStart..postEnd],
构造这个二叉树并返回该二叉树的根节点
*/
TreeNode build(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd) {
return null;
}
// root 节点对应的值就是后序遍历数组的最后一个元素
int rootVal = postorder[postEnd];
// rootVal 在中序遍历数组中的索引
int index = valToIndex.get(rootVal);
// 左子树的节点个数
int leftSize = index - inStart;
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
root.left = build(inorder, inStart, index - 1,
postorder, postStart, postStart + leftSize - 1);
root.right = build(inorder, index + 1, inEnd,
postorder, postStart + leftSize, postEnd - 1);
return root;
}
}
105.从前序与中序序列构造二叉树
思路:构造二叉树,第一件事一定是找根节点,然后想办法构造左右子树。前序遍历结果第一个就是根节点的值,然后再根据中序遍历结果确定左右子树的节点。
class Solution {
// 存储 inorder 中值到索引的映射
HashMap<Integer, Integer> valToIndex = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
for (int i = 0; i < inorder.length; i++) {
valToIndex.put(inorder[i], i);
}
return build(preorder, 0, preorder.length - 1,
inorder, 0, inorder.length - 1);
}
/*
定义:前序遍历数组为 preorder[preStart..preEnd],
中序遍历数组为 inorder[inStart..inEnd],
构造这个二叉树并返回该二叉树的根节点
*/
TreeNode build(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd) {
if (preStart > preEnd) {
return null;
}
// root 节点对应的值就是前序遍历数组的第一个元素
int rootVal = preorder[preStart];
// rootVal 在中序遍历数组中的索引
int index = valToIndex.get(rootVal);
int leftSize = index - inStart;
// 先构造出当前根节点
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
root.left = build(preorder, preStart + 1, preStart + leftSize,
inorder, inStart, index - 1);
root.right = build(preorder, preStart + leftSize + 1, preEnd,
inorder, index + 1, inEnd);
return root;
}
}