递归回溯 值传递

在写算法题的时候,犯了一些错误,突入忘记了java是值传递,方法内的int和String之类的因此都是固定的(String是由于别的方法就算改变这个String,也是另外生成一个新的String,int则是值传递),而像ArrayList这些(比如递归回溯时候的path),值传递是一个地址,别的方法改变了,那就要回溯,否则方法栈回溯的时候,方法对应的变量就发生了变化。

回溯位置

关于回溯位置是在for循环内还是外,看他改变路径的地方,其实平常完整执行完一个方法,你方法内,写了一个改变路径和一个回溯路径,两两抵消,写哪都没事,但是最后一次你的代码加入结果的时候(第一次也是,可能到下一个选择执行的时候还没执行到回溯),可能这两步就执行了一步,那么就有问题了,所以我们分析的时候,看看最后一步会不会只加不减,那就会有问题,都不加不减或者加了也减了就没事。或者看下一个选择的时候,这时候路径对不对,有没有回溯正确,分析一下上一个选择。

路径总和

在这里插入图片描述
来看一下这题,下面两种回溯都是对的,可问题是为啥一个弹出两次,一个if一次,而下面的java代码只要最后写一次,其实问题就出在最后一次加入结果集的时候,上面的代码执行到叶子节点时候,明显不会执行下面的if语句里面的弹出回溯,而java的则会执行一次回溯。重点还是分析是不是有进有出,进出的总次数,主要分析第一次和最后一次

if(root->left!=NULL) {
       dfs(root->left, sum); 
       path.pop_back();
       }
if(root->right!=NULL) {
       dfs(root->right, sum); 
       path.pop_back();
       }
class Solution {
    List<List<Integer>> res = new ArrayList<>();
    public List<List<Integer>> pathSum(TreeNode root, int targetSum) {
        List<Integer> path = new ArrayList<>();
        findPath(root,path,targetSum);
        return res;

    }
    public void findPath(TreeNode root,List<Integer> path,int targetSum){
        if(root == null){
            return;
        }
        path.add(root.val);
        if(root.left == null && root.right == null && targetSum == root.val){
            res.add(new ArrayList(path));
        }
        findPath(root.left,path,targetSum - root.val);
        findPath(root.right,path,targetSum - root.val);
        path.remove(path.size()-1);
    }
}

总结:

String在同一个方法内引用的内容固定,也就是递归下去的两个方法内参数内容是固定的,参见隐式回溯代码,不需要进行直接的回溯,两个方法内参数依然是那个String,而这题需要String发生了改变,同一个方法内第二次调用时候,String应该已经减去许多,这时候需要发生变化就定义一个全局变量,不走方法内值传递。走的是全局引用,一旦发生改变,就是新创建一个对象,引用的指向也发生改变。
而ArrayList这些可以走值传递,但是又不想发生变化时,就需要回溯。

序列化与反序列化二叉树

如果把String带入参数,那么 t.left = Deserialize(); t.right = Deserialize();方法内应该含有String,这时候就会出现左右子树使用的String一样。

private String deserializeStr;

public String Serialize(TreeNode root) {
    if (root == null)
        return "#";
    return root.val + " " + Serialize(root.left) + " " + Serialize(root.right);
}

public TreeNode Deserialize(String str) {
    deserializeStr = str;
    return Deserialize();
}

private TreeNode Deserialize() {
    if (deserializeStr.length() == 0)
        return null;
    int index = deserializeStr.indexOf(" ");
    String node = index == -1 ? deserializeStr : deserializeStr.substring(0, index);
    deserializeStr = index == -1 ? "" : deserializeStr.substring(index + 1);
    if (node.equals("#"))
        return null;
    int val = Integer.valueOf(node);
    TreeNode t = new TreeNode(val);
    t.left = Deserialize();
    t.right = Deserialize();
    return t;
}

隐式回溯 二叉树的所有路径

在这里插入图片描述

class Solution {
    List<String> res = new ArrayList<String>();
    public List<String> binaryTreePaths(TreeNode root) {
        backtracking(root,"");
        return res;

    }

    public void backtracking(TreeNode root, String path){ 
        if(root == null){
            return;
        }
        StringBuffer pathSB = new StringBuffer(path);
        pathSB.append(Integer.toString(root.val));
        if(root.left == null && root.right == null){
            res.add(pathSB.toString());
            //最后一次可不需要再执行下面的内容了,当然这题执行也没事,不涉及到路径的回溯,因为每个方法内都是新的StringBuffer
            return;
        }
        pathSB.append("->");
        //后续的改变是新的StringBuffer,效果也是一样,不需要回溯
        backtracking(root.left,pathSB.toString());
        backtracking(root.right,pathSB.toString());
    }

}

分割回文串

在这里插入图片描述

class Solution {
    List<List<String>> res = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<List<String>> partition(String s) {
        int len = s.length();
        //判断是否回文串dp
        boolean[][] dp = new boolean[len][len];
        for(int i = len - 1; i >= 0; i--){
            for(int j = i; j <= len - 1; j++){
                if(s.charAt(i) == s.charAt(j)){
                    if(j - i <= 1){
                        dp[i][j] = true;
                    }else if(dp[i+1][j-1]){
                        dp[i][j] = true;
                    }
                }
            }
        }
        backtracking(s,0,dp);
        return res;
    }

    public void backtracking(String s, int startIndex, boolean[][] dp){
        if(startIndex >= s.length()){
            res.add(new ArrayList(path));
        }
        for(int i = startIndex; i < s.length(); i++){
            //看看是不是回文串,是的话才能开启下一层
            if(!dp[startIndex][i]){
                continue;
            }
            path.add(s.substring(startIndex,i + 1));
            backtracking(s,i + 1,dp);
            path.remove(path.size() - 1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值