目录
- 112. 路径总和
- 题目
- 递归解
- 递归解,其他人的解法
- 迭代解,其他人的解法
- 113. 路径总和 II
- 题目
- 递归解
- 递归解,参考别人的思路
112. 路径总和
题目
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
 给定如下二叉树,以及目标和 sum = 22,
 返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
递归解
1、函数参数:当前树的根结点、当前累积的路径和,目标路径和;返回值为空
2、终止条件:该结点为空
3、单层逻辑:如果该结点不为空,则在累积路径和上加上该结点的值。如果该结点是叶子结点,判断此时的累积路径和与目标路径和是否相同,如果相同则将全局变量ifHas改为true,认为能够找到路径和为目标值的路径。然后返回父结点,回溯到上一个状态,参数会自动更正为上一个状态的参数。接下来就是按顺序对该结点的左右孩子进行遍历
这个思路是有问题的,因为它只在叶子结点之后才回溯,这是不合理的,但是也能AC。
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool ifHas=false;
    void traversal(TreeNode* cur,int target,int Mysum)
    {
        if(cur==NULL)  return;
        if(cur!=NULL)  Mysum+=cur->val;
        //如果是叶子结点,则进行比较
        if(cur->left==NULL && cur->right==NULL)
        {
            //如果和目标结果相同
            if(Mysum == target) ifHas=true;
            return;
        }
        if(cur->left)
        {
            traversal(cur->left,target,Mysum);
        }
        if(cur->right)
        {
            traversal(cur->right,target,Mysum);
        }
        return ;
    }
    bool hasPathSum(TreeNode* root, int sum) {
        //if(root == NULL) return false;
        int Mysum=0;
        traversal(root,sum,Mysum);
        return ifHas;
    }
};
递归解,其他人的解法
1、函数参数、返回值确定
之前有个结论:如果需要搜索整棵二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径就要及时返回。
 本题并不需要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。
bool traversal(TreeNode* cur,int count)2、终止条件确定
 在如何统计一条路径和的方法上,代码随想录使用递减的方法,让计数器count初始为目标和,然后每次减去遍历路径结点上的数值。如果最后count==0,同时到了叶子结点的话,说明了找到目标和。如果遍历到了叶子结点,cout不为0,就是没找到
if(!cur->left && !cur->right && count == 0) return true;    //遇到叶子结点,并且计数为0
if(!cur->left && !cur->right) return false;         //遇到叶子结点,没有找到合适的边,直接返回3、确定单层递归的逻辑
 因为终止条件是判断也自己诶单,所以递归过程中就不要让空结点进入递归了。
 递归函数的返回值为true的话说明了找到了合适的路径,应该立刻返回
if(cur->left)
{
  count -=cur->left->val;
  //遇到叶子结点返回true,则直接返回true;
  if(traversal(cur->left,count)) return true;
  count +=cur->left->val;     //回溯,撤销处理结果
}
if(cur->right)
{
  count -=cur->right->val;
  //遇到叶子结点返回true,则直接返回true;
  if(traversal(cur->right,count)) return true;
  count +=cur->right->val;      //回溯,撤销处理结果
}
return false;class Solution {
public:
    bool traversal(TreeNode* cur,int count)     
    {
        if(!cur->left && !cur->right && count == 0) return true;        //遇到叶子结点,并且计数为0
        if(!cur->left && !cur->right) return false;                 //遇到叶子结点,没有找到合适的边,直接返回
        if(cur->left)
        {
            count -=cur->left->val;
            //遇到叶子结点返回true,则直接返回true;
            if(traversal(cur->left,count)) return true;
            count +=cur->left->val;         //回溯,撤销处理结果
        }
        if(cur->right)
        {
            count -=cur->right->val;
            //遇到叶子结点返回true,则直接返回true;
            if(traversal(cur->right,count)) return true;
            count +=cur->right->val;            //回溯,撤销处理结果
        }
        return false;
    }
    bool hasPathSum(TreeNode* root, int sum) {
        if(root == NULL) return false;
        return traversal(root,sum-root->val);
    }
};迭代解,其他人的解法
如果使用栈模拟递归的话对于回溯如何处理?
 此时栈里面的一个元素不仅要记录该结点指针,还要记录从头结点到该结点的路径数值总和。
 这里使用pair结构来存放栈里面的元素。(第一次用这个结构)
 定义为:
pair<TreeNode*,int> pair<结点指针,路径数值>
为栈中的一个元素。
 使用栈模拟前序遍历;
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int sum) {
        if(root == NULL) return false;
        //此时栈里面要放的是pair<结点指针,路径数值>
        stack<pair<TreeNode*,int>> st;
        st.push(pair<TreeNode*,int>(root,root->val));
        while(!st.empty())
        {
            pair<TreeNode*,int> node = st.top();
            st.pop();
            //如果这个结点是叶子结点,同时该结点的路径数值等于sum,那么就返回true
            if(!node.first->left &&!node.first->right && sum == node.second ) return true;
            //右结点,压进去一个结点的时候,将该结点的路径数值也记录下来
            if(node.first->right)
            {
                st.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));
            }
            //右结点,压进去一个结点的时候,将该结点的路径数值也记录下来
            if(node.first->left)
            {
                st.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));
                
            }
        }
        return false;
    }
};113. 路径总和 II
题目
给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。
说明: 叶子节点是指没有子节点的节点。
递归解
同样的道理,Mysum作为函数参数每次返回的时候会自动更正,不需要手动回溯。
 完成一次子结果,就将子结果送入paths中。
 path需要手动回溯。
path.push_back(cur->left->val);
 traversal(cur->left,target,Mysum);
 path.pop_back();同时需要注意,在一开始要将根结点送入path中,因为在我们的递归函数中只对左右孩子进行push_back()
class Solution {
public:
    vector<vector<int>> paths;
    vector<int> path;
    void traversal(TreeNode* cur,int target,int Mysum)
    {
        if(cur==NULL)  return;
        if(cur!=NULL)
        {
            Mysum+=cur->val;
        }  
        //如果是叶子结点,则进行比较
        if(cur->left==NULL && cur->right==NULL)
        {
            //如果和目标结果相同
            if(Mysum == target)
            {
                paths.push_back(path);
            }
            return;
        }
        if(cur->left)
        {
            path.push_back(cur->left->val);
            traversal(cur->left,target,Mysum);
            path.pop_back();
        }
        if(cur->right)
        {
            path.push_back(cur->right->val);
            traversal(cur->right,target,Mysum);
            path.pop_back();
        }
        return ;
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if(root==NULL) return {};
        int Mysum=0;
        path.push_back(root->val);
        traversal(root,sum,Mysum);
        return paths;
    }
};递归解,参考别人的思路
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
private:
    vector<vector<int>> paths;
    vector<int> path;
    //递归函数不需要返回值,因为我们要遍历整个树
    void traversal(TreeNode* cur,int count)
    {
        if(!cur->left && !cur->right && count == 0)     //遇到了叶子结点且找到了和为sum的路径
        {
            paths.push_back(path);
            return;
        }
        if(!cur->left && !cur->right ) return;
        if(cur->left)
        {
            path.push_back(cur->left->val);
            count-=cur->left->val;
            traversal(cur->left,count);
            count+=cur->left->val;
            path.pop_back();
        }
        if(cur->right)
        {
            path.push_back(cur->right->val);
            count-=cur->right->val;
            traversal(cur->right,count);
            count+=cur->right->val;
            path.pop_back();
        }
        return;
    }
public:
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        paths.clear();
        path.clear();
        if(root==NULL) return paths;
        path.push_back(root->val);
        traversal(root,sum-root->val);
        return paths;
    }
};工程实践上一定要clear,但是由于力扣后台测试数据,每次都是新new一个对象
                
                









