2016-05-04 62 views
0

最具性能友好的方法我在做this FizzBuzz exercise on CodingBat;解決FizzBu​​zz

給定一個字符串str,如果字符串以「f」開頭返回「Fizz」。如果字符串以「b」結尾,則返回「Buzz」。如果「f」和「b」條件都爲真,則返回「FizzBu​​zz」。在所有其他情況下,請不變地返回字符串。

想出了這個答案;

public String fizzString(String str) 
{ 
    String sum = ""; 

    if (str.startsWith("f")) sum += "Fizz"; 
    if (str.endsWith("b")) sum += "Buzz"; 

    return (sum == "") ? str : sum; 
} 

然而,問題的作者去了;

public String fizzString(String str) 
{ 
    if (str.startsWith("f") && str.endsWith("b")) return "FizzBuzz"; 
    if (str.startsWith("f")) return "Fizz"; 
    if (str.endsWith("b")) return "Buzz"; 

    return str; 
} 

這似乎太冗餘...

我想知道,它將使在現實世界上的差異,表現明智的,去的第一個程序而不是第二個?

+4

第二個更快。儘管如此,我認爲FizzBu​​zz在現實世界中的表現並不重要。 – erickson

+0

在現實世界中?可能不會。在一個挑剔的世界裏,這兩種方法都存在權衡。第一種方法使用'串聯',這可能是[臭名昭着的緩慢](http://stackoverflow.com/q/1532461/758280)。第二種方法使用比第一種更多的條件。 – Jeffrey

+0

在解決方案#2的最壞情況下,字符串串聯不值得進行額外的條件檢查。您可能需要爲字符串串聯分配更多的內存,這比檢查布爾條件要慢得多 –

回答

0

我的計算告訴否則......(註釋部分得到了太擁擠了。)

我將盡可能快地運行的代碼塊的時間設定金額的Java程序(1000毫秒) 。它將這樣做10次以獲得平均值,最小值和最大值。

我得說,第一種方法出來更快,平均每秒大約4,000,000循環。

這裏是我的結果:

First Method: 
Least loops: 26,312,768 
Most loops: 26,918,157 
Average loops: 26,582,653.7 

    Second Method: 
Least loops: 22,039,592 
Most loops: 22,596,476 
Average loops: 22,424,598.5 

這裏的源代碼我有,請告訴我的方式,我得到了數據可能已被扭曲。我保持我的電腦常數不變,我保持代碼不變。唯一改變的是我在while循環中調用的內容。

package personal; 
 

 
import java.util.ArrayList; 
 
import java.util.Arrays; 
 
import java.util.Collections; 
 
import java.util.List; 
 

 
public class SpeedTest { 
 

 
    public static void main(String[] args) { 
 
    int loops = 10; 
 
    double DELAY = 1000; 
 
    int i; 
 
    double[] loopCount = new double[loops + 1]; 
 
    double sum = 0; 
 
    for (i = 0; i < loops + 1; i++) { 
 

 
     long startTime = System.currentTimeMillis(); 
 
     long endTime = (long)(startTime + DELAY); 
 
     long index = 0; 
 

 
     while (true) { 
 
     fizzString("TEST"); 
 
     //fizzString2("TEST"); 
 
     long now = System.currentTimeMillis(); 
 
     if (now >= endTime) { 
 
      break; 
 
     } 
 
     index++; 
 
     } 
 

 
     if (i != 0) { 
 
     if (DELAY != 1000) { 
 
      if (DELAY/1000 % 1 == 0) { 
 
      System.out.printf("Test %.0f. %,.0f loops in %.0f seconds.\n", (float) i, (float) index, (float) DELAY/1000); 
 
      } else if ((DELAY/100) % 1 == 0) { 
 
      System.out.printf("Test %.0f. %,.0f loops in %.1f seconds.\n", (float) i, (float) index, (float) DELAY/1000); 
 
      } else if ((DELAY/10) % 1 == 0) { 
 
      System.out.printf("Test %.0f. %,.0f loops in %.2f seconds.\n", (float) i, (float) index, (float) DELAY/1000); 
 
      } else if (DELAY % 1 == 0) { 
 
      System.out.printf("Test %.0f. %,.0f loops in %.3f seconds.\n", (float) i, (float) index, (float) DELAY/1000); 
 
      } 
 
     } else { 
 
      System.out.printf("Test %.0f. %,.0f loops in %.0f second.\n", (float) i, (float) index, (float) DELAY/1000); 
 
     } 
 
     loopCount[i] = index; 
 
     } 
 
    } 
 
    Arrays.sort(loopCount); 
 
    System.out.printf("Least loops: %,.0f\n", (loopCount[1])); 
 
    System.out.printf("Most loops: %,.0f\n", loopCount[loops]); 
 

 
    for (int d = 1; d < loopCount.length; d++) { 
 
     sum += loopCount[d]; 
 
    } 
 
    double averageLoopCount = 1.0f * sum/(loopCount.length - 1); 
 
    System.out.printf("Average loops: %,.1f", averageLoopCount); 
 
    } 
 

 
    public static String fizzString(String str) { 
 
    if (str.startsWith("f") && str.endsWith("b")) return "FizzBuzz"; 
 
    if (str.startsWith("f")) return "Fizz"; 
 
    if (str.endsWith("b")) return "Buzz"; 
 

 
    return str; 
 
    } 
 

 
    public static String fizzString2(String str) { 
 
    String sum = ""; 
 

 
    if (str.startsWith("f")) sum += "Fizz"; 
 
    if (str.endsWith("b")) sum += "Buzz"; 
 

 
    return (sum == "") ? str : sum; 
 
    } 
 
}

嘗試爲自己:)

+0

我只是一遍又一遍,你說得對,速度更快......我不明白,爲什麼其他人說解決方案#2是最快的呢? – CaffeinatedSynapse

+0

@CoffeeAddict真正的原因:我不知道;我可以說的是:*在這裏插入「theory vs practice」的報價* – Kaelinator

+4

首先,這個基準測試使用TEST作爲一個字符串,它消除了第一種方法的字符串結構,因爲它不是以f開頭,也不以b結尾。其次,它忽略了結果,它允許Hotspot完全避免對fizzbuzz的調用。第三,它使用System.currentTimeMillis(),並在每次迭代中調用它,所以這可能是大部分時間花在哪裏。在Java中編寫微基準測試很困難。閱讀http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java –

0

這真的取決於中得到執行的實際CPU指令,

但總的想法是有

  • 執行分支數最少(if-else)
  • 最少的內存訪問次數
  • 沒有動態分配。

像這樣的東西應該比兩個建議的解決方案都要快。

public String fizzString(String str) 
{ 
    if (str.length() == 0) return str; 

    if (str.charAt(0) == 'f') { 
     if (str.charAt(str.length() - 1) == 'b') { 
      return "FizzBuzz"; 
     } 
     return "Fizz"; 
    } 
    if (str.charAt(str.length() - 1) == 'b') { 
     return "Buzz"; 
    } 
    return str; 
} 
相關問題