关于递归函数返回值的讨论
1.需要搜索全局513. 找树左下角的值就没有返回值
2.只需要找出一条符合条件的路径就需要返回值,比如bool
Leetcode112
1.问题描述
2.解决方案
解法一:递归
大致思路呢其实很简单就是遍历所有根到叶子的路径,找到一条就算成功
1.根绝上面的讨论返回值肯定是bool了
2.这个return true/false的过程也是向上传递true/false的过程,我希望这个可以一点一点推导几遍
3.终止条件找到叶子如果符合就true,否则就false
4.递归调用的时候有很浓厚的回溯痕迹,backtracking(root->left,targetSum,curSum+root->val)
class Solution {
public:
bool backtracking(TreeNode* root,int targetSum,int curSum){
if(root== nullptr) return false;
if(root->left== nullptr&&root->right== nullptr){
if(curSum+root->val==targetSum) return true;
else return false;
}
if(backtracking(root->left,targetSum,curSum+root->val)== true) return true;
if(backtracking(root->right,targetSum,curSum+root->val)== true) return true;
return false;
}
bool hasPathSum(TreeNode* root, int targetSum) {
return backtracking(root,targetSum,0);
}
};
java写法基本上一样和c++
public class lc112 {
public boolean back(TreeNode root, int targetSum , int sum) {
if(root==null) return false;
if(root.left==null&&root.right==null){
if(sum+root.val==targetSum) return true;
else return false;
}
if(back(root.left, targetSum, sum+root.val)) return true;
if(back(root.right, targetSum, sum+root.val)) return true;
return false;
}
public boolean hasPathSum(TreeNode root, int targetSum) {
return back(root, targetSum, 0);
}
}
解法二:迭代
其实就是利用栈模拟前序遍历的迭代,有点繁琐,这里暂时就不给出了
Leetcode113
1.问题描述
2.解决方案
大致思路呢很简单,就是遍历所有路径符合就加入结果集
1.首先正如上面的讨论,因为要遍历整个树,所以递归函数不需要返回值
2.遇到叶子如果符合就加入,等等没什么可说的,但是这个回溯很重要!!!
3.记录path,可以放成全局变量,也可以作为递归函数的参数,因为这样回溯时方便一点,但是回溯就没那么明显了
4.说实话这个回溯你得好好想想到底时怎么回溯的,我们path.push_back(root->val),进入左子树递归时,加入了左子树的结点后,再递归右子树,这里看起来没回溯是不是就错了呀,实则不然,这正是将path作为函数参数的特点,就是虽然进入左子树会对path进行改变,但是由于path不是全局便利也不是引用类型,所以转入左子树的path不过是拷贝构造的结果,左子树递归完进入右子树时path还是原来的那个path,这不就回溯了嘛,牛批啊!
path.push_back(root->val);
backtracking(root->left,targetSum,path,curSum+root->val);
backtracking(root->right,targetSum,path,curSum+root->val);
4.如果path是全局变量,这才是显示的回溯,怕自己忘了写出来安心一点
path.push_back(cur->left->val);
backtracking(cur->left,curSum);
path.pop();
class Solution {
public:
vector<vector<int>> ans;
void backtracking(TreeNode* root,int targetSum,vector<int> path,int curSum){
if(root== nullptr) return;
if(root->left== nullptr&&root->right== nullptr){
if(curSum+root->val==targetSum){
path.push_back(root->val);
ans.push_back(path);
}
return;
}
path.push_back(root->val);
backtracking(root->left,targetSum,path,curSum+root->val);
backtracking(root->right,targetSum,path,curSum+root->val);
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
vector<int> path;
backtracking(root,targetSum,path,0);
return ans;
}
};
java的写法和cpp有所不同,区别在于c++的vector< int > path是走拷贝构造,完全是两个对象,而List< Integer > path从始至终都是一个对象,多个引用,所以分析一下具体的回溯过程,就知道,需要显示回溯
1.既然java始终都是一个对象,那其实在函数参数和全局的path没有区别
public class lc113 {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
public void back(TreeNode root, int targetSum, int sum, List<Integer> path) {
path.add(root.val);
sum += root.val;
if(root.left==null&&root.right==null){
if(sum==targetSum){
ans.add(new ArrayList<>(path));
}
return;
}
if(root.left!=null){
back(root.left, targetSum, sum, path);
path.remove(path.size()-1);
}
if(root.right!=null){
back(root.right, targetSum, sum, path);
path.remove(path.size()-1);
}
}
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if(root==null) return ans;
back(root, targetSum, 0, new ArrayList<>());
return ans;
}
}
class lc113_1 {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<>();
public void back(TreeNode root, int targetSum, int sum) {
path.add(root.val);
sum += root.val;
if(root.left==null&&root.right==null){
if(sum==targetSum){
ans.add(new ArrayList<>(path));
}
return;
}
if(root.left!=null){
back(root.left, targetSum, sum);
path.remove(path.size()-1);
}
if(root.right!=null){
back(root.right, targetSum, sum);
path.remove(path.size()-1);
}
}
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if(root==null) return ans;
back(root, targetSum, 0);
return ans;
}
}
2.上面两种都是在各自的回溯函数中,add各自的节点,然后还有另外一直回溯方式,显得更加清楚,那就是在回溯前add对应的节点,然后函数结束后再回溯,两种都可以,我更喜欢下面这种
class lc113_2 {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
List<Integer> path = new ArrayList<>();
public void back(TreeNode root, int targetSum, int sum) {
if(root.left==null&&root.right==null){
if(sum==targetSum){
ans.add(new ArrayList<>(path));
}
return;
}
if(root.left!=null){
path.add(root.left.val);
sum += root.left.val;
back(root.left, targetSum, sum);
path.remove(path.size()-1);
sum -= root.left.val;
}
if(root.right!=null){
path.add(root.right.val);
sum += root.right.val;
back(root.right, targetSum, sum);
path.remove(path.size()-1);
sum -= root.right.val;
}
}
public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
if(root==null) return ans;
else path.add(root.val);
back(root, targetSum, root.val);
return ans;
}
}