问题
题目:[Path 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;
int ans = 0;
bool found = false;
dfs( root, sum, ans, found);
return found;
}
private:
void dfs(TreeNode* root, int sum, int& ret, bool& found){
if(root&&!found){
ret += root->val;
if(ret == sum){ found = true; return;}
else if( ret > sum ){
ret -= root->val; // backtrace
return ;
}
else{
dfs(root->left, sum, ret, found);
dfs(root->right, sum, ret, found);
}
}
}
};
或者其实你没必要这么写,睡了一晚上发现。这也不算回溯。就是参数传递的时候。不要传递引用了。
代码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:
bool hasPathSum(TreeNode* root, int sum) {
if(!root) return false;
int ans = 0;
bool found = false;
dfs( root, sum, ans, found);
return found;
}
private:
void dfs(TreeNode* root, int sum, int ret, bool& found){
if(root&&!found){
ret += root->val;
if(ret == sum){ found = true; return;}
else if( ret > sum ) return;
else{
dfs(root->left, sum, ret, found);
dfs(root->right, sum, ret, found);
}
}
}
};
思路(本题)
因为要访问到最底层,所以到叶子的时候判断一下就行了。
代码
/**
* 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;
int ans = 0;
bool found = false;
dfs( root, sum, ans, found);
return found;
}
private:
void dfs(TreeNode* root, int sum, int ret, bool& found){
if(root && !found){
ret += root->val;
if(!root->left && !root->right){
if(ret==sum) found = true;
return;
}
dfs( root->left, sum, ret, found );
dfs( root->right, sum, ret, found );
}
}
};
思路2
纯递归,也是如果非要到空采取判断。需要对左右子树的情形均判断。
其实,我这种办法也相当于是判断叶子。不要到空再判断。
这道题的特点是,因为必须要到叶子。所以,要判断不是叶子的情形,以及刚好叶子边界的情形。
代码2
/**
* 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->left && !root->right) return root->val==sum;
else if(root->left&&!root->right) return hasPathSum(root->left, sum-root->val);
else if(!root->left&&root->right) return hasPathSum(root->right, sum-root->val);
else return hasPathSum(root->left, sum-root->val)||hasPathSum(root->right, sum-root->val);
}
};
思路3
这个题目,今天再次考虑,有新的收货。
对于这个题目,不放考虑一个类似的题目,其实他们都是一个题目。
如何判断一个二叉树当中是否存在值为1的叶子?
思路:基本的思路很容易考虑,dfs遍历就可以了,首先要判断是不是叶子,如果是再判断它的值是否为1,如果是1,直接返回true即可。但是,问题是,何时返回false.
我起初的思路是,整个遍历完之后,如果前面没有返回true.那么现在该返回false了。可是,这是个递归函数,什么时候才是最后运行完的时机呢?所以,上面的思路不正确。因为这不是递归解决问题的思路,递归的思路应该是找到原问题和子问题的关系。特别需要注意的时边界条件的情况。如果,不好划分原问题和子问题,那么可以考虑简单的例子,来让抽象问题形象化。
考虑这个二叉树,[1],这个节点是叶子,是1,返回true.
[2],这个节点是叶子,是2,返回false.
[6,1,2],原问题来说,由于6不是叶子,所以问题变成左右两颗子树当中是否存在值为1的叶子,此时问题变成上面的两种情形。
这样问题就很明确了,递归主要是考虑清楚原问题和子问题的关系,然后是边界条件要处理好。如果边界不好写,就考虑一个简单例子,就是只有一层递归的情形。便于想出结果来。
代码如下:
代码3
/**
* 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->left && !root->right )
return root->val == sum;
else
return hasPathSum(root->left, sum-root->val) || hasPathSum(root->right, sum-root->val);
}
};