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