今天上午刷到一道題,大體是寫一個方法判斷一個單詞中是否有重復的字母(或者說一個字符串中是否有重復的字符)。我的思路是一個字符一個字符地遍歷,如果發現有重復的停止:
1 function isIsogram(str) { 2 str = str.toLowerCase(); 3 4 for (var i = 0; i < str.length; i++) { 5 if (str.indexOf(str.charAt(i), i + 1) >= 0) { 6 return false; 7 } 8 } 9 10 return true; 11 }
這種簡單的場景下談性能沒什么意義,兩次循環速度並不慢( str.indexOf() 也認為是一次循環,但由於是native的行為,速度很快)。 后來我看到了別的用正則的實現,雖然很簡單,但一開始我確實沒住這方面想:
1 function isIsogram2(str) { 2 return !/(.).*\1/i.test(str); 3 }
或者:
function isIsogram2(str) { return !/^.*(.).*\1/i.test(str); }
這兩個其實沒什么區別,前者優先查找字符串尾端,后者優先查找字符串前端。這個正則比較好理解,不多解釋,比較讓我驚訝的這個匹配的性能。因為判斷一個字符串是否有重復字符這樣的任務太簡單,正因為太簡單,所以代表目標字符串的規律性太小。如果用正則必然帶來大量嘗試和回溯,其實主觀上會讓人覺得性能很不好。不過好不好不是隨便想一想就行的,還是要驗證一下。決定性能到底是好是壞,當然看最壞情況下,兩個算法的執行時間。構造這樣一個單詞: qwertyuiopas,沒有字母重復,意味着兩種算法都要跑完整的循環。
1 console.time("loop"); 2 for(var i=0; i<400000; i++){ 3 isIsogram("qwertyuiopas"); 4 } 5 console.timeEnd("loop"); 6 7 console.time("regexp"); 8 for(var i=0; i<400000; i++){ 9 isIsogram2("qwertyuiopas"); 10 } 11 console.timeEnd("regexp");
看看運行結果: amazing! 這個實驗證實了一個問題:javascript對正則確實有優化,使用正則的效率非常高。當然這句話也可以反過來理解,javascript中的字符串操作、循環太慢了。那么,對於正則還等什么呢,趕快用起來吧 轉載 周驊