LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)

在此非常感谢“代码随想录”的通俗易懂的总结!

(致敬叶师傅和李小龙)

“我不害怕曾经练过一万种踢法的人,但我害怕一种踢法练过一万次的人”(by 叶师傅的徒弟Bruce Lee)
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第1张图片

今天继续打5道,加油,冲冲冲!

具体题目

题目1:112. 路径总和

题目描述:
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

叶子节点 是指没有子节点的节点。

示例 1:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第2张图片

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true

示例 2:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第3张图片

输入:root = [1,2,3], targetSum = 5
输出:false

示例 3:
输入:root = [1,2], targetSum = 0
输出:false

C++代码

方法一、递归方法(规范写法)

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

方法二、递归方法(精简版)

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

方法三、迭代方法
迭代方法中使用了C++的pair数据结构:
标准库类型–pair类型定义在#include 头文件中,定义如下:
类模板:template struct pair
参数:T1是第一个值的数据类型,T2是第二个值的数据类型。
访问两个元素操作可以通过first和sencond访问

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

题目2:113. 路径总和 II

题目描述:
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

叶子节点 是指没有子节点的节点。

示例 1:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第4张图片

输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]

示例 2:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第5张图片

输入:root = [1,2,3], targetSum = 5
输出:[]

示例 3:
输入:root = [1,2], targetSum = 0
输出:[]

C++代码:

递归方法

class Solution {
     
private:
    vector<int> path;
    vector<vector<int>> result;
    void traversal(TreeNode* node, int count){
     
        if(!node->left && !node->right && count==0){
     
            result.push_back(path);
            return;
        }
        if(!node->left && !node->right) return;
        if(node->left){
     
            path.push_back(node->left->val);
            traversal(node->left,count-node->left->val); 
            path.pop_back();//回溯
        }
        if(node->right){
     
            path.push_back(node->right->val);
            traversal(node->right,count-node->right->val);
            path.pop_back();//回溯
        }
        return;
    }
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
     
        result.clear();
        path.clear();
        if(root==NULL) return result;
        path.push_back(root->val);
        traversal(root,targetSum-root->val);
        return result;
    }
};

题目3:106. 从中序与后序遍历序列构造二叉树

题目描述:
根据一棵树的中序遍历与后序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第6张图片
构造二叉树主要就是找到切割点:
一层一层切割,就应该想到了递归。
来看一下一共分几步:

第一步:如果数组大小为零的话,说明是空节点了。

第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

第五步:切割后序数组,切成后序左数组和后序右数组

第六步:递归处理左区间和右区间

C++代码:

class Solution {
     
public:
    TreeNode* traversal(vector<int>& inorder,int inorderbegin,int inorderend,vector<int>& postorder,int postorderbegin,int postorderend){
     
        if(inorderbegin==inorderend) return NULL;
        int rootvalue=postorder[postorderend-1];
        TreeNode* root=new TreeNode(rootvalue);
        if(postorderend-postorderbegin==1) return root;
        int delimiterIndex;//找到后序数组最后一个元素在中序数组的位置,作为切割点
        for(delimiterIndex=inorderbegin;delimiterIndex<inorderend-1;++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+leftinorderend-leftinorderbegin;
        int rightpostorderbegin=postorderbegin+leftinorderend-leftinorderbegin;
        int rightpostorderend=postorderend-1;
        
        root->left=traversal(inorder,leftinorderbegin,leftinorderend,postorder,leftpostorderbegin,leftpostorderend);
        root->right=traversal(inorder,rightinorderbegin,rightinorderend,postorder,rightpostorderbegin,rightpostorderend);
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
     
        if(!inorder.size() || !postorder.size()) return NULL;
        return traversal(inorder,0,inorder.size(),postorder,0,postorder.size());
    }
};

题目4:105. 从前序与中序遍历序列构造二叉树

题目描述:
根据一棵树的前序遍历与中序遍历构造二叉树。

注意:
你可以假设树中没有重复的元素。

例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第7张图片

C++代码:

class Solution {
     
public:
    TreeNode* traversal(vector<int>& inorder,int inorderbegin,int inorderend,vector<int>& preorder,int preorderbegin,int preorderend){
     
        if(inorderbegin==inorderend) return NULL;
        int rootvalue=preorder[preorderbegin];
        TreeNode* root=new TreeNode(rootvalue);
        if(preorderend-preorderbegin==1) return root;
        int delimiterIndex;
        for(delimiterIndex=inorderbegin;delimiterIndex<inorderend-1;++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+leftinorderend-leftinorderbegin;
        int rightpreorderbegin=preorderbegin+1+leftinorderend-leftinorderbegin;
        int rightpreorderend=preorderend;
        
        root->left=traversal(inorder,leftinorderbegin,leftinorderend,preorder,leftpreorderbegin,leftpreorderend);
        root->right=traversal(inorder,rightinorderbegin,rightinorderend,preorder,rightpreorderbegin,rightpreorderend);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
     
        if(!inorder.size() || !preorder.size()) return NULL;
        return traversal(inorder,0,inorder.size(),preorder,0,preorder.size());
    }
};

题目5:654. 最大二叉树

题目描述:
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:

二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。

示例 1:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第8张图片

输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:

  • [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    • [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
      • 空数组,无子节点。
      • [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
        • 空数组,无子节点。
        • 只有一个元素,所以子节点是一个值为 1 的节点。
    • [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
      • 只有一个元素,所以子节点是一个值为 0 的节点。
      • 空数组,无子节点。

示例 2:
LeetCode刷题复盘笔记:打爆二叉树(续四)(路径总和,构造二叉树,最大二叉树)_第9张图片

输入:nums = [3,2,1]
输出:[3,null,2,null,1]

C++代码:

class Solution {
     
public:
    TreeNode* traversal(vector<int>& nums,int left,int right){
     
        if(left>=right) return NULL;
        int maxindex=left;
        for(int i=left+1;i<right;++i){
     
            if(nums[i]>nums[maxindex]) 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) {
     
        return traversal(nums,0,nums.size());
    }
};

总结

遇到调试半天调不出来的题目的时候,要学会打日志来调试,把流程打印出来看看符不符合自己的思路!

二叉树

递归函数究竟什么时候需要返回值,什么时候不要返回值?
1.如果需要搜索整颗二叉树,那么递归函数就不要返回值
2.如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。

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