目录
一、找树左下角的值(力扣513)
实现思想:左下角的值 = 树最深一层的最左边节点的值
1.确定是最深的一层,用一个变量标记最大深度,只要出现深度加深的情况就更新最大深度
2.确定是左叶子节点,先遍历左子树再遍历右子树,因为如果最后一层有多个节点,由于深度相同只有最左边的会更新,其余不会更新。如果深度不同,则选择深度更深的节点。
class Solution {
public:
int result;
int maxDepth = INT_MIN;
void traversal(TreeNode* root, int depth){
if (root->left == nullptr && root->right == nullptr){
if (depth > maxDepth){
maxDepth = depth;
result = root->val;
}
return;
}
if (root->left){
depth++;
traversal(root->left,depth);
depth--;
}
if (root->right){
depth++;
traversal(root->right,depth);
depth--;
}
return;
}
int findBottomLeftValue(TreeNode* root) {
traversal(root, 0);
return result;
}
};
二、路经总和(力扣112)
实现思想:这道题比较重要的点是
1.要进行回溯
2.如果下层已经达到要求,就要一直进行返回,如何一直向上层返回true也是一大难点
class Solution {
public:
bool traversal(TreeNode* root, int count){
//如果遍历到根节点并且达到targetSum就说明这条路径达到要求返回true
if (root->left == nullptr && root->right == nullptr && count == 0)return true;
//没达到要求则返回false
if (root->left == nullptr && root->right == nullptr) return false;
//如果左节点存在
if (root->left){
//减去左节点的值
count -= root->left->val;
//如果下层返回的值是true,说明下层已经达到要求继续向上层返回true
if (traversal(root->left, count)) return true;
//如果下层没达到要求,说明这条路径不行,要进行回溯
count += root->left->val;
}
if (root->right){
//减去右节点的值
count -= root->right->val;
//如果下层返回的值是true,说明下层已经达到要求继续向上层返回true
if (traversal(root->right, count)) return true;
//如果下层没达到要求,说明这条路径不行,要进行回溯
count += root->right->val;
}
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
if (root == nullptr) return false;
//传进去的参数是已经减去根节点值得参数
return traversal(root,targetSum-root->val);
}
};
三、路径总和ii(力扣113)
实现思想:这道题比较重要的点是
1.要进行回溯
2.如果下层已经达到要求,就要一直进行返回,如何一直向上层返回true也是一大难点
3.这道题和上一道题的思想一样
class Solution {
public:
void traversal(TreeNode* root, int count, vector<int> &nums, vector<vector<int>> &result){
if(root->left == nullptr && root->right == nullptr && count != 0) return;
if(root->left == nullptr && root->right == nullptr && count == 0){
result.push_back(nums);
return;
}
if (root->left){
nums.push_back(root->left->val);count -= root->left->val;
traversal(root->left,count,nums,result);
nums.pop_back();count += root->left->val;
}
if (root->right){
nums.push_back(root->right->val);count -= root->right->val;
traversal(root->right,count,nums,result);
nums.pop_back();count += root->right->val;
}
return;
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<vector<int>> result;
vector<int> nums;
if (root == nullptr) return result;
nums.push_back(root->val);
traversal(root,targetSum-root->val,nums,result);
return result;
}
};
四、从中序和后序遍历序列构造二叉树(力扣106)
实现思想:
-
第一步:如果数组大小为零的话,说明是空节点了。
-
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
-
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
-
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
-
第五步:切割后序数组,切成后序左数组和后序右数组
-
第六步:递归处理左区间和右区间
class Solution {
public:
TreeNode* traversal(vector<int>& inorder, vector<int>& postorder){
//递归终止条件,如果后序遍历数组长度为0就说明节点值为空
if (postorder.size() == 0) return nullptr;
//确定根节点
int rootvalue = postorder[postorder.size()-1];
TreeNode* root = new TreeNode(rootvalue);
//如果后序遍历数组长度只有为1,就证明只有一个节点,可以直接返回
if (postorder.size() == 1) return root;
//在中序遍历数组中寻找根节点
int index;
for (index = 0; index < inorder.size(); index++){
if (inorder[index] == rootvalue) break;
}
//开始切割中序遍历数组
vector<int> linorder(inorder.begin(), inorder.begin()+index);
vector<int> rinorder(inorder.begin()+index+1, inorder.end());
postorder.resize(postorder.size()-1);
//开始切割后序遍历数组
vector<int> lpostorder(postorder.begin(), postorder.begin()+linorder.size());
vector<int> rpostorder(postorder.begin()+linorder.size(), postorder.end());
root->left = traversal(linorder,lpostorder);
root->right = traversal(rinorder,rpostorder);
return root;
}
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
if (inorder.size() == 0 || postorder.size() == 0) return nullptr;
return traversal(inorder, postorder);
}
};
五、从前序和中序遍历序列构造二叉树(力扣107)
实现思想:
class Solution {
private:
TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
if (preorderBegin == preorderEnd) return NULL;
int rootValue = preorder[preorderBegin]; // 注意用preorderBegin 不要用0
TreeNode* root = new TreeNode(rootValue);
if (preorderEnd - preorderBegin == 1) return root;
int delimiterIndex;
for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == rootValue) break;
}
// 切割中序数组
// 中序左区间,左闭右开[leftInorderBegin, leftInorderEnd)
int leftInorderBegin = inorderBegin;
int leftInorderEnd = delimiterIndex;
// 中序右区间,左闭右开[rightInorderBegin, rightInorderEnd)
int rightInorderBegin = delimiterIndex + 1;
int rightInorderEnd = inorderEnd;
// 切割前序数组
// 前序左区间,左闭右开[leftPreorderBegin, leftPreorderEnd)
int leftPreorderBegin = preorderBegin + 1;
int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; // 终止位置是起始位置加上中序左区间的大小size
// 前序右区间, 左闭右开[rightPreorderBegin, rightPreorderEnd)
int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
int rightPreorderEnd = preorderEnd;
root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, preorder, leftPreorderBegin, leftPreorderEnd);
root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
return root;
}
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if (inorder.size() == 0 || preorder.size() == 0) return NULL;
// 参数坚持左闭右开的原则
return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
}
};