从求二叉树的所有路径题目看String和StringBuffer的区别

二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

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

1.方法一:临时路径使用String存储

class Solution {
    List<String> res = new ArrayList<String>();
    public List<String> binaryTreePaths(TreeNode root) {
        if(root == null){
            return res;
        }
        // String init = "";
        // dfs(root, init);   //上面这两行ok.
        dfs(root, "");
        return res;

    }
    public void dfs(TreeNode root,String s) {
    //public void dfs(TreeNode root , Strng s){
        if(root == null){
            return;
        }
        if(root.left == null && root.right == null){
            //String temps = new String(root.val);
            s = s+root.val;  // ok
            //s = s + String.valueOf(root.val);  ok
            //res.add(new String(s));      ok
            res.add(s);   //ok 此处是否是new String都行
        }
        s = s + root.val;
        s = s+ "->";
        dfs(root.left, s); // s是String类型,在left这一侧会被操作改动,例如
        dfs(root.right,s);
    }
}

2.错误的方法二: 临时路径使用StringBuffer存储

如果我们直接把方法一中的代码粘贴过来,然后把String的地方全部改为StringBuffer,会发现答案不正确。

要清楚错误原因:我们先了解一下StringBuffer和String的区别

1)String类是不可变类,其对象是不可更改的常量。而StringBuffer是可变类,它的对象是可以扩充和修改的。

2)对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新对象的地址赋给原引用。

3)StringBuffer是一个可变对象,当对他进行修改时候,不会像String那样重新建立对象。

知道上面区别之后我们通俗递讲解一下,上面方法一中的代码为什么可以使用String,而不能使用StringBuffer了。

重点看这几行代码:

s = s+ root.val;  (例如目前存放的是"qwer")

dfs(root.left, s);

dfs(root.right,s);

    我们的代码逻辑是:把当前存放的“qwer”去左子树遍历,把当前存放的“qwer”去右子树遍历。

由于我们的String每次修改,例如 s = s+ root.val,都是创建一个新对象,

所以s="qwer"进入左子树之后,原始的s = "qwer"不会变, 只是会新生成一个s,所以原始的"qwer"

还是会以"qwer"的值进入右子树。

    而当我们使用的是StringBuffer,StringBuffer是一个可变对象,原始s="qwer"进入左子树之后,左子树里面的逻辑会改变原始s的值了。

所以进入右子树的s就不再是“qwer”了。所以左子树产生的结果,这样当然就不符合我们的逻辑。

3.正确的方法二:使用StringBuffer存储。

但是我们可以事先对s = "qwer"进行一下备份s_copy,让s = "qwer"进入左子树,

让s_copy = "qwer"进入右子树,这样就可以符合整体逻辑了

class Solution {
    List<String> res = new ArrayList<String>();
    public List<String> binaryTreePaths(TreeNode root) {
        if(root == null) return res;
        dfs(root,new StringBuffer());
        return res;
    }
    public void dfs(TreeNode root , StringBuffer s){
        if(root == null) return;
        if(root.left == null && root.right == null){
            s.append(root.val);
            res.add(s.toString());
        }
        s.append(root.val);
        s.append("->");
        StringBuffer s_copy = new StringBuffer(s);
        dfs(root.left , s);
        dfs(root.right, s_copy);
    }
}

核心一句代码:StringBuffer s_copy = new StringBuffer(s);注意必须使用new StringBuffer()这种产生对象的方法,不能直接

使用StringBuffer s_copy = s这种方法,因为这种方法还是没有产生新对象,还是会错误。

4.总结补充

1)我们借助这个样例可以很好的对是否创新一个新对象,以及创建新对象对代码逻辑产生的影响

     有一个很好的认知了。以前总是停留在文字概念层面,现在深化到理解运用层面了。

2)在二叉树,树的遍历这一块我们经常使用的是String,但是在回溯那一块,我们StringBuffer用的比较多

      我们要具体问题具体分析,在理解的基础上形成肌肉记忆,不要混乱,尽量从逻辑底层出发思考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值