找树左下角的值
层序遍历
考虑遍历数的每一层,最下层的最左边元素就是树左下角的值。简单的层序遍历,在对每层遍历时都将第一个节点的值更新为返回值ans,最后返回ans。
class Solution {
public:
queue<TreeNode*>queue;
int findBottomLeftValue(TreeNode* root) {
int ans;
queue.push(root);
while(!queue.empty()){
int levelsize = queue.size();
for(int i =0; i< levelsize;i++){
TreeNode*cur = queue.front();
if(i == 0){
ans = cur->val;//将ans更新为第一个节点的值
}
queue.pop();
if(cur->left){
queue.push(cur->left);
}
if(cur->right){
queue.push(cur->right);
}
}
}
return ans;
}
};
算法时间复杂度和空间复杂度均为O(n)。
递归法
可以考虑前序、中序和后序三种方式,因为这里只要求遍历到最深层,然后返回最深处第一个节点的值。
class Solution {
public:
int max_depth = INT_MIN;//或者设为0,也可以
int result;//返回的结果
int depth = 0;//初始深度设定为0
void travesal(TreeNode *root, int &depth){//注意这里传入的是depth的引用
if(root->left == nullptr and root->right == nullptr){//递归中找到根节点,若比最大深 //度大,则更新result(无论何种顺序,都是该深度下最左边的节点)
if(depth > max_depth){
max_depth = depth;
result = root->val;
}
}
if(root->left){//注意这里的回溯,depth++后传入travesal,若到了根节点,则返回,depth--。
depth++;
travesal(root->left,depth);
depth--;
}
if(root->right){//同上
depth++;
travesal(root->right,depth);
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
travesal(root,depth);
return result;
}
};
算法的时间复杂度和空间复杂度均为O(n)。
路径总和
递归法
我选择从根节点开始向下递归,并每次更新targetofsum的值,采取前序遍历的顺序,递归条件设定为若找到叶子节点等于更新后的targetsum,则返回true,否则递归完成后返回false。具体代码如下。
class Solution {
public:
bool hasPathSum(TreeNode* root, int targetSum) {
// 如果根节点为空,直接返回 false。
if (root == nullptr) {
return false;
}
// 如果根节点是叶子节点(即没有左右子节点),并且 targetSum 等于该节点的值,返回 true。
if (root->left == nullptr && root->right == nullptr) {
return targetSum == root->val;
}
// 更新 targetSum 为 targetSum - root->val。
targetSum -= root->val;
bool leftPath = hasPathSum(root->left, targetSum);
bool rightPath = hasPathSum(root->right, targetSum);
// 最后,如果左右子树中有任意一个存在满足条件的路径,返回 true;否则返回 false。
return leftPath || rightPath;
}
};
时间复杂度和空间复杂度均为O(n)。
路径总和ii
与路径总和i相类似的方式,不过每次递归都将一个temp数组递下去,并将节点的val值push_back到数组的尾部。
class Solution {
public:
void findPaths(TreeNode* root, int targetSum, vector<int>& temp, vector<vector<int>>& ans) {
if (root == nullptr) {
return;
}
// 将当前节点的值添加到临时路径中
temp.push_back(root->val);
targetSum -= root->val;
// 如果是叶子节点且路径和等于目标和,将路径添加到结果中
if (root->left == nullptr && root->right == nullptr) {
if (targetSum == 0) {
ans.push_back(temp);
}
}
// 递归处理左子树和右子树
findPaths(root->left, targetSum, temp, ans);
findPaths(root->right, targetSum, temp, ans);
// 回溯:移除当前节点,以便继续探索其他路径
temp.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> temp;
vector<vector<int>> ans;
findPaths(root, targetSum, temp, ans);
return ans;
}
};
从中序与后序遍历序列构建二叉树
递归法
需要把握后序遍历和中序遍历的特点,后序遍历的顺序是左右中,中序遍历的顺序是左中右,即后序遍历结果的最后一个位置为二叉树的根节点,再带入中序遍历中,中序遍历是左中右,即在我们已知根节点的情况下,可以在中序遍历中区分左子树和右子树。以leetcode上的实例举例,我们先在后序[9,15,7,20,3]和中序[9,3,15,20,7]这两个序列中,先从后序序列中找到树的根节点3,以节点3将中序分为左子树和右子树,之后再根据后序,找出左子树和右子树的根节点。依此顺序递归。由此可以写出以下代码。
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
//
if(postorder.size() == 0){
return nullptr;
}
int root_val = postorder[postorder.size()-1];
TreeNode* root = new TreeNode(postorder[postorder.size()-1]);
if(postorder.size() == 1)
return root;
//创建索引,找寻根节点在中序序列中的位置
int index = -1;
for(int i = 0 ; i < inorder.size(); i ++){
if(inorder[i] == root_val){
index = i;
break;
}
}
//根据索引区分中序的左右子树序列、后序的左右子树
vector<int>inorederlefttree(inorder.begin(),inorder.begin() + index);
vector<int>inorderrighttree(inorder.begin()+index+1,inorder.end());
vector<int>postorderlefttree(postorder.begin(),postorder.begin()+inorederlefttree.size());
vector<int>postorderrighttree(postorder.begin()+inorederlefttree.size(),postorder.end()-1);
root -> left = buildTree(inorederlefttree,postorderlefttree);
root -> right = buildTree(inorderrighttree,postorderrighttree);
return root;
}
};
算法的时间复杂度和空间复杂度为O(n)
从前序与中序遍历序列构建二叉树
和前文类似,与之前的区别在于后序的最后一个节点为根节点,而前序的第一个节点为根节点,以此类推。
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0)
return nullptr;
int root_val = preorder[0];
TreeNode* root = new TreeNode(root_val);
if(preorder.size() == 1)
return root;
int index = -1;
for(int i = 0; i < inorder.size(); i++){
if(inorder[i] == root_val){
index = i;
break;
}
}
vector<int>inorderlefttree(inorder.begin(),inorder.begin()+index);
vector<int>inorderrighttree(inorder.begin()+index+1,inorder.end());
vector<int>preorderlefttree(preorder.begin()+1,preorder.begin()+1+inorderlefttree.size());
vector<int>preorderrighttree(preorder.begin()+1+inorderlefttree.size(),preorder.end());
root->left = buildTree(preorderlefttree,inorderlefttree);
root->right = buildTree(preorderrighttree,inorderrighttree);
return root;
}
};
算法的时间复杂度和空间复杂度为O(n)。