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

posted @ 2015-12-07 11:30  0giant  阅读(233)  评论(0编辑  收藏  举报