目录
513.找树左下角的值
LeetCode-513-题目链接
深度最大的叶子结点一定是最后一行
对于本题而言,递归方法:使用前序、中序、后序都是可以的
因为本题中是没有中 节点的处理逻辑的,只需要先遍历左就可以;因为优先遍历的是左节点,所以只要我们一旦得到深度最大的节点,我们得到的就是最后一行最靠左侧的结点。
注意:最靠左侧的结点 并不一定是 左孩子
在遍历的时候每当遇到深度 比之前 深度大的结点,就更新最左侧的值
同时本题也可以使用迭代法,也就是使用队列的层序遍历方法,是一种比较容易理解方法。
递归法
class Solution {
public:
// 使用递归写法
int depth_ = INT_MIN;
int result;
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
void traversal(TreeNode* node, int depth) {
if (node == NULL) return;
if (node->left == NULL && node->right == NULL) {
if (depth_ < depth) {
depth_ = depth;
result = node->val;
}
return;
}
if (node->left) {
depth++;
traversal(node->left, depth);
depth--;
}
if (node->right) {
depth++;
traversal(node->right, depth);
depth--;
}
return;
}
};
迭代法
class Solution {
public:
// 使用迭代写法 层序遍历 队列
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> queue1;
queue1.push(root);
int result;
while(!queue1.empty()) {
int size;
size = queue1.size();
for(int i = 0; i < size; i++) {
TreeNode* node = queue1.front();
queue1.pop();
// 每次只记录 每层的第一个结点的值
if (i == 0) {
result = node->val;
}
if (node->left) {
queue1.push(node->left);
}
if (node->right) {
queue1.push(node->right);
}
}
}
return result;
}
};
112.路径总和
LeetCode-112-题目链接
对于找到一条 符合的路径就返回,就一路 一直返回 true。并不需要遍历整棵树
可以在遍历的时候对总和进行递减,这样代码更简洁
同样,该题对遍历顺序没有要求,因为不涉及中 结点的处理。
- 112 题 是找到一个就返回
- 113 题 是找到所有的路径
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == NULL) return false;
return traversal(root, targetSum - root->val);
}
bool traversal(TreeNode* node, int targetSum) {
if (node->left == NULL && node->right == NULL && targetSum == 0) return true;
if (node->left == NULL && node->right == NULL && targetSum != 0) return false;
if (node->left) {
targetSum -= node->left->val;
if (traversal(node->left, targetSum)) return true;
targetSum += node->left->val;
}
if (node->right) {
targetSum -= node->right->val;
if (traversal(node->right, targetSum)) return true;
targetSum += node->right->val;
}
return false;
}
};
113.路径总和ii
class Solution {
public:
vector<vector<int>> result;
vector<int> resultSmall;
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
if (root == NULL) return result;
resultSmall.push_back(root->val);
traversal(root, targetSum - root->val);
return result;
}
void traversal(TreeNode* node, int targetSum) {
if (node == NULL) return;
if (node->left == NULL && node->right == NULL && targetSum == 0) {
result.push_back(resultSmall);
return;
}
if (node->left == NULL && node->right == NULL && targetSum != 0) {
return;
}
if (node->left) {
targetSum -= node->left->val;
resultSmall.push_back(node->left->val);
traversal(node->left, targetSum);
targetSum += node->left->val;
resultSmall.pop_back();
}
if (node->right) {
targetSum -= node->right->val;
resultSmall.push_back(node->right->val);
traversal(node->right, targetSum);
targetSum += node->right->val;
resultSmall.pop_back();
}
return;
}
};
106.从中序与后序遍历序列构造二叉树
-
思路:
-
(1)若后序数组为空,则返回空结点
-
(2)后序数组中的最后一个元素为结点元素
-
(3)寻找中序数组位置作为切割点
-
(4)进行中序数组的切割
-
(5)基于切割后的中序数组,进行后序数组的切割
-
(6)最后递归处理左区间和右区间
-
只有前序和后序是不能唯一确定一棵二叉树的;中序和后序 以及 中序和前序 都可以,思路是一致的。
-
本题给出了 便于理解的题解,但是每次递归时定义了新的vector,对空间和时间有很大的消耗,下面给出了,对于数组分割的优化解法:利用vector 下标索引进行处理。对于本方法需要注意的是:需要把之间对vector的操作,全部变成索引之间的关系来表示。
容易理解版本
// 便于理解版本
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, postorder);
}
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder) {
if (postorder.size() == 0) return NULL;
TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
if (postorder.size() == 1) return root;
vector<int> inorderLeft, inorderRight;
int mid;
// 寻找中序数组位置作为切割点,同时进行中序数据的切割
for (int i = 0; i < inorder.size(); i++) {
if (root->val == inorder[i]) {
mid = i;
break;
}
inorderLeft.push_back(inorder[i]);
}
for (int i = mid + 1; i < inorder.size(); i++) {
inorderRight.push_back(inorder[i]);
}
// postorder舍弃末尾元素
postorder.resize(postorder.size() - 1);
// 接下来进行后序数组的切割
// 按照切割后的中序数组的 长度
vector<int> postorderLeft, postorderRight;
for (int i = 0; i < inorderLeft.size(); i++) {
postorderLeft.push_back(postorder[i]);
}
for (int i = inorderLeft.size(); i < postorder.size(); i++) {
postorderRight.push_back(postorder[i]);
}
root->left = traversal(inorderLeft, postorderLeft);
root->right = traversal(inorderRight, postorderRight);
return root;
}
};
使用vector下标索引优化版本
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return NULL;
return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
}
TreeNode* traversal(vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) {
if (postorderBegin == postorderEnd) return NULL;
TreeNode* root = new TreeNode(postorder[postorderEnd - 1]);
if ((postorderEnd - postorderBegin) == 1) return root;
int mid;
// 寻找中序数组位置作为切割点,同时进行中序数据的切割
for (int i = 0; i < inorderEnd; i++) {
if (root->val == inorder[i]) {
mid = i;
break;
}
}
// 统一左闭右开 [inorderLeftBegin, inorderRightEnd)
int inorderLeftBegin = inorderBegin;
int inorderLeftEnd = mid;
int inorderRightBegin = inorderLeftEnd + 1;
int inorderRightEnd = inorderEnd;
// 接下来进行后序数组的切割
// 按照切割后的中序数组的 长度
int postorderLeftBegin = postorderBegin;
int postorderLeftEnd = postorderBegin + (inorderLeftEnd - inorderLeftBegin);
int postorderRightBegin = postorderLeftEnd;
int postorderRightEnd = postorderEnd - 1;
root->left = traversal(inorder, inorderLeftBegin, inorderLeftEnd, postorder, postorderLeftBegin, postorderLeftEnd);
root->right = traversal(inorder, inorderRightBegin, inorderRightEnd, postorder, postorderRightBegin, postorderRightEnd);
return root;
}
};
105.从前序与中序遍历序列构造二叉树
容易理解版本
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return traversal(preorder, inorder);
}
TreeNode* traversal(vector<int>& preorder, vector<int>& inorder) {
if (preorder.size() == 0 || inorder.size() == 0) return NULL;
// 前序数组第一个元素为 结点元素
TreeNode* root;
root = new TreeNode(preorder[0]);
if (preorder.size() == 1) {
return root;
}
vector<int> inorderLeft, inorderRight;
// 根据前序第一个结点元素 对中序 数组进行 分割
for (int i = 0; i < inorder.size(); i++) {
if (preorder[0] == inorder[i]) {
break;
}
inorderLeft.push_back(inorder[i]);
}
for (int i = inorderLeft.size() + 1; i < inorder.size(); i++) {
inorderRight.push_back(inorder[i]);
}
// 此时继续根据 分割后的中序数组 对 前序数据进行分割
vector<int> preorderLeft, preorderRight;
for (int i = 1; i < inorderLeft.size() + 1; i++) {
preorderLeft.push_back(preorder[i]);
}
for (int i = inorderLeft.size() + 1; i < preorder.size(); i++) {
preorderRight.push_back(preorder[i]);
}
root->left = traversal(preorderLeft, inorderLeft);
root->right = traversal(preorderRight, inorderRight);
return root;
}
};