zoukankan      html  css  js  c++  java
  • leetcode Path Sum

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

    For example:
    Given the below binary tree and sum = 22,

                  5
                 / 
                4   8
               /   / 
              11  13  4
             /        
            7    2      1
    

    return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

    有点难,总之,我没想出来,刚开始我觉得不能用递归,因为你总要回溯到根节点。总之就是想错了。

    后来又忽略了一旦访问过的路径就不需要访问了。总之,没想出来。

    还有就是只有到叶子节点才判断是否和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 PathNum(TreeNode*root,int sum, int cursum){
            if(root==NULL) return false;
            if(!root->left&&!root->right) return sum==cursum+root->val;
            return PathNum(root->left,sum,cursum+root->val)||PathNum(root->right,sum,cursum+root->val);
        }
        bool hasPathSum(TreeNode* root, int sum) {
            return PathNum(root,sum,0);
        }
    };

    我没有想到的是,可以加入cursum来暂存路径上的节点和。

    再看一个用map来储存是否访问过节点的非递归方法:

    /**
     * Definition for binary tree
     * 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;
                
            stack<TreeNode*> stk;
            int cur = root->val;
            unordered_map<TreeNode*, bool> visited;
            stk.push(root);
            visited[root] = true;
            
            while(!stk.empty())
            {
                TreeNode* top = stk.top();
                if(!top->left && !top->right)
                {//leaf
                    if(cur == sum)
                        return true;
                }
                
                if(top->left && visited[top->left] == false)
                {
                    stk.push(top->left);
                    visited[top->left] = true;
                    cur += top->left->val;
                    continue;
                }
                if(top->right && visited[top->right] == false)
                {
                    stk.push(top->right);
                    visited[top->right] = true;
                    cur += top->right->val;
                    continue;
                }
                
                stk.pop();
                cur -= top->val;
            }
            return false;
        }
    };

    关于这个题我还是想了很多的:

    首先,DFS:

    void depthFirstSearch(Tree root){
        stack<Node *> nodeStack;  //使用C++的STL标准模板库
        nodeStack.push(root);
        Node *node;
        while(!nodeStack.empty()){
            node = nodeStack.top();
            printf(format, node->data);  //遍历根结点
            nodeStack.pop();
            if(node->rchild){
                nodeStack.push(node->rchild);  //先将右子树压栈
            }
            if(node->lchild){
                nodeStack.push(node->lchild);  //再将左子树压栈
            }
        }
    }
      

    但是这道题远不止DFS这么简单啊,它需要保存路径,也就是有的节点只存在一次(只有一个孩子的节点),有的节点要出现两次(有两个孩子的节点)。

    再来本来想用vector储存路径,涉及到了numeric头文件中的accumulate函数

    假设vec是一个int型的vector对象,下面的代码:

    //sum the elements in vec starting the summation with the value 42
    int sum = accumulate(vec.begin() , vec.end() , 42);

    将sum设置为vec的元素之和再加上42。

    accumulate带有三个形参:头两个形参指定要累加的元素范围,第三个形参则是累加的初值

    accumulate函数将它的一个内部变量设置为指定的初始值,然后在此初值上累加输入范围内所有元素的值。accumulate算法返回累加的结果,其返回类型就是其第三个实参的类型

    用于指定累加起始值的第三个参数是必要的,因为accumulate对将要累加的元素类型一无所知,除此之外,没有别的办法创建合适的起始值或者关联的类型。

    accumulate对要累加的元素类型一无所知,这个事实有两层含义。首先,调用该函数时必需传递一个初始值,否则,accumulate将不知道使用什么初始值。其次,容器内的元素类型必须与第三个实参的类型匹配,或者可转换为第三个实参的类型。在accumulate内部,第三个实参用作累加的起点;容器内的元素按顺序连续累加到综合之中。因此,必须能够将元素类型加到总和类型上。

    假定V是vector<double>类型的对象,则调用accumulate<v.begin() , v.end() , 0>是否有错?如果有的话,错在哪里?

    从函数调用上看没有错误。
    调用accumulate函数必须满足的条件包括:容器内的元素类型必须与第三个实参的类型匹配,或者可转换为第三个实参的类型。上述调用中的第三个实参为int类型,而vector对象中的元素的类型为double类型,可以转换为int类型。

    但计算的结果不准确。因为将double类型转换为int类型会截去小数部分,得到的求和结果是各元素的整数部分的和,是一个int类型的值,与实际的元素值总和相比会有比较大的误差。

    考虑下面的例子,可以使用accumulate把string型的vector容器中的元素连接起来:

    //concatenate elements from V and store in sum
    string sum = accumulate(v.begin() , v.end() , string(" "));

    这个函数调用的效果是:从空字符串开始,把vec里的每个元素连接成一个字符串。

     c.pop_back() 删除c的最后一个元素,返回void

  • 相关阅读:
    Bootstrap 学习笔记 之网格系统
    自定义属性建立匹配、对应关系——JS学习笔记2015-5-27(第40天)
    CSS那些事儿——关于如何提高编写代码的能力
    自定义属性,匹配数组内容——JS学习笔记2015-5-26(第39天)
    css学习之幻灯片(轮播图)原理
    自定义属性,第一节——JS学习笔记2015-5-25(第38天)
    字体不同,造成的显示异常
    浮动相关理解,以及清除浮动的方法总结
    border实现三角箭头
    go mode
  • 原文地址:https://www.cnblogs.com/LUO77/p/5025610.html
Copyright © 2011-2022 走看看