一道淘汰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("
");
	}

	private void putBuffer(int i, String s) {
		sBuffer.append(i);
		sBuffer.append(s);
		sBuffer.append("
");
	}

}

程序运行时间:

/*
* 耗时: 
* 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某工程师

原文地址:https://www.cnblogs.com/aikongmeng/p/3697295.html