0
点赞
收藏
分享

微信扫一扫

LeetCode 112. 路径总和 、113. 路径总和 II 思考分析


目录

  • ​​112. 路径总和​​
  • ​​题目​​
  • ​​递归解​​
  • ​​递归解,其他人的解法​​
  • ​​迭代解,其他人的解法​​
  • ​​113. 路径总和 II​​
  • ​​题目​​
  • ​​递归解​​
  • ​​递归解,参考别人的思路​​

112. 路径总和

题目

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,
LeetCode 112. 路径总和 、113. 路径总和 II 思考分析_算法
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。

递归解

1、函数参数:当前树的根结点、当前累积的路径和,目标路径和;返回值为空
2、终止条件:该结点为空
3、单层逻辑:如果该结点不为空,则在累积路径和上加上该结点的值。如果该结点是叶子结点,判断此时的累积路径和与目标路径和是否相同,如果相同则将全局变量ifHas改为true,认为能够找到路径和为目标值的路径。然后返回父结点,回溯到上一个状态,参数会自动更正为上一个状态的参数。接下来就是按顺序对该结点的左右孩子进行遍历

这个思路是有问题的,因为它只在叶子结点之后才回溯,这是不合理的,但是也能AC。

/**
* 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 ifHas=false;
void traversal(TreeNode* cur,int target,int Mysum)
{
if(cur==NULL) return;
if(cur!=NULL) Mysum+=cur->val;
//如果是叶子结点,则进行比较
if(cur->left==NULL && cur->right==NULL)
{
//如果和目标结果相同
if(Mysum == target) ifHas=true;
return;
}
if(cur->left)
{
traversal(cur->left,target,Mysum);
}
if(cur->right)
{
traversal(cur->right,target,Mysum);
}
return ;
}
bool hasPathSum(TreeNode* root, int sum) {
//if(root == NULL) return false;
int Mysum=0;
traversal(root,sum,Mysum);
return ifHas;
}
};

LeetCode 112. 路径总和 、113. 路径总和 II 思考分析_二叉树_02

递归解,其他人的解法

1、函数参数、返回值确定
之前有个结论:如果需要搜索整棵二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径就要及时返回
本题并不需要遍历整棵树,所以递归函数需要返回值,可以用bool类型表示。

bool traversal(TreeNode* cur,int count)

2、终止条件确定
在如何统计一条路径和的方法上,​代码随想录使用递减的方法,让计数器count初始为目标和,然后每次减去遍历路径结点上的数值。如果最后count==0,同时到了叶子结点的话,说明了找到目标和。如果遍历到了叶子结点,cout不为0,就是没找到

if(!cur->left && !cur->right && count == 0) return true;    //遇到叶子结点,并且计数为0
if(!cur->left && !cur->right) return false; //遇到叶子结点,没有找到合适的边,直接返回

3、确定单层递归的逻辑
因为终止条件是判断也自己诶单,所以递归过程中就不要让空结点进入递归了。
递归函数的返回值为true的话说明了找到了合适的路径,应该立刻返回

if(cur->left)
{
count -=cur->left->val;
//遇到叶子结点返回true,则直接返回true;
if(traversal(cur->left,count)) return true;
count +=cur->left->val; //回溯,撤销处理结果
}
if(cur->right)
{
count -=cur->right->val;
//遇到叶子结点返回true,则直接返回true;
if(traversal(cur->right,count)) return true;
count +=cur->right->val; //回溯,撤销处理结果
}
return false;
class Solution {
public:
bool traversal(TreeNode* cur,int count)
{
if(!cur->left && !cur->right && count == 0) return true; //遇到叶子结点,并且计数为0
if(!cur->left && !cur->right) return false; //遇到叶子结点,没有找到合适的边,直接返回
if(cur->left)
{
count -=cur->left->val;
//遇到叶子结点返回true,则直接返回true;
if(traversal(cur->left,count)) return true;
count +=cur->left->val; //回溯,撤销处理结果
}
if(cur->right)
{
count -=cur->right->val;
//遇到叶子结点返回true,则直接返回true;
if(traversal(cur->right,count)) return true;
count +=cur->right->val; //回溯,撤销处理结果
}
return false;
}
bool hasPathSum(TreeNode* root, int sum) {
if(root == NULL) return false;
return traversal(root,sum-root->val);
}
};

迭代解,其他人的解法

如果使用栈模拟递归的话对于回溯如何处理?
此时栈里面的一个元素不仅要记录该结点指针,还要记录从头结点到该结点的路径数值总和。
这里使用pair结构来存放栈里面的元素。(第一次用这个结构)
定义为:

pair<TreeNode*,int> pair<结点指针,路径数值>

为栈中的一个元素。
使用栈模拟前序遍历;

/**
* 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 == NULL) return false;
//此时栈里面要放的是pair<结点指针,路径数值>
stack<pair<TreeNode*,int>> st;
st.push(pair<TreeNode*,int>(root,root->val));
while(!st.empty())
{
pair<TreeNode*,int> node = st.top();
st.pop();
//如果这个结点是叶子结点,同时该结点的路径数值等于sum,那么就返回true
if(!node.first->left &&!node.first->right && sum == node.second ) return true;

//右结点,压进去一个结点的时候,将该结点的路径数值也记录下来
if(node.first->right)
{
st.push(pair<TreeNode*,int>(node.first->right,node.second+node.first->right->val));

}
//右结点,压进去一个结点的时候,将该结点的路径数值也记录下来
if(node.first->left)
{
st.push(pair<TreeNode*,int>(node.first->left,node.second+node.first->left->val));

}
}
return false;
}
};

113. 路径总和 II

题目

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。
LeetCode 112. 路径总和 、113. 路径总和 II 思考分析_算法_03

递归解

同样的道理,Mysum作为函数参数每次返回的时候会自动更正,不需要手动回溯。
完成一次子结果,就将子结果送入paths中。
path需要手动回溯。

path.push_back(cur->left->val);
traversal(cur->left,target,Mysum);
path.pop_back();

同时需要注意,在一开始要将根结点送入path中,因为在我们的递归函数中只对左右孩子进行push_back()

class Solution {
public:
vector<vector<int>> paths;
vector<int> path;
void traversal(TreeNode* cur,int target,int Mysum)
{
if(cur==NULL) return;
if(cur!=NULL)
{
Mysum+=cur->val;
}
//如果是叶子结点,则进行比较
if(cur->left==NULL && cur->right==NULL)
{
//如果和目标结果相同
if(Mysum == target)
{
paths.push_back(path);
}
return;
}
if(cur->left)
{
path.push_back(cur->left->val);
traversal(cur->left,target,Mysum);
path.pop_back();
}
if(cur->right)
{
path.push_back(cur->right->val);
traversal(cur->right,target,Mysum);
path.pop_back();
}
return ;
}
vector<vector<int>> pathSum(TreeNode* root, int sum) {
if(root==NULL) return {};
int Mysum=0;
path.push_back(root->val);
traversal(root,sum,Mysum);
return paths;
}
};

递归解,参考别人的思路

/**
* 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 {
private:
vector<vector<int>> paths;
vector<int> path;
//递归函数不需要返回值,因为我们要遍历整个树
void traversal(TreeNode* cur,int count)
{
if(!cur->left && !cur->right && count == 0) //遇到了叶子结点且找到了和为sum的路径
{
paths.push_back(path);
return;
}
if(!cur->left && !cur->right ) return;
if(cur->left)
{
path.push_back(cur->left->val);
count-=cur->left->val;
traversal(cur->left,count);
count+=cur->left->val;
path.pop_back();
}
if(cur->right)
{
path.push_back(cur->right->val);
count-=cur->right->val;
traversal(cur->right,count);
count+=cur->right->val;
path.pop_back();
}
return;
}
public:
vector<vector<int>> pathSum(TreeNode* root, int sum) {
paths.clear();
path.clear();
if(root==NULL) return paths;
path.push_back(root->val);
traversal(root,sum-root->val);
return paths;
}
};

工程实践上一定要clear,但是由于力扣后台测试数据,每次都是新new一个对象


举报

相关推荐

0 条评论