给定一个字符串数组,找到特定字符的出现频率。
例如。给定数组{“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 :(得分:3)
对不起,我认为方法2减慢了速度。为了将每个字符串添加到HashMap
,该方法计算哈希码,该哈希码查看字符串中的每个字符。因此,设置HashMap
已经查看了每个字符串中的每个字符,这与您使用方法1所需的时间一样长,然后您必须再次通过地图。
答案 1 :(得分:2)
方法1在这里是优选的。在最坏的情况下,其中任何一个的成本都是O(N)
。使用HashMap<String>
来记住旧的访问字符串(具有固有的散列成本)的第二种方法不会带来值得提及的性能改进。我们应该避免过早优化,因为approach 1
更简单。
答案 2 :(得分:2)
方法2不是很优化,你应该做的是创建一个Map<Character,Integer>
,然后你不需要计算第二个循环,但是你需要循环每个字符串中的每个字符。
方法1,取决于你的实现也只计算字符串中出现的每个字符,它是否考虑字符是否出现两次,例如"hash"
?
这两种方法都需要比较 EACH 字符串中的 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),来自docs for HashMap
此实现为基本操作(get和put)提供了恒定时间性能
但是,即使使用我上面提供的方法,在填充地图时也需要额外的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;
}
答案 3 :(得分:1)
不一定。 另一种可能性是将数组“扁平”为单个字符串并在其中搜索单个字符(快速与变体1相同)。这可能会加速思考一下,但这并不一定会使代码“更好”。可以在此SO answer中找到字符串中字符搜索的示例。
答案 4 :(得分:1)
不,只有一次搜索,你永远不会比O(n)做得更好。但是,如果你要针对同一个数组多次搜索,对于不同的字符,你可以首先运行数组并从每个字符构建一个哈希映射到它的出现次数。然后,对于每次搜索,您只需要进行简单的恒定时间查找,而不是O(n)搜索。
答案 5 :(得分:1)
Hashmap比第一个慢得多。两种算法都需要从每个字符传递一次,因此两者都需要O(n)时间。但第一个更简单,并且将执行更少的代码行。
不错的尝试:)