【代码随想录_Day13】513 找树左下角的值 112 路径总和 113 路径总和ii 106 从中序与后序遍历序列构造二叉树 105 从前序与中序遍历序列构造二叉树

以下是今日份的总结

513 找树左下角的值
112 路径总和
113 路径总和ii
106 从中序与后序遍历序列构造二叉树
105 从前序与中序遍历序列构造二叉树

513 层序遍历,只需要找到最后一层的第一个节点

112 回溯的思想

113 同上

106 中序和后序确认一棵二叉树

105 同上

今天的题目难度不低,但是也不难想,跟着随想录码一遍很容易就会了 ^ _ ^

找树左下角的值

思路:

深度最深的左叶子节点,没有左叶子节点时就是右叶子节点
层序遍历,只需要找到每一层的第一个节点

值得注意的是

递归和迭代法思路都是一样的

递归

    void order(TreeNode* cur,vector<vector<int>>&vec,int depth){
        if(cur==nullptr)return;
        if(vec.size()==depth)vec.push_back(vector<int>());
        vec[depth].push_back(cur->val);
        order(cur->left,vec,depth+1);
        order(cur->right,vec,depth+1);
        
    }
    int findBottomLeftValue(TreeNode* root) {
        vector<vector<int>>res;//二维数组最下层的最左边的就是左下角的值
        int depth = 0;
        order(root, res, depth);
        return res[res.size()-1][0];
    }

迭代

    int findBottomLeftValue(TreeNode* root) {
        if (root == NULL)
            return 0;

        queue<TreeNode*> que;
        que.push(root);

        TreeNode* leftMost = root;
        
        while (!que.empty()) {
        	//使用size 来保存当前层的节点数,确保我们在遍历当前层时不会受 que.size() 变化的影响。
            int size = que.size();
            for (int i = 0; i < size; i++) {

                TreeNode* tmp = que.front();
                que.pop();

                if (i == 0)
                    leftMost = tmp;
                if (tmp->left) 
                    que.push(tmp->left);
                
                if (tmp->right) {

                    que.push(tmp->right);
                }
            }
        }

        return leftMost->val;
    }

路径总和

思路:

找从根节点到叶节点的路径,用到回溯,并在过程中计算路径上节点值的和是否等于targetSum

值得注意的是

数组越界问题,在左右子树的递归时对队列进行弹出操作,在叶节点判断的时候不需要,这样会导致数组越界;path.pop_back() 仅在递归回溯时调用一次,以确保路径管理正确。这样可以避免对已被删除的元素进行访问。

    void road(TreeNode* cur,vector<int> &path,vector<int> &sum){

        //中序遍历
        path.push_back(cur->val);//中
        //左
        if(cur->left){
            road(cur->left, path,sum);
            path.pop_back();
        }
        //右
        if(cur->right){
            road(cur->right, path,sum);
            path.pop_back();
        }
        //叶节点判断
        if(cur->left==NULL&&cur->right==NULL){
            int size = path.size(),sums = 0;
            for(int i = 0;i<size;i++){
                sums+=path[i];
            }
            sum.push_back(sums);
            //path.pop_back();
            return;
        }
        //path.pop_back();
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root == nullptr) return false;
        vector<int> path;
        vector<int> sum;
        road(root,path,sum);
        for(int i:sum){
            if(i==targetSum)return true;
        }
        return false;
    }

路径总和ii

思路:

找从根节点到叶节点的路径,用到回溯,并在过程中计算路径上节点值的和是否等于targetSum

值得注意的是

上一题是判断有没有路径总和为targetSum的路径,而这道题是找出有几条

    void road(TreeNode* cur,vector<int> &path,vector<vector<int>> &sPath,int targetSum){

        //中序遍历
        path.push_back(cur->val);//中
        //左
        if(cur->left){
            road(cur->left, path,sPath,targetSum);
            //path.pop_back();
        }
        //右
        if(cur->right){
            road(cur->right,path,sPath,targetSum);
            //path.pop_back();
        }
        //叶节点判断
        if(cur->left==NULL&&cur->right==NULL){
            int size = path.size(),sums = 0;
            
            for(int i = 0;i<size;i++){
                sums+=path[i];
                
            }
            if(sums==targetSum){
                sPath.push_back(path);
            }
            
            //path.pop_back();错误,会造成多一次的元素弹出,数组越界
            //return;
        }
        path.pop_back();
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root == NULL)return vector<vector<int>>();
        vector<vector<int>> res;
        vector<int>path;
        road(root,path,res,targetSum);
        return res;
    }

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

思路:

根据后序遍历序列分割中序遍历序列,然后递归

值得注意的是

多层vector的创建影响效率,仍然可以优化更好的方法

    TreeNode* traversal(vector<int>& inorder,vector<int>& postorder){
        //1.做判空处理
        if(postorder.size()==0) return NULL;

        //2.后续遍历数组最后一位是当前的中间节点
        int rootValue = postorder[postorder.size()-1];
        TreeNode* root = new TreeNode(rootValue);//创建根结点
        //发现是叶子节点
        if(postorder.size()==1)return root;

        //3.找切割点
        int index;
        for(index= 0;index<inorder.size();index++){
            if(inorder[index]==rootValue)break;//得到当前在inorder数组中跟节点的位置
        }
        //4.切割中序数组,得到左右两个数组
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        //5.切割后续数组,得到左右两个数组
        postorder.resize(postorder.size()-1);//舍弃末尾元素
        // [0, leftInorder.size)
        vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());//利用中序左数组的长度
        // [leftInorder.size(), end)
        vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());//已经舍弃末尾元素所以使用end
        //6.递归
        root->left = traversal(leftInorder, leftPostorder);
        root->right = traversal(rightInorder, rightPostorder);
        //返回
        return root;
    }
    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>& preorder, vector<int>& inorder) {
        // 1.做判空处理
        if (preorder.size() == 0)
            return NULL;

        // 2.先序遍历数组第一位是当前的中间节点
        int rootValue = preorder[0];
        TreeNode* root = new TreeNode(rootValue); // 创建根结点
        // 发现是叶子节点
        if (preorder.size() == 1)
            return root;

        // 3.找切割点
        int index;
        for (index = 0; index < inorder.size(); index++) {
            if (inorder[index] == rootValue)
                break; // 得到当前在inorder数组中跟节点的位置
        }
        // 4.切割中序数组,得到左右两个数组
        vector<int> leftInorder(inorder.begin(), inorder.begin() + index);
        vector<int> rightInorder(inorder.begin() + index + 1, inorder.end());
        // 5.切割先序数组,得到左右两个数组
        vector<int>tmp (preorder.begin()+1,preorder.end());
        preorder.resize(preorder.size() - 1); // 舍弃开头元素
        preorder.clear();
        preorder = tmp;
        // [0, leftInorder.size)
        vector<int> leftPreorder(
            preorder.begin(),
            preorder.begin() + leftInorder.size()); // 利用中序左数组的长度
        // [leftInorder.size(), end)
        vector<int> rightPreorder(
            preorder.begin() + leftInorder.size(),
            preorder.end()); // 已经舍弃末尾元素所以使用end
        // 6.递归
        root->left = traversal(leftPreorder, leftInorder);
        root->right = traversal(rightPreorder, rightInorder);
        // 返回
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0||inorder.size()==0)return NULL;
        return traversal(preorder,inorder);
    }

写在最后

----OK,今日份的博客就写到这里,这一期的题不轻松啊,明天继续加油!!!
—看了看下期的题,二叉树就没轻松的;
–追上时间进度了吗?如追,从欠四天变成欠三天!!(笑
-温柔藏在睫毛里👀。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值