别说话,快上题!
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
*///:~
javap -c Concatenation
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.youkuaiyun.com/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());
}
}
}
贴个测试时间图 哈哈哈