513. 找树左下角的值
题目链接:513. 找树左下角的值 - 力扣(LeetCode)
题目描述:给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:

输入: root = [2,1,3]
输出: 1
示例 2:

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7
提示:
- 二叉树的节点个数的范围是
[1,104] -231 <= Node.val <= 231 - 1
解法一、递归
一直向左遍历即可,但是要注意:一直向左遍历的最后一个节点,未必在最后一行
如何判断是否是最后一行? 深度最大的叶子节点一定是最后一行
如何找最左边的节点? 可以使用前序遍历(中序后序也可),只有保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值
int maxDepth = -1;
int leftval = 0;
void dfs(struct TreeNode* root, int depth) {
if (root == NULL)
return ;
if (depth > maxDepth) {
maxDepth = depth;// 更新最大深度
leftval = root->val;// 最大深度最左面的数值
}
dfs(root->left, depth + 1);// 隐藏着回溯
dfs(root->right, depth + 1);
}
int findBottomLeftValue(struct TreeNode* root){
maxDepth = -1;
leftval = 0;
dfs(root, 1);
return leftval;
}
解法二、迭代
采用层序遍历的方式,一般每层是从左至右遍历,这样最后一层第一个就是最左边的节点。这里采用从右至左的顺序,这样层序遍历的最后一个节点就是最底层最左边的节点
#define MAX_NODE_SIZE 10000
int findBottomLeftValue(struct TreeNode *root) {
int ret = 0;
struct TreeNode *queue[MAX_NODE_SIZE];
int rear = 0, front = 0;
queue[rear++] = root;
while(front != rear){
int size = rear - front;
//从右至左遍历每一层
for(int i=0;i<size;i++){
struct TreeNode *node = queue[front++];
if(node->right) queue[rear++] = node->right;
if(node->left) queue[rear++] = node->left;
ret = node->val;//每层最后一个节点就是该层最左边的节点
}
}
return ret;
}
112.路径总和
题目描述:给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:
输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。
提示:
- 树中节点的数目在范围
[0, 5000]内 -1000 <= Node.val <= 1000-1000 <= targetSum <= 1000
解法一、递归
如果累加判断的话,会比较麻烦,因此这里采用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值
//递减判断
bool hasPathSum(struct TreeNode* root, int targetSum){
// 递归结束条件:若当前节点不存在,返回false
if(!root)
return false;
// 若当前节点为叶子节点,且targetSum-root的值为0。(当前路径上的节点值的和满足条件)返回true
if(!root->right && !root->left && targetSum == root->val)
return true;
// 查看左子树和右子树的所有节点是否满足条件
return hasPathSum(root->right, targetSum - root->val) || hasPathSum(root->left, targetSum - root->val);
}
//累加判断
bool dfs(struct TreeNode* root, int totalSum, int targetSum) {
if (root == NULL) {
return false;
}
totalSum += root->val;
if (root->left == NULL && root->right == NULL && totalSum == targetSum) {
return true;
}
bool left = dfs(root->left, totalSum, targetSum);
bool right = dfs(root->right, totalSum, targetSum);
return left || right;
}
bool hasPathSum(struct TreeNode* root, int targetSum) {
return dfs(root, 0, targetSum);
}
解法二、迭代
// 存储一个节点以及当前的和
struct Pair {
struct TreeNode* node;
int sum;
};
bool hasPathSum(struct TreeNode* root, int targetSum){
struct Pair stack[1000];
int stackTop = 0;
// 若root存在,则将节点和值封装成一个pair入栈
if(root) {
struct Pair newPair = {root, root->val};
stack[stackTop++] = newPair;
}
// 当栈不为空时
while(stackTop) {
// 出栈栈顶元素
struct Pair topPair = stack[--stackTop];
// 若栈顶元素为叶子节点,且和为targetSum时,返回true
if(!topPair.node->left && !topPair.node->right && topPair.sum == targetSum)
return true;
// 若当前栈顶节点有左右孩子,计算和并入栈
if(topPair.node->left) {
struct Pair newPair = {topPair.node->left, topPair.sum + topPair.node->left->val};
stack[stackTop++] = newPair;
}
if(topPair.node->right) {
struct Pair newPair = {topPair.node->right, topPair.sum + topPair.node->right->val};
stack[stackTop++] = newPair;
}
}
return false;
}
113.路径总和II
题目链接:113. 路径总和 II - 力扣(LeetCode)
题目描述:给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例 2:

输入:root = [1,2,3], targetSum = 5
输出:[]
示例 3:
输入:root = [1,2], targetSum = 0
输出:[]
提示:
- 树中节点总数在范围
[0, 5000]内 -1000 <= Node.val <= 1000-1000 <= targetSum <= 1000
DFS 递归
int** ret;
int* path;
int* colSize;
int retTop;
int pathTop;
void traversal(const struct TreeNode* const node, int count) {
// 若当前节点为叶子节点
if(!node->right && !node->left) {
// 若当前path上的节点值总和等于targetSum。
if(count == 0) {
// 复制当前path
int *curPath = (int*)malloc(sizeof(int) * pathTop);
memcpy(curPath, path, sizeof(int) * pathTop);
// 记录当前path的长度为pathTop
colSize[retTop] = pathTop;
// 将当前path加入到ret数组中
ret[retTop++] = curPath;
}
return;
}
// 若节点有左/右孩子
if(node->left) {
// 将左孩子的值加入path中
path[pathTop++] = node->left->val;
traversal(node->left, count - node->left->val);
// 回溯
pathTop--;
}
if(node->right) {
// 将右孩子的值加入path中
path[pathTop++] = node->right->val;
traversal(node->right, count - node->right->val);
// 回溯
--pathTop;
}
}
int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** returnColumnSizes){
// 初始化数组
ret = (int**)malloc(sizeof(int*) * 1000);
path = (int*)malloc(sizeof(int*) * 1000);
colSize = (int*)malloc(sizeof(int) * 1000);
retTop = pathTop = 0;
*returnSize = 0;
// 若根节点不存在,返回空的ret
if(!root)
return ret;
// 将根节点加入到path中
path[pathTop++] = root->val;
traversal(root, targetSum - root->val);
// 设置返回ret数组大小,以及其中每个一维数组元素的长度
*returnSize = retTop;
*returnColumnSizes = colSize;
return ret;
}
106.从中序与后序遍历序列构造二叉树
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
题目描述:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树
示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]
示例 2:
输入:inorder = [-1], postorder = [-1]
输出:[-1]
提示:
1 <= inorder.length <= 3000postorder.length == inorder.length-3000 <= inorder[i], postorder[i] <= 3000inorder和postorder都由 不同 的值组成postorder中每一个值都在inorder中inorder保证是树的中序遍历postorder保证是树的后序遍历
思路
以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
- 第一步:如果数组大小为零的话,说明是空节点了。
- 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
- 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
- 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
- 第五步:切割后序数组,切成后序左数组和后序右数组
- 第六步:递归处理左区间和右区间
切割时要注意坚持循环不变量
int linearSearch(int* arr, int arrSize, int key) {
int i;
for(i = 0; i < arrSize; i++) {
if(arr[i] == key)
return i;
}
return -1;
}
struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){
//若中序遍历数组中没有元素,则返回NULL
if(!inorderSize)
return NULL;
//创建一个新的结点,将node的val设置为后序遍历的最后一个元素
struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
node->val = postorder[postorderSize - 1];
//通过线性查找找到中间结点在中序数组中的位置
int index = linearSearch(inorder, inorderSize, postorder[postorderSize - 1]);
//左子树数组大小为index
//右子树的数组大小为数组大小减index减1(减的1为中间结点)
int rightSize = inorderSize - index - 1;
node->left = buildTree(inorder, index, postorder, index);
node->right = buildTree(inorder + index + 1, rightSize, postorder + index, rightSize);
return node;
}
353

被折叠的 条评论
为什么被折叠?



