您的位置:首页 > 其它

leetcode-437-Path Sum III

2017-02-22 11:23 337 查看

问题

题目:[Path Sum III]

思路

这个题目其实挺好的,感觉对于preOrder的理解一下又上升了一个层次。

当然,这个题本身我没做出来。实际做的时候,只能说做出了一部分。

还是对于遍历这件事本省立即的不充分。还有对于递归的语义没有想清楚。

这到题麻烦的一点是说:不一定从根节点开始,你可以从任意节点。只要是从它开始字段和为sum即可。

那这个题的解法不就是,遍历每一个点,然后从每一节点开始寻找和为sum的子段。这个思路是没有问题的。就是一道遍历的问题。

然后,visit的实现非诚清晰。

然后,主函数语义是什么?这个我一直想的不是很明白

还是要对树的遍历语义充分理解就明白了。

想一想最基本的遍历:

void preOrder(TreeNode* root){
if(!root) return;
else{
visit(root);
preOrder(root->left);
preOrder(root->right);
}
}


遍历一棵树,可以划分为三个子问题。

访问root节点

遍历左子树

遍历右子树

那么同样的,对于pathSum(root, target)的语义:查找以root为根但不见得以root开始的和为target的路径。

可以划分为三个子问题。

以root开始和为target的路径

查找以root->left为根但不见得以root->left开始的和为target的路径。

查找以root->right为根但不见得以root->right开始的和为target的路径。

这样语义不就顺了,我第一次之所以错,就是因为语义的事我没想清楚。换个角度,如果你在pathSum递归调用的时候,缩小了target的规模,那么你再调用一层的时候,从子节点开始就不是寻找和为target的节点了。这样显然就不对了。

这个题不错,加深了对递归的理解,这个题没有对target缩减规模,但是树的深度还是缩减了。

代码

/**
* 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;
else{

int ans = 0;

ans += visit(root, sum);
ans += pathSum( root->left, sum );
ans += pathSum( root->right, sum );
return ans;
}
}
private:
int visit(TreeNode* root, int target){
if(!root) return 0;
else{
int ans = 0;
if(root->val == target) ++ans;
ans += visit(root->left, target-root->val);
ans += visit(root->right, target-root->val);
return ans;
}
}
};


思路1

方法没区别,又写了一遍。

代码1

/**
* 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;
int ans = 0;
dfs(root, sum, ans);
return ans;
}
private:
void dfs(TreeNode* root, int target, int& ans){
if(!root) return;

visit(root, 0, target, ans );
dfs(root->left, target, ans);
dfs(root->right, target, ans);
}
void visit(TreeNode* root, int cur_sum, int target, int& ans){
if(!root) return;
cur_sum += root->val;
if(cur_sum == target) ++ans;

visit(root->left, cur_sum, target, ans);
visit(root->right, cur_sum, target, ans);
}
};


思路1

又写了一遍。

注意一点就好,对于pathSum从左右枝走的时候,还是要判断路径和为sum。

对于问题的缩减是在visit的时候。

代码

/**
* 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;
int ret = 0;
ret += visit(root, sum);
ret += pathSum(root->left, sum);
ret += pathSum(root->right, sum);
return ret;
}
private:
int visit(TreeNode* root, int sum){
if(!root) return 0;
int ans = 0;
if(root->val == sum) ++ans;
ans += visit(root->left, sum-root->val);
ans += visit(root->right, sum-root->val);
return ans;
}
};


思路2

这个题的思路我是有的,这个题其实也是遍历。

只不过每次遍历的visti又是一个遍历。

注意以下两个接口的区别:

dfs当中的root,代表从以这个root开始的子树当中,存在的所有路径和为target的路径,也就是说从这个root子树的任何一个节点都可能是一条全新的path。

但是,visit接口当中的path,表明的就是以当前root开始的path。

前面的代表整个root子树当中,所有根节点开始的path,而后者只是一个root的path。

4000
再说一遍,前者的root子树当中的每一个节点都可以开始一条path,而后者root代表就是从该root开始的一条path.

/**
* 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;
int ans = 0;

dfs(root, sum, ans);
return ans;
}
private:
void dfs(TreeNode* root, int target, int& ans){
if(root){
visit( root, 0, target, ans);
dfs( root->left, target, ans );
dfs( root->right, target, ans );
}
}
private:
void visit(TreeNode* root, int cur, int target, int& ans){
if(root){
cur += root->val;
if( cur == target ) ++ans;
visit(root->left, cur, target, ans);
visit(root->right, cur, target, ans);
}
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: