leetcode872 叶子相似的树
这题本身不难,树的遍历。有几个注意点,一个是String的使用方法,另一个是数据中的坑。
首先我想用一个字符串来储存结果,然后判断两个字符串是否相等。但是这里就有几个问题:
- String类本身分为两种,一种是栈上的常量,一种是堆上的对象,需要注意的是,“只有常量才能使用+号正常相加”是一种典型的错误观念,二者仅在初始化以及存储方式上有差别,不存在用法上的不同。
- 前面的博文中提到过,String类是一类不可改变类,内容一旦确定即不可改变,所以对其进行“+”与“+=”操作将会产生新的String类,String类占用的空间将越来越多。
- 那么即使不计空间浪费,+号就是个好的字符串连接选择吗?也不是。如果是for或者while这种循环还好,如果是递归,就出现问题了。java中的函数参数传递本身是引用传递,但是这种参数的引用传递与C++中的思维不太相同。java中的形参实际上是一个储存实参地址的变量,这样对形参使用=号赋值的话,并不是说实参变成了新的对象的地址,而是说形参变成了新的对象的地址,这在某种程度上类似值传递。但是如果调用该形参储存的对象的方法对该对象进行修改的话,实参也会被修改,因为他们的地址是一样的,这就又像是引用传递了。因此,递归中使用“+=”对字符串进行修改,是无法实现+=的效果的,即使是最简单的尾递归也会因为参数传递的原因导致计算结果被封存在递归的底层,如果递归再复杂些,如本题这样,那这个问题就导致了完全的失效了。
- 因此,我们实际上可以把额外空间浪费和形参实参传递问题归结于一个问题,那就是消除String类的不可修改性,让所有的修改发生在同一地址同一对象,StringBuilder类就解决了这一问题。“+=”用append()方法代替(使用对象本身的方法而不是产生新的对象,很合理不是吗)。该方法可以直接appendString类。如果需要线程安全的StringBuilder类,那就使用StringBuffer类。
- 需要注意的是,StringBuilder没有复写equals方法,它实际上比较的还是地址,因此需要把它toString一下。
代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public void backTrack(TreeNode root, StringBuilder tree){
if(root.left == null && root.right == null){
tree.append(String.valueOf(root.val));
}
if(root.left != null){
backTrack(root.left, tree);
}
if(root.right != null){
backTrack(root.right, tree);
}
}
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
// StringBuilder可以减少内存使用
StringBuilder t1 = new StringBuilder();
StringBuilder t2 = new StringBuilder();
backTrack(root1, t1);
backTrack(root2, t2);
return t1.toString().equals(t2.toString());
}
}
但是即使这样,问题还是没有解决。。因为万恶的测试者设计了这样一个测试用例,阻断了我使用字符串的想法:
[3,5,1,6,2,9,8,null,null,7,14] [3,5,1,6,71,4,2,null,null,null,null,null,null,9,8]
因此最后,我还是乖乖用回了List…
class Solution {
public void backTrack(TreeNode root, List<Integer> tree){
if(root.left == null && root.right == null){
tree.add(root.val);
}
if(root.left != null){
backTrack(root.left, tree);
}
if(root.right != null){
backTrack(root.right, tree);
}
}
public boolean leafSimilar(TreeNode root1, TreeNode root2) {
List<Integer> t1 = new ArrayList<>();
List<Integer> t2 = new ArrayList<>();
backTrack(root1, t1);
backTrack(root2, t2);
return t1.equals(t2);
}
}
0ms 36MB