力扣刷题记录(2)LeetCode:404、513、112、106

404. 左叶子之和

力扣刷题记录(2)LeetCode:404、513、112、106_第1张图片

这道题的问题在于如何去判断该结点是否是左叶子结点。比如说示例1:判断9是否是左叶子结点?如果我们遍历到9这个结点了再去判断9是否是叶子结点的话那肯定就不好判断了,但如果我们在3结点处就来判断9结点,那问题就简单了。

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if(root==nullptr)   return 0;
        int left=0;
        //判断该结点的左结点是否为叶子结点
        if(root->left&&root->left->left==root->left->right)  left=root->left->val;
        //这一步的意思就是将该结点左子树的所有左叶子结点的和加上该结点右子树的所有左叶子结点的和,再加上当前结点的左叶子结点
        return sumOfLeftLeaves(root->left)+sumOfLeftLeaves(root->right)+left;
    }
};

513. 找树左下角的值

力扣刷题记录(2)LeetCode:404、513、112、106_第2张图片

要求找出最底层最左边的节点,注意是最左边,不是左节点。最直观的方法就是用层序遍历,然后将每一层的第一个值取出,不断更新这个值。其实也可以用递归+回溯,但是感觉没有层序遍历来的直观。

层序遍历:

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue qu;
        //length表示当前层共有多少结点,size表示当前层还剩多少节点
        int size=0,ans,length=0;
        qu.push(root);
        size++;
        length++;
        while(!qu.empty())
        {
            TreeNode* temp=qu.front();
            if(temp->left)  qu.push(temp->left);
            if(temp->right) qu.push(temp->right);
            //如果size与length相等,表示点前结点是当前层的第一个结点,也就是最左边结点
            //每过一层,不断更新最左边结点
            if(size==length) ans=temp->val;
            qu.pop();
            size--;
            if(size==0) 
            {
                size=qu.size();
                length=qu.size();
            }
        }
        return ans;
    }
};

112. 路径总和

力扣刷题记录(2)LeetCode:404、513、112、106_第3张图片

毫无疑问肯定要遍历这棵树,题目说从根节点到叶子结点,那正好可以用前序遍历。最容易想到的就是声明一个sum来记录从根节点到当前结点的和,然后到叶子结点的时候判断是否等于targetSum。然后在返回上一层的时候用sum减去当前结点的值,不断维护sum。递归+回溯

class Solution {
public:
    int sum=0;
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return false;
        sum+=root->val;
        //判断是否是叶子结点
        if(root->left==root->right)
        {
            if(targetSum==sum)    return true;
        }
        bool left=hasPathSum(root->left,targetSum);
        bool right=hasPathSum(root->right,targetSum);
        //返回上一层前,sum减去当前结点的val    回溯
        sum-=root->val;
        return left || right;
    }
};

但其实可以直接维护targetSum的值,到叶子结点的时候判断targetSum是否与叶子结点的值先等就可以了。而且也不需要去在函数末尾写回溯,因为每一层的targetSum的值都不一样,回溯已经隐藏在了targetSum里面。

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return false;
        //判断是否是叶子结点
        if(root->left==root->right)
        {
            if(targetSum==root->val)    return true;
        }
        //进入下一层,需要减去当前层的值
        bool left=hasPathSum(root->left,targetSum-root->val);
        bool right=hasPathSum(root->right,targetSum-root->val);
        return left || right;
    }
};

106. 从中序与后序遍历序列构造二叉树

力扣刷题记录(2)LeetCode:404、513、112、106_第4张图片

如果自己画的话那非常容易就画出来这棵树是什么样子的,用代码实现的话就没那么容易了。我们还是把每个结点都看成是一棵树。如果确定了这棵树的根节点(root),那么根据根节点(root)的中序遍历集合(inorder)就可以将其分成两个集合,分别表示根节点(root)的左子树中序遍历集合(inorder)和根节点(root)的右子树中序遍历集合(inorder)。然后我们根据左子树右子树的inorder集合,来维护左子树、右子树的postorder集合。最后利用递归连接root的左右子树。

那么现在问题的难点就是如何确定根节点以及如何维护中序遍历集合(inorder)、后序遍历集合(postorder)。其实这两点都很好实现。根节点就是postorder的最后一个元素。维护中序遍历集合(inorder),就是在根节点的中序遍历集合(inorder)中将根节点左侧的元素分给左子树的中序遍历集合、将根节点右侧的元素分给右子树的中序遍历集合。维护后序遍历集合(postorder)就是根据左子树的中序遍历集合(inorder)的大小size,在根节点的后序遍历集合(postorder)中从左到右取size个元素给左子树的后序遍历集合(postorder),其余归右子树的后序遍历集合(postorder)。

class Solution {
public:
    TreeNode* buildTree(vector& inorder, vector& postorder) {
        if(postorder.size()==0) return nullptr;
        TreeNode* root=new TreeNode();
        root->val=postorder[postorder.size()-1];
        //弹出已经创建好了的根节点数据
        postorder.pop_back();
        //判断该结点是否为叶子结点,如果是叶子结点就没必要进行下面的操作了
        if(postorder.size()==0) return root;
        //在inorder中查找根节点,将根节点左侧的值放到left中,右侧的值放到right中
        vector leftInorder;//存储根节点的左子树中序遍历
        vector rightInorder;//存储根节点的右子树中序遍历
        bool found=false;//用来标记是否已经找到了根节点
        for(int i=0;ival)   found=true;
            else if(found==false)   leftInorder.push_back(inorder[i]);
            else if(found==true)    rightInorder.push_back(inorder[i]);
        }
        //根据中序结果,再生成后续结果
        //这里要用到一个特性,那就是中序容器中节点的个数等于后续容器中结点的个数
        vector leftPostorder;
        vector rightPostorder;
        for(int i=0;ileft=buildTree(leftInorder,leftPostorder);
        root->right=buildTree(rightInorder,rightPostorder);
        return root;
    }
};

你可能感兴趣的:(leetcode,算法,数据结构,c++)