2013-07-18 95 views
0

請耐心等待。我已經一年多沒有編程了,而且我正在通過做「家庭作業問題」來回顧我的Java求職面試。我的函數應該返回一個包含給定字符串中每個第二個字符的字符串。有沒有一個尷尬的方式來做到這一點?有沒有更好的方法來遍歷java中的字符串?

public String stringBits(String str) { 
    StringBuffer tmp = new StringBuffer(); 
    for(int i = 0; i<str.length(); i+=2) 
    tmp.append(str.charAt(i)); 
    String ret = new String(tmp); 
    return ret; 
+1

是你應該包括第一個字符?只有跳出來的修正是你應該'返回tmp.toString()'而不是'new String(tmp)',並且使用'StringBuilder'而不是'StringBuffer'。 –

+0

謝謝。你能解釋爲什麼使用StringBuilder是一個更好的主意嗎? – Yitzchak

+1

'StringBuffer'是同步的,而'StringBuilder'不是,所以對於單線程代碼,使用StringBuilder更有效率。實際上,現在使用StringBuilder幾乎總是比較好,因爲您很少在線程之間共享這樣的類的實例。 –

回答

0

你在做什麼,盡我所知。這裏有一個簡單的測試用例:

package com.sandbox; 

import org.junit.Test; 

import static org.junit.Assert.assertEquals; 

public class SandboxTest { 

    @Test 
    public void testMocking() { 
     assertEquals("foo", stringBits("f1o2o3")); 
    } 

    public String stringBits(String str) { 
     StringBuffer tmp = new StringBuffer(); 
     for (int i = 0; i < str.length(); i += 2) { 
      tmp.append(str.charAt(i)); 
     } 
     String ret = new String(tmp); 
     return ret; 
    } 
} 

我認爲這是一個非常簡單的方法。有一種方法可以用正則表達式和一個組來完成,但我有一種感覺,你現在的代碼會更容易閱讀。


我從來沒有聽說過的StringCharacterIterator的,直到我看到@喬伊的答案,但它看起來像一個有趣的解決方案。下面是使用他的答案代碼:

package com.sandbox; 

import org.junit.Test; 

import java.text.CharacterIterator; 
import java.text.StringCharacterIterator; 

import static org.junit.Assert.assertEquals; 

public class SandboxTest { 

    @Test 
    public void testMocking() { 
     assertEquals("foo", stringBits("f1o2o3")); 
    } 

    public String stringBits(String str) { 
     StringBuilder buf = new StringBuilder(); 
     StringCharacterIterator iterator = new StringCharacterIterator(str); 
     for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) { 
      buf.append(c); 
      iterator.next(); 
     } 
     return buf.toString(); 
    } 
} 
0

不,這根本不笨拙。對於每一個有用的任務,可能有更合適的方法,但在這種情況下,你別無選擇,只能遍歷字符串。

0

我相信這也應該起作用,而且看起來更簡單。

public String stringBits(String str) { 
    String tmp = ""; 
    for(int i = 0; i<str.length(); i+=2) 
     tmp+=str.charAt(i); 
    return tmp; 

我編輯說,如果你想要第二,第四,六,...字符,我應該等於1。

+1

使用StringBuffer/StringBuilder比使用String連接要好得多,因爲使用+ =和一個String會生成很多不必要的inbetween對象,對於大型字符串來說效率非常低。不會倒退,但這不是一個特別好的解決方案。 –

+0

總是很好學習新東西。謝謝。 – Bobbick

0

你可以把串入一個CharArray並使用for-each循環:

for (char c: str.toCharArray()){ 
} 

當然,你可能會需要一個櫃檯或以獲得所有其他角色的標誌,所以它可能不難尷尬。

3

我會用StringBuilder,不StringBufferStringBuffer適用於多線程情況,因此它比StringBuilder慢,因爲它不同步。我在這個線程中測試了通過各種答案列出的四種基本方法。 但是,請注意,我總是在這裏做某些事情;這些應該是你的面試官真正需要的東西:

  • 我從來沒有使用String += nextCharacter;,因爲它是多,比使用StringBuilder慢得多。
  • 我設置了initialCapacity,因爲這樣做總是比較快。如果你不這樣做,如果StringBuilder變滿,它必須重新分配一個新陣列並複製,這很慢。

,代碼:

import com.google.caliper.Runner; 
import com.google.caliper.SimpleBenchmark; 

import java.text.CharacterIterator; 
import java.text.StringCharacterIterator; 
import java.util.Random; 

public class EveryOtherTest { 
    public static class StringBenchmark extends SimpleBenchmark { 
     private String input; 

     protected void setUp() { 
      Random r = new Random(); 
      int length = r.nextInt(1000) + 1000; 
      StringBuilder sb = new StringBuilder(); 
      for (int i = 0; i < length; i++) { 
       sb.append((char) ('A' + r.nextInt(26))); 
      } 
      input = sb.toString(); 
     } 

     public String timeCharArrayForeach(int reps) { 
      String output = ""; 
      Random r = new Random(); 
      for (int i = 0; i < reps; i++) { 
       StringBuilder sb = new StringBuilder(input.length()/2 + 1); 
       boolean use = false; 
       for (char c : input.toCharArray()) { 
        if(use) sb.append(c); 
        use = !use; 
       } 
       String newOutput = sb.toString(); 
       if (r.nextBoolean()) output = newOutput; // Trick the JIT 
      } 

      return output; 
     } 

     public String timeCharArrayPlusTwo(int reps) { 
      String output = ""; 
      Random r = new Random(); 
      for (int i = 0; i < reps; i++) { 
       StringBuilder sb = new StringBuilder(input.length()/2 + 1); 
       char[] charArray = input.toCharArray(); 
       for(int j = 0; j < input.length(); j += 2) { 
        sb.append(charArray[j]); 
       } 
       String newOutput = sb.toString(); 
       if (r.nextBoolean()) output = newOutput; // Trick the JIT 
      } 

      return output; 
     } 

     public String timeCharAt(int reps) { 
      String output = ""; 
      Random r = new Random(); 
      for (int i = 0; i < reps; i++) { 
       StringBuilder tmp = new StringBuilder(input.length()/2 + 1); 
       for (int j = 0; j < input.length(); j += 2) { 
        tmp.append(input.charAt(j)); 
       } 
       String newOutput = tmp.toString(); 
       if (r.nextBoolean()) output = newOutput; // Trick the JIT 
      } 

      return output; 
     } 

     public String timeIterator(int reps) { 
      String output = ""; 
      Random r = new Random(); 
      for(int i = 0; i < reps; i++) { 
       StringBuilder buf = new StringBuilder(input.length()/2 + 1); 
       StringCharacterIterator iterator = new StringCharacterIterator(input); 
       for (char c = iterator.first(); c != CharacterIterator.DONE; c = iterator.next()) { 
        buf.append(c); 
        iterator.next(); 
       } 
       String newOutput = buf.toString(); 
       if (r.nextBoolean()) output = newOutput; // Trick the JIT 
      } 

      return output; 
     } 

     public String timeRegex(int reps) { 
      String output = ""; 
      Random r = new Random(); 
      for(int i = 0; i < reps; i++) { 
       String newOutput = input.replaceAll("(?<!^).(.)", "$1"); 
       if (r.nextBoolean()) output = newOutput; // Trick the JIT 
      } 

      return output; 
     } 
    } 

    public static void main(String... args) { 
     Runner.main(StringBenchmark.class, args); 
    } 
} 

結果:

0% Scenario{vm=java, trial=0, benchmark=CharArrayForeach} 2805.55 ns; ?=688.96 ns @ 10 trials 
20% Scenario{vm=java, trial=0, benchmark=CharArrayPlusTwo} 3428.48 ns; ?=475.32 ns @ 10 trials 
40% Scenario{vm=java, trial=0, benchmark=CharAt} 2138.68 ns; ?=379.44 ns @ 10 trials 
60% Scenario{vm=java, trial=0, benchmark=Iterator} 3963.94 ns; ?=389.53 ns @ 10 trials 
80% Scenario{vm=java, trial=0, benchmark=Regex} 58743.66 ns; ?=10850.33 ns @ 10 trials 

     benchmark us linear runtime 
CharArrayForeach 2.81 = 
CharArrayPlusTwo 3.43 = 
      CharAt 2.14 = 
     Iterator 3.96 == 
      Regex 58.74 ============================== 

vm: java 
trial: 0 
+0

CharArray和CharAt有這樣的區別,這讓人頗爲意外。如果你使用循環索引即char [] ca = input.toCharArray(),那麼CharArray的時間是多少? for(int i = 0; ... i + = 2)'而不是'for(char c:input.toCharArray())'? –

+0

@ c.s。我不確定,但我預計它會非常相似。我認爲原因是'.toCharArray()'必須創建一個數組副本(因爲'字符串是不可變的,它不能只提供底層數組),'charAt'不會。 – durron597

+0

您能否按照我的建議修改您的測試並重新檢查?就像現在一樣,測試不是等值的。在CharArray中,'for-loop'隱式使用'Iteratable',這就是爲什麼結果與'Iterator'類似的原因。如果使用索引訪問數組並使用'i + = 2',則只能訪問陣列的n/2個元素,並且我認爲它類似於CharAt情況 –

1

你可以使用這個表達式相當於

String newString = str.replaceAll("(?<!^).(.)", "$1"); 
+0

核選項。 –

+0

也是最慢的。看到我的回答:) – durron597

相關問題