找树左下角的值

link:513. 找树左下角的值 - 力扣(LeetCode)

思路分析

看题目给出的样例分析,觉得可以从深度入手.如果是左子树深度最大,那直接输出最左边的左子树节点即可(只有一个左节点的话也是如出一辙)
又假设二叉树中至少有一个节点,就已经列举出一种特殊需要判断的情况了.

递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int result = 0;
//定义为-1 确保只有一个节点时也能成功遍历
int Deepth = -1;
public int findBottomLeftValue(TreeNode root) {
result = root.val;
exrloration(root,0);
return result;
}
public void exrloration(TreeNode node,int deepth) {
//其实题目描述已经避免这种情况了
if(node == null) {
return ;
}
if(node.left == null && node.right == null) {
if(deepth > Deepth) {
Deepth = deepth;
result = node.val;
}
}
if(node.left != null) {
exrloration(node.left,deepth+1);
}
if(node.right!= null) {
exrloration(node.right,deepth+1);
}
}
}

路径总和

link:112. 路径总和 - 力扣(LeetCode)

思路分析

类似数组遍历求和(滑动窗口)找目标总和值只不过换成二叉树.
首先还是想到按照前序遍历的方式,递归遍历.由于根节点是一定要选中的,(null另算)那我们遍历子节点做差判断最后是否等于0即可.
或者可以从下向上按照层,借助队列实现二叉树版滑动窗口.🤔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
//特殊情况优先
if(root == null) {
return false;
}
targetSum -= root.val;
if(root.left == null && root.right == null) {
return targetSum == 0;
}
if(root.left != null){
boolean left = hasPathSum(root.left,targetSum);
//剪枝判断
if(left) {
return true;
}
}
if(root.right != null){
boolean right = hasPathSum(root.right,targetSum);
if(right) {
return true;
}
}
return false;
}
}

从中序和后序遍历构造二叉树

link:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

思路分析

其实和我们数据结构考试中的内容一致,画图推推规律.
image-20241112100932554

image-20241112101050227

根据画图规律可得 后续遍历中root位置出现在最后一个位置,再结合中序遍历可以得出9为左子树,15、20、7为右子树.
我使用Map进行解决,key存储值,value存储下标.
中序遍历中root的index + 1.
根据之前分析的规律,我们利用后序遍历确定root.value,然后对应在中序遍历中定位到root位置(利用index)然后回溯到中序遍历切割出左子树那么在后序遍历中剩余的部分就是右子树.

Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
Map<Integer,Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>();
for(int i = 0;i<inorder.length;i++)
{
map.put(inorder[i],i);
}
return FindOrder(inorder,0,inorder.length,postorder,0,postorder.length);

}
public TreeNode FindOrder(int[] inOrder,int inBegin,int inEnd,int[] postOrder,int postBegin,int postEnd)
{
//结束条件,左闭右开
if(inBegin>=inEnd || postBegin>=postEnd)
{
return null;
}
//找到后序在中序的位置
int index = map.get(postOrder[postEnd - 1]);
//构造节点
TreeNode root = new TreeNode(inOrder[index]);
//保存中序左子树的个数,用来确定后序的区间
int lenOfLeft = index - inBegin;
root.left = FindOrder(inOrder,inBegin,index,postOrder,postBegin,postBegin+lenOfLeft);
root.right = FindOrder(inOrder,index+1,inEnd,postOrder,postBegin+lenOfLeft,postEnd-1);
return root;
}
}
递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
public int postIndex;
public TreeNode buildTree(int[] inorder, int[] postorder) {

postIndex = postorder.length-1;

return buildTreeChild(postorder,inorder,0,inorder.length-1);
}

private TreeNode buildTreeChild(int[] postorder,int[] inorder,int inbegin,int inend) {

//1. 没有左树 或者 没有右树了
if(inbegin > inend) {
return null;
}
//2.创建根节点
TreeNode root = new TreeNode(postorder[postIndex]);

//3.从中序遍历当中 找到根节点所在的下标
int rootIndex = findIndex(inorder,inbegin,inend,postorder[postIndex]);
if(rootIndex == -1) {
return null;
}

postIndex--;
//4. 创建左子树 和 右子树

root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);

root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);

return root;
}

private int findIndex(int[] inorder,int inbegin,int inend,int key) {
for(int i = inbegin;i <= inend;i++) {
if(inorder[i] == key) {
return i;
}
}
return -1;
}
}

Tips

理解构建过程的示例

以中序遍历 inorder = [9, 3, 15, 20, 7] 和后序遍历 postorder = [9, 15, 7, 20, 3] 为例:

  1. 第一次调用
    • postIndex 指向 3,创建根节点 3.
    • 在中序数组中找到 3 的索引为 1.
    • 右子树范围 [15, 20, 7],左子树范围 [9].
  2. 构建右子树
    • 递归调用构建右子树,postIndex 现在指向 20,创建节点 20.
    • 在中序数组中找到 20 的索引为 3.
  3. 构建左子树(对于 20
    • 继续递归构建右子树(此时后序的下一节点是 7).
    • 处理完 20 的右子树后,回溯到 20,然后处理 20 的左子树(为 15).
  4. 构建左子树(对于 3
    • 现在回到根节点 3,处理左子树(此时后序的下一节点是 9).