2013-10-16 63 views
2

給定一個字符串數組,找出特定字符出現的頻率。查找字符串數組中字符的頻率

例如。給定數組{「hon」,「bhig」,「zzz」,「hello」}和字符'h',輸出爲3.

以下是我如何解決它: 方法1:遍歷數組,每當該字符出現在當前字符串中時遞增計數器。運行時間是O(n),其中n是數組中所有字符串的累積長度。

方法2:這可以使用HashMap進行優化;如果字符串在數組中重複,這特別有用。以下是我所做的:使用HashMap,其中key = string,value =數組中出現字符串的次數。將給定數組中的所有字符串連同其計數一起放入HashMap中。然後迭代HashMap中的每個鍵值對,計算給定字符出現在鍵(字符串)中的次數,並將其增加HashMap中相應的值。

我的問題是:有沒有更好的方法來做到這一點?

下面的代碼:

注意:請閱讀全文,接受的答案。

public static int findFreq(String[] arr,char c) { 
    Map<String,Integer> map = new HashMap<String,Integer>(); 
    for(int i=0;i<arr.length;i++) { 
     if(map.containsKey(arr[i])) 
      map.put(arr[i],map.get(arr[i])+1); 
     else 
      map.put(arr[i], 1); 
    } 
    int freq=0; 
    for(Entry<String,Integer> entr:map.entrySet()) { 
     String s = entr.getKey(); 
     for(int i=0;i<s.length();i++) { 
      if(s.charAt(i)==c) 
       freq += entr.getValue(); 
     } 
    } 
    return freq; 
} 
+0

看到,因爲你將不得不看每個人字符數組來解決這個問題,你永遠不會比O(N)做的更好。我沒有看到如何通過字符串來繪製地圖是有幫助的(事實上,如果你再也不會看到'arr',那麼你不需要地圖)。如果你想保留它,我會從字母表中的每個字母映射到它出現的次數(即'h - > 3')。 –

+1

計算字符串的哈希碼需要查看每個字母。當然,哈希碼可能已經被計算過一次(因此被緩存),第二種方法可能會有更多的工作,並且(平均而言)不能少工作。只有在字符串數量顯着多於1的情況下才有節省。 –

回答

2

方法2並不是非常優化,你真正應該做的是創建一個Map<Character,Integer>然後你不需要第二個循環來計數,但是你需要循環每個字符串中的每個字符。

方法1,根據您的實現也只計算字符串中出現的每個字符,它是否考慮如果字符出現兩次,例如"hash"

兩種方法都需要比較EACH角色中的每個字符串再算上

這是方法2應該如何

public static int findFreq(String[] arr,char c) { 
    Map<Character,Integer> map = new HashMap<Character,Integer>(); 
    for(int i=0;i<arr.length;i++) { 
     for(Character ch : arr[i].toCharArray()){ 
      if(map.containsKey(ch)) 
       map.put(ch,map.get(ch)+1); 
      else 
       map.put(ch, 1); 
     } 
    } 
    return map.get(Character.valueOf(c)); 
} 

無論哪種方式,這兩種方法將是爲O(n), from docs for HashMap

此實現提供了恆定時間性能基本操作(獲取和放入)

但即使採用我上面提供的方法,在填充地圖時還需要額外的get

所以方法1是更好,如果使用單個搜索,如果用反覆則接近2要走的路(但填充的方法外地圖)

一些指標可供您:

Number of Words | Array (approach 1) | Map (My approach 2) | Map (your approach 2) 
       |  (time in ms)  |  (time in ms)  |  (time in ms) 
       |  (groovy)/(java)  |  (groovy)/(java) |  (groovy)/(java)  
------------------------------------------------------------------------------------------- 
     43303  |   118/5  |   229/34  |   /16  
    417221  |   852/10  |  1088/120  |   /49 
    2086705  |  2929/45  |  5064/731  |   /219 

我收回我的方法,看起來你的Map方法更快!

這是我的陣列方法(如果你的不同)

private static int findFreqArray(String[] arr, char c){ 
    int count = 0; 
    for(int i=0;i<arr.length;i++) { 
     for(char ch : arr[i].toCharArray()){ 
      if(ch == c) 
       count++; 
     } 
    } 
    return count; 
} 
+0

非常感謝你的指標,這真的解決了我的一些疑問。是的,許多人認爲,方法1似乎是最快的。 – codewarrior

+0

是啊,看起來是爲什麼,我驚訝地發現你的地圖方法用2個循環更快,但現在我看它,在我的方法中調用'arr [i] .toCharArray()'可能會減慢它的速度 –

+0

也許更像是它映射每個字符,而數組方法(和你的地圖)只在字符匹配時映射。 –

1

不一定。 還有一種可能性是將你的數組「扁平化」爲一個單一的字符串並在其中搜索一個單獨的字符(與你的變體1一樣快)。這可能會讓速度稍微增加一點,但它不一定會使代碼「更好」。字符串中字符搜索的示例可以在SO answer中找到。

2

方法1在此優選。在最壞的情況下,他們中的任何一個的成本是O(N)。使用HashMap<String>來記憶舊訪問過的字符串(具有固有的散列成本)的第二種方法不會帶來值得提及的性能改進。我們應該避免過早優化,因爲approach 1更簡單

3

對不起,我認爲方法2減慢了速度。爲了將每個字符串添加到HashMap,該方法計算哈希代碼,該代碼查看字符串中的每個字符。因此,設置HashMap已經查看了每個字符串中的每個字符,這需要與方法1所需的時間相同,然後您必須再次通過地圖。

+0

如果字符串在數組中重複,則地圖只能提供節省。發佈的樣本數組OP根本沒有節省。 –

1

不,你永遠只是一個搜索做的比O(n)的更好。但是,如果您要針對同一個數組搜索多次,對於不同的字符,您可以先遍歷數組,然後從每個字符到其出現次數構建一個哈希映射。然後,對於每次搜索,您只需執行簡單的常量查找,而不是O(n)搜索。

1

哈希表比第一個更慢。兩種算法都需要從每個字符傳遞一次,所以都需要O(n)次。但第一個更簡單,將執行更少的代碼行。

不錯的嘗試雖然:)