Kri*_*ran 30 java algorithm hash dictionary hashmap
我从面试中得到了以下问题.
我得到了一个像这样的字符数组:
char[] characters = {'u', 'a', 'u', 'i', 'o', 'f', 'u'};
Run Code Online (Sandbox Code Playgroud)
我需要获得每个角色的不同角色和数量:
u = 3
a = 1
i = 1
o = 1
f = 1
Run Code Online (Sandbox Code Playgroud)
所以我用Java回答了以下代码:
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int i = 1;
for (char c : characters) {
if (map.containsKey(c)) {
int val = map.get(c);
map.put(c, ++val);
} else map.put(c, i);
}
Run Code Online (Sandbox Code Playgroud)
面试官是一名解决方案架构师.他问我为什么,我同时使用containsKey()和get()方法,在这里,并指出这是多余的使用这两种方法.他的观点是什么?我在这做错了什么?我的代码会导致性能问题等吗?
Tob*_*fke 25
架构师意味着get并且containsKey具有相同的成本并且可以累积到一个支票中:
Integer val = map.get(c);
if (val != null) {
...
} else {
...
}
Run Code Online (Sandbox Code Playgroud)
但我想知道为什么建筑师只关心这一点,因为有更多的事情需要改进:
AtomicInteger(或任何其他可修改的数字类)而不是Integer您甚至可以将get与其中一个put合并因此,从我的观点来看,使用HashMap时的最佳性能将提供:
Map<Character, AtomicInteger> map = new HashMap<>();
for (Character c : characters) {
AtomicInteger val = map.get(c);
if (val != null) {
val.incrementAndGet();
} else {
map.put(c, new AtomicInteger(1));
}
}
Run Code Online (Sandbox Code Playgroud)
如果字符的范围很小(并且事先已知),则可以使用int数组进行计数.这将是所有可能解决方案中最快的:
char firstCharacter = 'a';
char lastCharacter = 'z';
int[] frequency = new int[lastCharacter - firstCharacter + 1];
for (char c : characters) {
frequency[c - firstCharacter]++;
}
Run Code Online (Sandbox Code Playgroud)
Era*_*ran 18
你的代码是多余的,因为get和containsKey做了几乎相同的工作.您可以检查get是否返回null值,而不是调用containsKey.
代码可以简化为:
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
for (char c : characters) {
Integer val = map.get(c);
if (val == null)
val = 0;
map.put(c,++val);
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样写你的for循环 -
for (char c : characters) {
Integer val = map.get(c);
if (null != val){
map.put(c, ++val);
} else {
map.put(c, 1);
}
}
Run Code Online (Sandbox Code Playgroud)
注意:我已修改int为Integer以便我可以检查它null如果地图已经包含一个值,那么它将返回该值,它将与您声明的Integer变量一起分配val.否则val就会null.所以我认为你不需要使用Map.containsKey()方法.
让我们从您的代码开始,然后开始减少它.
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int i = 1;
for (char c : characters)
{
if (map.containsKey(c))
{
int val = map.get(c);
map.put(c, ++val);
}
else map.put(c, i);
}
Run Code Online (Sandbox Code Playgroud)
我要做的第一件事是使用Java 7菱形运算符,并删除变量 i
Map<Character, Integer> map = new HashMap<>();
for (char c : characters)
{
if (map.containsKey(c))
map.put(c, ++map.get(c));
else
map.put(c, 1);
}
Run Code Online (Sandbox Code Playgroud)
这是我的第一步,我们删除了变量,i因为它始终是常量,1并且在执行期间不会更改.我也简化了声明,并map.get打电话map.put给我.现在,在看到时,我们有三次调用map方法.
Map<Character, Integer> map = new HashMap<>();
for (char c : characters)
{
Integer i = map.get(c);
if (i == null) i = 0;
map.put(c, ++i);
}
Run Code Online (Sandbox Code Playgroud)
这是最好的方式,也是@Eran在上面的回答中所说的.希望这种细分有所帮助
for (char c : characters) {
Integer val = map.get(c);
if(val != null){
map.put(c, ++val);
}else{
map.put(c, 1);
}
}
Run Code Online (Sandbox Code Playgroud)
这可能是最好的方式
函数get和contains都做同样的工作......
而不是通过使用get函数同时使用它的好处
使用get函数时,请在此处检查null值.通过避免两次调用,它将改善性能.
注意:在这种情况下,可能看起来性能没有任何改善,但在另一种情况下,它会有大量的数据.
从Java 8开始,您甚至可以执行以下操作:
final Map<Character, Integer> map = new HashMap<>();
for (char c : characters)
map.merge(c, 1, Integer::sum);
Run Code Online (Sandbox Code Playgroud)
请注意,您使用此解决方案进行了大量的装箱和拆箱.这应该不是问题,但要注意它是很好的.
上面的代码实际上做了什么(即手动装箱和拆箱):
for (char c : characters)
map.merge(
Character.valueOf(c),
Integer.valueOf(1),
(a, b) -> Integer.valueOf(Integer.sum(a.intValue(), b.intValue())));
Run Code Online (Sandbox Code Playgroud)