• [LeetCode] #112 #113 #437 Path Sum Series


    首先要说明二叉树的问题就是用递归来做,基本没有其他方法,因为这数据结构基本只能用递归遍历,不要把事情想复杂了。

    #112 Path Sum

    原题链接:https://leetcode.com/problems/path-sum/

    判断从树的根节点到叶子节点的路径中,是否有一条所有节点上的值之和和特定的数字,即sum

    从根节点到叶子节点,线路的起点的是固定的,只需要不断递归下去,判断在叶子节点处是否满足根节点加到该节点的值之和为sum

    这个限制条件把这个问题简化了很多很多。

    /**
     * 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) return false;
            if (root->val == sum && root->left == NULL && root->right == NULL) return true;
            return hasPathSum(root->left, sum - root->val) || hasPathSum(root->right, sum - root->val);
        }
    };
    

    #113 Path Sum II

    与前题要做的事情一致,只是现在要求输出路径。如果路径有多条,要求输出多条路径。

    要输出路径,在递归的过程中肯定是要有一个传址的变量vector<int>将路径记录下来。有多条路径,需要把多条路径vector<vector<int> >记录下来。

    /**
     * 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:
        vector<vector<int>> pathSum(TreeNode* root, int sum) {
            vector<vector<int> > paths;
            vector<int> path;
            pathSumHelper(root, sum, path, paths);
            return paths;
        }
    private:
        void pathSumHelper(TreeNode* root, int sum, vector<int>& path, vector<vector<int>>& paths) {
            if (root == NULL) return;
            path.push_back(root->val);
            if (root->val == sum && root->left == NULL && root->right == NULL) { 
    	        paths.push_back(path);
            }
            pathSumHelper(root->left, sum - root->val, path, paths);
            pathSumHelper(root->right, sum - root->val, path, paths);
            path.pop_back();
        }
    };
    

    这里有一点搞不懂,为什么最后要进行path.pop_back(),如果我把代码写成这样子:

        void pathSumHelper(TreeNode* root, int sum, vector<int>& path, vector<vector<int>>& paths) {
            if (root == NULL) return;
            path.push_back(root->val);
            if (root->left == NULL && root->right == NULL) {
                if (root->val == sum) {
                    paths.push_back(path);
                }
                path.pop_back();
            }
            pathSumHelper(root->left, sum - root->val, path, paths);
            pathSumHelper(root->right, sum - root->val, path, paths);
        }
    

    然后,发现如果这么写我是错的。对于下面的这一棵二叉树,得到的结果是[[5,4,11,2],[5,4,11,8,4,5]],正确结果是[[5,4,11,2],[5,8,4,5]]。第二条路径中多了4, 11,问题出在只是把根节点去除掉,没有去除中间节点,使得中间节点及其子孙节点中的中间节点出现在了经过其兄弟节点的路径。

    Tree

    如,左侧的4节点会留在右子树的路径中是因为,调用根节点的pathSumHelper时,会调用两次pathSumHelper(root->left/* node 4 */, sum - root->val, path, paths);pathSumHelper(root->right/* node 8 */, sum - root->val, path, paths);,在第一次调用完成之后,path变量中的4节点未被删除,所以存留在了路径[5,4,11,8,4,5]中(就是第一个4)。

    #437 Path Sum III

    继续,判断是否存在路径上的值之和为特定的数字sum。变化在于起点不固定、终点也不固定,值存在负数(其实无所谓,因为前面的代码没有判断数值超过sum就不再递归)。最后的输出是路径的条数。

    /**
     * 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:
        int pathSum(TreeNode* root, int sum) {
            if (!root) return 0;
            return sumUp(root, 0, sum) + pathSum(root->right, sum) + pathSum(root->left, sum);
        }
        
    private:
        int sumUp(TreeNode* root, int pre, int sum) {
            if (!root) return 0;
            int current = pre + root->val;
            return (current == sum) + sumUp(root->right, current, sum) + sumUp(root->left, current, sum); // 如果当前节点能够满足条件,有一条路径了,但是还是要继续搜索左右子树,因为值不全为非负,这里返回的路径都具有同一个根节点。
        }
    };
    

    这里有两个递归函数,函数pathSumreturn sumUp(root, 0, sum) + pathSum(root->right, sum) + pathSum(root->left, sum);是以该节点root为起点的路径条数、以root->right为起点或者以其子孙节点为起点的路径条数、以root->left为起点或者以其子孙节点为起点的路径条数。

  • 相关阅读:
    Lightoj 1422
    BZOJ 1801 [AHOI 2009] 中国象棋(DP)
    [SCOI2008]天平
    [SCOI2008]奖励关
    [USACO08JAN]haybale猜测Haybale Guessing
    [Sdoi2016]征途
    [SHOI2014]概率充电器
    [USACO08JAN]电话线Telephone Lines
    [HEOI2016]排序
    友好的生物
  • 原文地址:https://www.cnblogs.com/JingeTU/p/6390936.html
Copyright © 2020-2023  润新知