Leetcode: Binary Tree Paths 从一道Easy题看Java String链接效率

来源:互联网 发布:好用的vpn 知乎 编辑:程序博客网 时间:2024/05/20 09:47

别说话,快上题!

Given a binary tree, return all root-to-leaf paths.

For example, given the following binary tree:

   1 /   \2     3 \  5

All root-to-leaf paths are:

["1->2->5", "1->3"]

其实这是一道挺简单的Tree的DFS输出路径的题目,但是题目唯一tricky的地方就是输出。它是要输出一个String类型的list,并不是像往常一样输出一个Integer类型的Array。其实就是一个String的链接嘛。

/** * Definition for a binary tree node. * public class TreeNode { *     int val; *     TreeNode left; *     TreeNode right; *     TreeNode(int x) { val = x; } * } */public class Solution {    public List<String> binaryTreePaths(TreeNode root) {        List<String> Result = new ArrayList();                if(root == null){            return Result;        }                        String temp = new String();        pathHelper(root,temp,Result);                        return Result;                    }    private void pathHelper(TreeNode root,                            String temp,                            List<String> Result)    {        if (root == null){            return;        }                        temp += String.valueOf(root.val);        int length = temp.length();                        if (root.left == null && root.right == null){            Result.add(temp);            return;        }                        pathHelper(root.left,temp + "->",Result);        pathHelper(root.right,temp + "->",Result);        temp.substring(0,length-1);    }                                                            }


最后一行是为了确保返递归返回时把上一个解去掉,这样才能找到所有的解。

其实这道题讲究的地方还是挺多的。如果在面试的时候给了这样的解答,会有一个follow up就是如何提高string链接的效率。其实在Java中,String的‘+’操作符是javaJDK中唯一overload的操作符。它其实是完成了append()方法,所以使用‘+’操作符进行字符串链接时效率并没有那么高。

在Thinking in Java的String那章里,作者专门对String的‘+’操作符与StringBuilder中的append()方法的效率进行了一个比较。

public class Concatenation {      public static void main(String[] args) {
        String mango = "mango";        String s = "abc" + mango + "def" + 47;        System.out.println(s);
      }    } /* Output:    abcmangodef47    *///:~
这是作者进行试验的代码。将三个字符串进行链接。使用java JDK中的javap工具我们可以查看JVM在编译这段代码时做了什么

javap -c Concatenation
在command line中输入上面命令  -c 命令会产生JVM编译时候的字节码。跳过一些不重要部分我们可以截取最关键的部分:

public static void main(java.lang.String[]);      Code:
       Stack=2, Locals=3, Args_size=1       0:    ldc #2; //String mango
2:    astore_1   3:    new #3; //class StringBuilder   6:    dup   7:    invokespecial #4; //StringBuilder."<init>":()   10:   ldc #5; // String abc   12    invokevirtual #6; //StringBuilder.append:(String)   15    aload_1   16    invokevirtual #6; //StringBuilder.append:(String)   19    ldc #7; //String def   21    invokevirtual #6; //StringBuilder.append:(String)   24    bipush 47   26    invokevirtual #8; //StringBuilder.append:(I)   29    invokevirtual #9; //StringBuilder.toString:()   32    astore_2   33    getstatic #10; //Field System.out:PrintStream;   36    aload_2   37    invokevirtual #11; // PrintStream.println:(String)   40    return

line 7 12 16 21 26 29我们可以看到 通过invokevirtual命令,编译器调用了JVM中的StringBuilder这个类,但是我们的代码中并没有使用这个类,但是编译器决定这么做,应为StringBuilder的效率更高。


我们再将实验代码换成StringBuilder实现:

//: strings/WhitherStringBuilder.java
public class WhitherStringBuilder {  public String implicit(String[] fields) {
    String result = "";    for(int i = 0; i < fields.length; i++)
      result += fields[i];    return result;
  }  public String explicit(String[] fields) {
    StringBuilder result = new StringBuilder();    for(int i = 0; i < fields.length; i++)
      result.append(fields[i]);    return result.toString();

}
} ///:~ 


我们使用Javap -c WithStringBuilder 我们可以比较两个方法的不同之处:

第一个是使用+运算符的。

public java.lang.String implicit(java.lang.String[]);  Code:
   0:    ldc #2; //String   2:    astore_2   3:    iconst_0   4:    istore_3
   5:    iload_3   6:    aload_1   7:    arraylength   8:    if_icmpge 38   11:   new #3; //class StringBuilder   14:   dup   15:   invokespecial #4; // StringBuilder.”<init>”:()   18:   aload_2   19:   invokevirtual #5; // StringBuilder.append:()   22:   aload_1   23    iload_3   24    aaload   25:   invokevirtual #5; // StringBuilder.append:()   28:   invokevirtual #6; // StringBuiIder.toString:()   31:   astore_2   32:   iinc 3, 1   35:   goto 5   38:   aload_2   39    areturn

接下来是使用StringBuilder的:

public java.lang.String explicit(java.lang.String[]);  Code:
   0:    new #3; //class StringBuilder   3:    dup   4:    invokespecial #4; // StringBuilder.”<init>”:()   7:    astore_2   8:    iconst_0   9:    istore_3   10:   iload_3   11:   aload_1   12:   arraylength   13:   if_icmpge 30   16:   aload_2   17:   aload_1   18:   iload_3   19:   aaload   20    invokevirtual #5; // StringBuilder.append:()   23    pop   24:   iinc 3,1   27:   goto 10   30:   aload_2   31:   invokevirtual #6; // StringBuiIder.toString:()   34:   areturn

可以看到第二个方法,JVM以及编译器会提升很多效率。

在@tianping168博主的文章:http://blog.csdn.net/tianping168/article/details/2458103 中有对于Java各个String链接方式的性能测试。大家有兴趣的可以去看一看。


最后贴一下这道题使用StringBuilder的方法:


/** * Definition for a binary tree node. * public class TreeNode { *     int val; *     TreeNode left; *     TreeNode right; *     TreeNode(int x) { val = x; } * } */public class Solution {    public List<String> binaryTreePaths(TreeNode root) {        List<String> Result = new ArrayList();                        if (root == null){            return Result;        }        StringBuilder temp = new StringBuilder();        minHelper(root,temp,Result);        return Result;    }        private void minHelper(TreeNode  root,                           StringBuilder temp,                           List<String> Result){                if(root == null){            return;         }                temp.append(String.valueOf(root.val));        int length = temp.length();        if(root.left == null && root.right == null){           Result.add(temp.toString());           return;        }                       if(root.left != null){           minHelper(root.left,temp.append("->"),Result);           temp.delete(length,temp.length());       }       if(root.right != null){           minHelper(root.right,temp.append("->"),Result);           temp.delete(length,temp.length());       }                    }}

贴个测试时间图 哈哈哈



0 0
原创粉丝点击