刷题神器
往期回顾
>【二叉树】|代码随想录算法训练营第13天|110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和、222.完全二叉树的节点个数
题目
513.找树左下角的值
-
学后思路
层序遍历最后一行第一个就是答案,递归遍历需要注意回溯和左下角节点的逻辑,注意左下角的定义,不是左叶子节点
解法1: 递归
class Solution {
int maxDepth = Integer.MIN_VALUE;
int result;
public int findBottomLeftValue(TreeNode root) {
traversal(root, 1);
return result;
}
public void traversal(TreeNode root, int depth) {
if (root.left == null && root.right == null) {
if (depth > maxDepth) {
maxDepth = depth;
result = root.val;
return;
}
}
if (root.left != null) {
depth = depth + 1;
traversal(root.left, depth);
depth = depth - 1;// 回溯
}
if (root.right != null) {
depth = depth + 1;
traversal(root.right, depth);
depth = depth - 1;// 回溯
}
return;
}
}
解法二: 层序遍历
class Solution {
public int findBottomLeftValue(TreeNode root) {
Queue<TreeNode> queue = new LinkedList();
int result = -1;
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (i == 0) {// 每一层第一个数据
result = node.val;
}
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
return result;
}
}
- 题目总结
-
traversal(root, 1); 注意传 0, 1都不影响,只要保证depth是递增判断逻辑没区别
-
层序遍历,相对好理解,注意判断每层第一个的逻辑,我总是把层序遍历和迭代法搞混,大家要注意
-
路径总和
题目:112.路径总和
112.路径总和
- 学后思路
遍历所有路径,注意重点就是回溯,注意判断条件,每次左减法,看叶子节点和count的值
解法一:
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null)
return false;
return traversal(root, targetSum - root.val);
}
public boolean traversal(TreeNode root, int targetSum) {
if (root.left == null && root.right == null && targetSum == 0)
return true;
if (root.left == null && root.right == null)
return false;
if (root.left != null) {
targetSum = targetSum - root.left.val;
boolean result = traversal(root.left, targetSum);
targetSum = targetSum + root.left.val;
if (result) {
return true;
}
}
if (root.right != null) {
targetSum = targetSum - root.right.val;
boolean result = traversal(root.right, targetSum);
targetSum = targetSum + root.right.val;
if (result) {
return true;
}
}
return false;
}
}
- 题目总结
- 注意第一个节点的情况
113.路径总和2
- 学后思路
路径总和2,需要返回所有的路径集合,也注意要回溯,整个流程里存在多个相等的集合
解法一:
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if (root == null)
return result;
path.add(root.val);
traversal(root, targetSum - root.val);
return result;
}
public void traversal(TreeNode root, int targetSum) {
if (root.left == null && root.right == null && targetSum == 0) {
// new 新的list ,如果直接用path会出问题
result.add(new ArrayList(path));
return;
}
if (root.left == null && root.right == null)
return;
if (root.left != null) {
targetSum = targetSum - root.left.val;
path.add(root.left.val);
traversal(root.left, targetSum);
path.remove(path.size() - 1);
targetSum = targetSum + root.left.val;
}
if (root.right != null) {
targetSum = targetSum - root.right.val;
path.add(root.right.val);
traversal(root.right, targetSum);
path.remove(path.size() - 1);
targetSum = targetSum + root.right.val;
}
}
}
- 题目总结
- 注意返回值处理
从中序与后序遍历序列构造二叉树
106.从中序与后序遍历序列构造二叉树
- 学后思路
通过后续遍历确定根节点,然后切割中序遍历确定左右子树,然后切割后续遍历,然后重复上述方法
解法一:
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0)
return null;
// 找根
int rootVal = postorder[postorder.length - 1];
TreeNode root = new TreeNode(rootVal);
if (inorder.length == 1)
return root;
// 找分割点
int dIndex = 0;
for (; dIndex < inorder.length; dIndex++) {
if (inorder[dIndex] == rootVal) {
break;
}
}
// 切割 中序遍历 copyOfRange 包含start, 不包含end
int[] inleftorder = Arrays.copyOfRange(inorder, 0, dIndex);
int[] inrightorder = Arrays.copyOfRange(inorder, dIndex + 1, inorder.length);
// 切割 后续遍历
int[] postleftorder = Arrays.copyOfRange(postorder, 0, inleftorder.length);
int[] postrightorder = Arrays.copyOfRange(postorder, inleftorder.length,
inleftorder.length + inrightorder.length);
root.left = buildTree(inleftorder, postleftorder);
root.right = buildTree(inrightorder, postrightorder);
return root;
}
}
- 题目总结
- 主要注意切割的范围区间
105.从前序与中序遍历序列构造二叉树
- 学后思路
从前序遍历寻找根节点,找到切割点,切割中序遍历
解法一:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (inorder.length == 0)
return null;
// 找根
int rootVal = preorder[0];
TreeNode root = new TreeNode(rootVal);
if (inorder.length == 1)
return root;
// 找分割点
int dIndex = 0;
for (; dIndex < inorder.length; dIndex++) {
if (inorder[dIndex] == rootVal) {
break;
}
}
int[] inleftorder = Arrays.copyOfRange(inorder, 0, dIndex);
int[] inrightorder = Arrays.copyOfRange(inorder, dIndex + 1, inorder.length);
int[] preleftorder = Arrays.copyOfRange(preorder, 1, 1 + inleftorder.length);
int[] prerightorder = Arrays.copyOfRange(preorder, 1 + preleftorder.length, preorder.length);
root.left = buildTree(preleftorder, inleftorder);
root.right = buildTree(prerightorder, inrightorder);
return root;
}
}
- 题目总结
- 注意切割的边界