代码随想录训练营Day14:二叉树03

1.513找树左下角的值

树左下角的值,首先得条件就是要在最下面这一层,其次就是这一层的最左边,所以这个题目和层次遍历的方式很匹配。

思路:按照层次遍历(广度)即可,稍微修改一下,每次result只取最左边的那个值,然后更新到最后就是树左下角的值了。

int findBottomLeftValue(TreeNode* root) {
        //先用层序遍历来解决这个问题
        queue<TreeNode*> que;
        int result = 0;
        if(root != nullptr) que.push(root);
        while(!que.empty()){
            int n = que.size();
            result = que.front()->val;
            for(int i = 0;i<n;i++){
                TreeNode* node = que.front();
                que.pop();
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return result;
    }

2.112路径总和

路径总和就开始用到了一个回溯的思想。通过不断地回溯来计算每个的路径的值,然后统计输出。

2.1回溯

回溯其实就是一种暴力递归,其可以抽象为一个树形结构,遍历代表着广度,递归代表着深度。所以我们可以按照递归的思路来进行处理。

1.回溯的返回值和输入参数,返回值一般设置的是void,输入参数一般就是四个:result用于记载最终的结果,path用于记载当前的路径,target用于判断对应的路径是否需要添加到result中,index:代表的是遍历的索引位置。具体需要看实际的需求

2.回溯的终止条件:一般来说就是遍历到了最下面,判断这个路径加不加入到结果里面。

3.回溯的每一个递归的具体处理:先移动,然后调用,再将刚才加入到path的退出一步。

具体在这个例子里面:我们通过判断当前节点是否为叶子节点代表是否到达底部,然后通过判断count是否为0来确定返回值是否为true(count是target-path的值,其实是将两个给缩减成一个了)。后面的if(node->left)其实就将回溯部分给隐藏了,因为我们在这一层回溯中是没有改变node的位置。

//回溯法
    bool backtracking(TreeNode* node,int count){
        if(node->left==nullptr&&node->right==nullptr){
            if(count == 0){
                return true;
            }else{
                return false;
            }
        }
        if(node->left){
            if(backtracking(node->left,count-node->left->val))return true;
        }
        if(node->right){
            if(backtracking(node->right,count-node->right->val))return true;
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==nullptr) return false;
        return backtracking(root,targetSum-root->val);
    }

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

首先我们知道中序遍历与后序遍历的区别就是通过根节点将其分成三个部分,左子树、根节点、右子树三个部分。只是不同的排列顺序,但是每一部分的长度是相同的,且根节点长度为1。所以我们根据这个进行设计代码。

1.后序遍历的最后一个节点一定是根节点,找到对应的根节点

2.遍历中序数组,找到根节点的位置,确定左子树的长度和右子树的长度。同时确定后序遍历数组的左子树和右子树的长度和位置。

3.递归找到跟节点的左右节点。

在这个里面设置的区间全都是左闭右开的区间

/*
    //因为两者的长度一定相等,所以只需要判断一个即可
    TreeNode* traversal(vector<int>& inorder,vector<int>& postorder){
        int n = postorder.size();
        if(n == 0){
            return nullptr;
        }
        int rootval = postorder[n-1];
        TreeNode* root = new TreeNode(rootval);
        if(n == 1){
            return root;
        }
        int delima;
        for(delima = 0;delima<n;delima++){
            if(inorder[delima] == rootval)break;//找到分界点
        }
        vector<int> leftInorder(inorder.begin(),inorder.begin()+delima);
        vector<int> rightInorder(inorder.begin()+delima+1,inorder.end());
        vector<int> leftPostorder(postorder.begin(),postorder.begin()+delima);
        vector<int> rightPostorder(postorder.begin()+delima,postorder.end()-1);
        root->left = traversal(leftInorder,leftPostorder);
        root->right = traversal(rightInorder,rightPostorder);
        return root;
    }
    */
    //第二种方法
    TreeNode* traversal(vector<int>& inorder,int leftInorderIndex,int rightInorderIndex,vector<int>& postorder,int leftPostorderIndex,int rightPostorderIndex){
        if(leftInorderIndex == rightInorderIndex) return nullptr;
        int rootval = postorder[rightPostorderIndex-1];
        TreeNode* root = new TreeNode(rootval);
        if(rightInorderIndex - leftInorderIndex == 1){
            return root;
        }
        int delimaIndex;
        for(delimaIndex = leftInorderIndex;delimaIndex<rightInorderIndex;delimaIndex++){
            if(inorder[delimaIndex]==rootval) break;
        }
        root->left = traversal(inorder,leftInorderIndex,delimaIndex,postorder,leftPostorderIndex,leftPostorderIndex+(delimaIndex-leftInorderIndex));
        root->right = traversal(inorder,delimaIndex+1,rightInorderIndex,postorder,leftPostorderIndex+(delimaIndex-leftInorderIndex),rightPostorderIndex-1);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size()==0) return nullptr;
        //return traversal(inorder,postorder);
        int n = inorder.size();
        return traversal(inorder,0,n,postorder,0,n);
    }

4.654最大二叉树

最大二叉树的思路和前面的106题目有些类似,都是一个查找位置,分段,然后对每段进行相应的操作即可。

    TreeNode* traversal(vector<int>& nums,int left,int right){
        if(right - left == 0)return nullptr;
        int maxs = 0;
        int maxIndex = left;
        for(int i = left;i<right;i++){
            if(nums[i]>maxs){
                maxs = nums[i];
                maxIndex = i;
            }
        }
        TreeNode* root = new TreeNode(nums[maxIndex]);//赋值语句
        root->left = traversal(nums,left,maxIndex);
        root->right = traversal(nums,maxIndex+1,right);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        int n = nums.size();
        if(n == 0) return nullptr;
        return traversal(nums,0,n);
    }

5.一些小小的注意事项

在我们对数组进行操作从而构造二叉树的时候,我们最好直接使用索引进行操作,这样可以减少时间和空间的花销。但是相对来说会想的复杂一点。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值