一道淘汰85%面试者的百度开发者面试题参考答案
/**
* 百度面试题 http://student.csdn.net/mcd/topic/235300/753730
* 依序遍历0到100闭区间内所有的正整数,如果该数字能被3整除,则输出该数字及‘*’标记;如果该数字能被5整除,则输出该数字及‘#’标记;
* 如果该数字既能被3整除又能被5整除,则输出该数字及‘*#’标记。
*/
对算法没有什么研究, 只是觉得好的算法能给程序带来更快的速度, 所以我下面代码的重点不是算法,而是哪个运行耗时最少:
public class Test { StringBuffer sBuffer; StringBuilder sBuilder; public static void main(String[] args) { long start = System.nanoTime(); foo(); long end = System.nanoTime(); System.out.println("--------1-------"); long start1 = System.nanoTime(); Test test = new Test(); test.sBuffer = new StringBuffer(); test.foo1(); System.out.println(test.sBuffer); long end1 = System.nanoTime(); System.out.println("--------2-------"); long start2 = System.nanoTime(); Test test2 = new Test(); test2.sBuilder = new StringBuilder(); test2.foo2(); System.out.println(test2.sBuilder); long end2 = System.nanoTime(); System.out.println("--------3-------"); long start3 = System.nanoTime(); new Test().foo3(); long end3 = System.nanoTime(); System.out.println("--------4-------"); long start4 = System.nanoTime(); Test test4 = new Test(); test4.sBuilder = new StringBuilder(); test4.foo4(); System.out.println(test4.sBuilder); long end4 = System.nanoTime(); long start5 = System.nanoTime(); Test test5 = new Test(); test5.sBuilder = new StringBuilder(); test5.foo5(); System.out.println(test5.sBuilder); long end5 = System.nanoTime(); System.out.println(end - start); System.out.println(end1 - start1); System.out.println(end2 - start2); System.out.println(end3 - start3); System.out.println(end4 - start4); System.out.println(end5 - start5); } /** * 方法一:直接使用+ 拼接 * * @author Administrator * @date 2014年4月24日 */ private static void foo() { for (int i = 1; i <= 100; i++) { if (i % 3 == 0 && i % 5 == 0) { System.out.println(i + "*#"); } else if (i % 5 == 0) { System.out.println(i + "#"); } else if (i % 3 == 0) { System.out.println(i + "*"); } } } /** * 方法二:采用StringBuffer * * @author Administrator * @date 2014年4月24日 */ private void foo1() { for (int i = 1; i <= 100; i++) { if (i % 3 == 0 && i % 5 == 0) { putBuffer(i, "*#"); } else if (i % 5 == 0) { putBuffer(i, "#"); } else if (i % 3 == 0) { putBuffer(i, "*"); } } } /** * 方法三:采用StringBuilder * * @author Administrator * @date 2014年4月24日 */ private void foo2() { for (int i = 1; i <= 100; i++) { if (i % 3 == 0 && i % 5 == 0) { putBuilder(i, "*#"); } else if (i % 5 == 0) { putBuilder(i, "#"); } else if (i % 3 == 0) { putBuilder(i, "*"); } } } /** * 网友参考答案 */ private void foo3() { final int COUNT = 100; // 为什么是final , 使用final的好处是什么? boolean isMod3; boolean isMod5; for (int i = 1; i <= COUNT; i++) { isMod3 = i % 3 == 0; isMod5 = i % 5 == 0; if (isMod3 && isMod5) { System.out.println(i + " *#"); } else if (isMod3) { System.out.println(i + " *"); } else if (isMod5) { System.out.println(i + " #"); } } } /** * 更改参考答案 */ private void foo4() { final int COUNT = 100; // 为什么是final , 使用final的好处是什么? boolean isMod3; boolean isMod5; for (int i = 1; i <= COUNT; i++) { isMod3 = i % 3 == 0; isMod5 = i % 5 == 0; if (isMod3 && isMod5) { putBuilder(i, "*#"); } else if (isMod3) { putBuilder(i, "*"); } else if (isMod5) { putBuilder(i, "#"); } } } /** * 更改网友答案 */ private void foo5() { int COUNT = 100; // 为什么是final , 使用final的好处是什么? boolean isMod3; boolean isMod5; for (int i = 1; i <= COUNT; i++) { isMod3 = i % 3 == 0; // isMod3 = (i%3==0) isMod5 = i % 5 == 0; if (isMod3 && isMod5) { putBuilder(i, "*#"); } else if (isMod3) { putBuilder(i, "*"); } else if (isMod5) { putBuilder(i, "#"); } } } /** * 添加符合要求的数字和所对应的字符 * * @param i * 数字 * @param s * 字符 * @author Administrator * @date 2014年4月24日 */ private void putBuilder(int i, String s) { sBuilder.append(i); sBuilder.append(s); sBuilder.append("\n"); } private void putBuffer(int i, String s) { sBuffer.append(i); sBuffer.append(s); sBuffer.append("\n"); } }
程序运行时间:
/*
* 耗时:
* 1211687 直接拼接
* 153947 StringBuffer
* 103593 StringBuilder
* 1105859 参考
* 131818 改参考后
* 108725 不加final
*/
单看,100次循环的耗时, 可以看出 , StringBuilder 耗时是最少, 加final的反而耗时更多.
将循环次数, 该为100000,多次运行后各个方法所耗时为:
// 291248482 // 27186869 // 37310223 // 238034804 // 57009133 // 135859617 // 291248482 //直接 // 27186869 //StringBuffer // 37310223 //StringBuilder // 238034804 //.. // 57009133 //StringBuilder+..+final // 135859617 //StringBuilder+ .. // 289988355 // 94520451 // 37578349 // 203889493 // 48452840 // 133518969 // 294954135 // 27723121 // 143139427 // 272538045 // 67523450 // 135150816 // 280107789 // 20859612 // 135050429 // 314615520 // 47390279 // 137197360 // 294913403 // 37562313 // 133788698 // 286650573 // 55538290 // 138061072
...
可以得出:
StringBuffer 和StringBuilder 耗时比较少, 由于StringBuilder是线程不安全的,理论上是要比Stringbuffer更快;
使用+ 拼接的是特别耗时的, final 在循环次数增多以后,其对于不加final来说,效果是明显的.
同样,采用直接拼接字符, 没优化算法之前的方法一要比优化算法后的方法四耗时明显.
相关权威理论,可以从<<Java编程思想>>P506 Stirng vs StringBuffer获得
PS :
性能优化无末日, 我们能做的很多 -- Tx某工程师