513. 找树左下角的值
题目链接:https://leetcode.com/problems/find-bottom-left-tree-value/
Given the root of a binary tree, return the leftmost value in the last row of the tree.
思路:
在树的最后一行找到最左边的值。
优先左边搜索,然后记录深度最大的叶子节点,前序遍历(中后序也可以)
递归
class Solution {
int maxDepth = -1;
int result = 0;
public int findBottomLeftValue(TreeNode root) {
result = root.val;
traversal(root, 0);
return result;
}
// 寻找深度最深的左叶子节点 // 有问题,应该是深度最深的最左边的节点
public void traversal (TreeNode node, int depth) {
depth++; // 需要回溯吗?
if (node.left == null && node.right == null) {
if (depth > maxDepth) {
maxDepth = depth;
result = node.val;
return;
}
}
if (node.left != null) { // depth++;需要回溯为什么
traversal(node.left, depth);
}
if (node.right != null) {
traversal(node.right, depth);
}
}
}
class Solution {
int maxDepth = -1;
int result = 0; //记录最大深度最左边节点的值
public int findBottomLeftValue(TreeNode root) {
result = root.val;
traversal(root, 1);
return result;
}
// 寻找深度最深的左叶子节点 // 有问题,应该是深度最深的最左边的节点
public void traversal (TreeNode node, int depth) {
//遇到叶子节点就更新最大深度
if (node.left == null && node.right == null) {
if (depth > maxDepth) {
maxDepth = depth;
result = node.val;
return;
}
}
if (node.left != null) {
traversal(node.left, depth+1);
}
if (node.right != null) {
traversal(node.right, depth+1);
}
}
}
层序遍历(更简单)
class Solution {
// 层序遍历
public int findBottomLeftValue(TreeNode root) {
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int leftMost = root.val;
while (!queue.isEmpty()) {
int size = queue.size();
leftMost = queue.peek().val;
while (size -- > 0) {
TreeNode node = queue.poll(); // 中
if (node.left != null) queue.offer(node.left); // 左
if (node.right != null) queue.offer(node.right); // 右
}
}
return leftMost;
}
}
这里有个疑问?回溯到底有没有必要?????
112. 路径总和
题目链接:https://leetcode.com/problems/path-sum/
Input: root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum =22
Output: true
Explanation: The root-to-leaf path with the target sumis shown.
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
if (root == null) {
return false;
}
return traversal(root, targetSum, root.val);
}
private boolean traversal (TreeNode node, int targetSum, int count) {
if (node.left == null && node.right == null) {
if (count == targetSum) {
return true;
}
}
boolean left = false;
boolean right = false;
if (node.left != null) {
if(traversal(node.left, targetSum, count+node.left.val)){ // 可直接返回
return true;
}
}
if (node.right != null) {
if(right = traversal(node.right, targetSum, count+node.right.val)){
return true;
}
}
return false;
}
}
思路:
- 返回值,递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:
如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
- 遍历的路线,并不要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。
- 确定终止条件:遍历到叶子节点且sum满足,不放入空节点
- 迭代与回溯,count直接在传入参数处改变,数值没有改变,此时不需要回溯,拎出来就需要了
113.路径总和2
题目链接:https://leetcode.com/problems/path-sum-ii/
Input: root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
Output: [[5,4,11,2],[5,8,4,5]]
Explanation: There are two paths whose sum equals targetSum:
5 + 4 + 11 + 2 = 22
5 + 8 + 4 + 5 = 22
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
if (root == null) return result;
traversal(root, targetSum, root.val, path, result);
return result;
}
private void traversal(TreeNode node, int targetSum, int count, List<Integer> path, List<List<Integer>> result){
path.add(node.val);
if (node.left == null && node.right == null) {
if (count == targetSum) {
result.add(new ArrayList<>(path));
//result.add(path);
}
return;
}
if (node.left != null) {
traversal(node.left, targetSum, count+node.left.val, path, result);
path.remove(path.size()-1); // 回溯
}
if (node.right != null) {
traversal(node.right, targetSum, count+node.right.val, path, result);
path.remove(path.size()-1);
}
}
}
思路:
出错了!!!!注意:
- 要遍历整个树,找到所有路径,所以递归函数不要返回值!
- result添加path需要new arraylist
- path添加必须要回溯
106.从中序与后序遍历序列构造二叉树
题目链接:
https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
Given two integer arrays inorder and postorder where inorder is the inorder traversal of a binary tree and postorder is the postorder traversal of the same tree, construct and return the binary tree.
Input: inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
Output: [3,9,20,null,null,15,7]
思路:
模拟一层层切割 前中后序
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
// 第一步:如果数组大小为零的话,说明是空节点了。
if (postorder.length == 0) {
return null;
}
// 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
int rootVal = postorder[postorder.length - 1];
TreeNode root = new TreeNode(rootVal);
// 叶子节点
if (postorder.length == 1){
return root;
}
// 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
int index = 0;
for (int i = 0; i < inorder.length; i ++) {
if (inorder[i] == rootVal){
index = i;
}
}
// 左闭右开区间:[0, delimiterIndex)
// 第四步:切割中序数组,得到 中序左数组和中序右数组
int[] left_inorder = Arrays.copyOfRange(inorder, 0, index);
int[] right_inorder = Arrays.copyOfRange(inorder, index+1, inorder.length);
// 第五步:切割后序数组,得到 后序左数组和后序右数组
int[] left_postorder = Arrays.copyOfRange(postorder, 0, left_inorder.length);
int[] right_postorder = Arrays.copyOfRange(postorder, left_inorder.length, left_inorder.length + right_inorder.length);
// 第六步:递归处理左区间和右区间
root.left = buildTree(left_inorder, left_postorder);
root.right = buildTree(right_inorder, right_postorder);
return root;
}
}
思路:
- 如何切割?先找root,切割中序再后序
- 边界值 保持循环不变量
- 中序数组大小一定是和后序数组的大小相同的(这是必然)
105.前序中序
题目链接:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0) {
return null;
}
int rootVal = preorder[0];
TreeNode root = new TreeNode(rootVal);
int index = 0;
for (int i = 0; i < inorder.length; i ++){
if (inorder[i] == rootVal) {
index = i;
}
}
int[] left_inorder = Arrays.copyOfRange(inorder, 0, index);
int[] right_inorder = Arrays.copyOfRange(inorder, index+1, inorder.length);
int[] left_preorder = Arrays.copyOfRange(preorder, 1, left_inorder.length+1);
int[] right_preorder = Arrays.copyOfRange(preorder, left_inorder.length+1, preorder.length);
root.left = buildTree(left_preorder, left_inorder);
root.right = buildTree(right_preorder, right_inorder);
return root;
}
}
思路:
必须有中序,因为中序可以分割左右