代码随想录算法训练营第十八天 | 513.找树左下角的值, 112. 路径总和 , 113.路径总和ii, 106.从中序与后序遍历序列构造二叉树 ,105.从前序与中序遍历序列构造二叉树

Day18

513.找树左下角的值

递归,按前中后序遍历都可以。只要先遍历左子树就行。

前序

class Solution {
public:
    int result;
    int treedepth;
    void getdepth(TreeNode* node,int depth){
        if(node==NULL) return;
        if(depth>treedepth){
            treedepth=depth;
            result=node->val;
        }
        if(node->left){
            depth++;
            getdepth(node->left,depth);
            depth--;
        }
        if(node->right){
            depth++;
            getdepth(node->right,depth);
            depth--;
        }
        return;
    }
    int findBottomLeftValue(TreeNode* root) {
        int depth=1;
        getdepth(root,depth);
        return result;
    }
};

层序遍历

需要注意的是如果没说明使用了deque定义队列,那么不能使用push_back();

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode*> que;
        que.push(root);
        int val;
        while(!que.empty()){
            int size=que.size();
            TreeNode* node=que.front();
            que.pop();
            val=node->val;
            if(node->left){
                que.push(node->left);
            }
            if(node->right){
                que.push(node->right);
            }
            for(int i=0;i<size-1;i++){
                TreeNode* cur=que.front();
                que.pop();
                if(cur->left)que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }
        }
        return val;
    }
};

112. 路径总和

首先是我自己考虑的递归方法,判断是否相等,相等返回.但是存在一个问题,当找到符合要求的结果后不会马上退出递归。有一种解法

 return isSame(node->left, sum, targetSum) || isSame(node->right, sum, targetSum);

写成这种  ||  的形式就可以允许短路行为。

这里面主要是返回值的问题,

1.如果需要遍历整个树,而且返回值不需要处理,比如在函数外定义的result这种,就不需要返回值。

2.如果需要处理返回值,那么就需要根据需要返回值

3.如果不需要遍历整个树,找到结果就可以返回这种,那么也需要返回值,就像本题,找到一种路径就可以退出递归循环了。所以考虑使用bool,其实bool也是一种返回值,所以只需要判断左右子树是否符合要求就可以了。

这也是二叉树常用的一种递归思路:左右子树是否符合

class Solution {
public:
    bool isSame(TreeNode* node,int sum,int targetSum){
        sum+=node->val;
        if(sum == targetSum && node->left==NULL && node->right==NULL){
            return true;
        }
        bool left;
        bool right;
        if(node->left){
            left=isSame(node->left,sum,targetSum);
        }
        if(node->right){
            right=isSame(node->right,sum,targetSum);
        }
        return left || right;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==NULL) return false;
        return isSame(root,0,targetSum);
    }
};

下面是代码随想录的,区别就在于他用target减去目标值。然后把if判断结果也是true与false特性考虑进去,只要出现true,也会一级级退出循环,使用if也可以允许短路行为

class Solution {
public:
    bool isSame(TreeNode* node,int sum){
        sum-=node->val;
        if(node->left==NULL&& node->right==NULL && sum==0){
            return true;
        }
        if(node->left){
            if(isSame(node->left,sum)) return true;
        }
        if(node->right){
            if(isSame(node->right,sum)) return true;
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int targetSum) {
        if(root==NULL) return false;
        int sum=targetSum;
        return isSame(root,sum);
        
    }
};

迭代法

auto 不能用于直接调用构造函数

pair的用法

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        stack<pair<TreeNode*,int>> st;
        if(root==NULL) return false;
        st.push(pair<TreeNode*,int>(root,root->val));
        while(!st.empty()){
            auto node=st.top();
            st.pop();
            if(node.first->left==NULL&&node.first->right==NULL&&node.second==targetSum){
                return true;
            }
            if(node.first->left){
                st.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));
            }
            if(node.first->right){
                st.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));
            }
        }
        return false;
    }
};

113.路径总和ii

使用迭代法:难点在于如何存储路径,同时又判断是否相等。

class Solution {
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        stack<pair<TreeNode*,int>> st;
        vector<vector<int>> result;
        stack<vector<int>> st2;
        vector<int> vec;
        if(root==NULL){return result;}
        st.push({root,root->val});
        vec.push_back(root->val);
        st2.push(vec);
        while(!st.empty()){
            auto node=st.top();
            st.pop();
            vector<int> node2=st2.top();//到该节点的路径
            st2.pop(); 
            if(node.first->left==NULL && node.first->right==NULL && node.second==targetSum){
                result.push_back(node2);
            }
            if(node.first->left){
                st.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));
                vector<int> node3=node2;
                node3.push_back(node.first->left->val);
                st2.push(node3);
            }
            if(node.first->right){
                st.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));
                node2.push_back(node.first->right->val);
                st2.push(node2);
            }
            
        } 
        return result;
    }
};

递归法:

跟之前的其实差不多思路,区别在于要遍历全树以及如何存储路径。

class Solution {
public:
    vector<vector<int>> result;
    vector<int> vec;
    void isSame(TreeNode* node,int sum){
        vec.push_back(node->val);
        sum-=node->val;
        if(node->left==NULL && node->right==NULL && sum==0){
            result.push_back(vec);
            vec.pop_back();
            return;
        }
        if(node->left){
            isSame(node->left,sum);
        }
        if(node->right){
            isSame(node->right,sum);
        }
        vec.pop_back();
        return;
    }
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
        if(root==NULL) return result;
        int sum=targetSum;
        isSame(root,sum);
        return result;
    }
};

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

思路不算很难,但是写起来小问题很多,主要是分割数组的边界问题

在定义一个vector时,.end()指向的那个不在容器内,定义也是一样

vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);

这里面最后一个元素不在容器内。

下面是在原本给出的容器内进行操作:

class Solution {
public:
    TreeNode* travelsal(vector<int>& inorder,int inorderbegin,int inorderend,vector<int> postorder,int postorderbegin,int postorderend){
        if(postorderbegin==postorderend) return NULL;

        int rootvalue=postorder[postorderend-1];
        TreeNode* root=new TreeNode(rootvalue);

        int delimiterIndex;
        for(delimiterIndex=inorderbegin;delimiterIndex<inorderend;delimiterIndex++){
            if(inorder[delimiterIndex]==rootvalue) break;
        }

        int leftinorderbegin=inorderbegin;
        int leftinorderend=delimiterIndex;
        int rightinorderbegin=delimiterIndex+1;
        int rightinorderend=inorderend;

        int leftpostorderbegin=postorderbegin;
        int leftpostorderend=postorderbegin+delimiterIndex-inorderbegin;
        int rightpostorderbegin=postorderbegin+delimiterIndex-inorderbegin;
        int rightpostorderend=postorderend-1;

        root->left=travelsal(inorder,leftinorderbegin,leftinorderend,postorder,leftpostorderbegin,leftpostorderend);
        root->right=travelsal(inorder,rightinorderbegin,rightinorderend,postorder,rightpostorderbegin,rightpostorderend);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size()==0) return NULL;
        return travelsal(inorder,0,inorder.size(),postorder,0,postorder.size());
    }
};

105.从前序与中序遍历序列构造二叉树

跟上面那题思路差不多,只不过从找最后一个节点变成了找第一个节点。

下面是使用vector的代码

class Solution {
public:
    TreeNode* travelsal(vector<int>& preorder,vector<int>& inorder){
        if(inorder.size()==0) return NULL;

        int rootValue=preorder[0];
        TreeNode* root=new TreeNode(rootValue);
        
        int delimiterIndex;
        for(delimiterIndex=0;delimiterIndex<inorder.size();delimiterIndex++){
            if(inorder[delimiterIndex]==rootValue) break;
        }

        vector<int> leftin(inorder.begin(),inorder.begin()+delimiterIndex);
        vector<int> rightin(inorder.begin()+delimiterIndex+1,inorder.end());

        vector<int> leftpre(preorder.begin()+1,preorder.begin()+leftin.size()+1);
        vector<int> rightpre(preorder.begin()+leftin.size()+1,preorder.end());

        root->left=travelsal(leftpre,leftin);
        root->right=travelsal(rightpre,rightin);

        return root;

    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0) return NULL;
        return travelsal(preorder,inorder);
    }
};

使用下标索引

class Solution {
public:
    TreeNode* travelsal(vector<int>& preorder,int preorderbegin,int preorderend,vector<int>& inorder,int inorderbegin,int inorderend){
        if(preorderbegin==preorderend) return NULL;

        int rootValue=preorder[preorderbegin];
        TreeNode* root=new TreeNode(rootValue);

        int delimiterIndex;
        for(delimiterIndex=inorderbegin;delimiterIndex<inorderend;delimiterIndex++){
            if(inorder[delimiterIndex]==rootValue) break;
        }

        int leftinorderbegin=inorderbegin;
        int leftinorderend=delimiterIndex;
        int rightinorderbegin=delimiterIndex+1;
        int rightinorderend=inorderend;

        int leftpreorderbegin=preorderbegin+1;
        int leftpreorderend=preorderbegin+1+delimiterIndex-inorderbegin;
        int rightpreorderbegin=preorderbegin+1+delimiterIndex-inorderbegin;
        int rightpreorderend=preorderend;

        root->left=travelsal(preorder,leftpreorderbegin,leftpreorderend,inorder,leftinorderbegin,leftinorderend);
        root->right=travelsal(preorder,rightpreorderbegin,rightpreorderend,inorder,rightinorderbegin,rightinorderend);

        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0){
            return NULL;
        }
        return travelsal(preorder,0,preorder.size(),inorder,0,inorder.size());
    }   
};

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值