用迭代器遍历HashMap时容易忽略的一个问题:getValue()方法的返回值类型

@Java: HashMap

HashMap遍历:getValue()方法的返回值类型

今天在做LeetCode的第242题:【有效的字母异位词】时碰到了一个问题关于Java的HashMap迭代器的问题。在这里把关于这个问题的心得写下来,好让更多的人可以避免这个问题。

解题思路

题目描述

我的思路是,用两个HashMap分别记录两个输入字符串中的出现的所有字母以及这些字母出现的次数。字符串s对应的HashMapsMap,字符串t对应的HashMaptMap。然后,用一个迭代器it去遍历sMap,每迭代一条记录,先判断tMap中是否包含key值相同(即针对同一个字符)的记录。如果没有,则说明s和t所含的字符不相同,两者不是字母异位词。如果有,则继续比较这条记录所对应的value值(即字符的出现次数)与tMap对应记录的value值是否相等。一旦不相等,就说明对应字符在st中的出现次数不相同,即说明两者不是字母异位词。我首先用以下语句建立了sMap的迭代器it,并用其进行迭代与判断:

 Iterator<Map.Entry<Character,Integer>> it=sMap.entrySet().iterator(); //创建迭代器it
 while(it.hasNext()){
	 Map.Entry ent=it.next();
	 if(!tMap.containsKey(ent.getKey()))
		 return false; //判断是否tMap中是否含有针对相同字符的记录
	 else if(tMap.get(ent.getKey())!=ent.getValue())
		 return false; //判断s和t中相同字符的出现次数是否相等
 }

从表面上看,这个代码没有任何逻辑上的问题。可在实际提交之后,系统却显示“解答错误”。系统所给的36个测试用例中,有35个顺利通过了测试,唯独只有一个测试用例运行后返回的是错误的结果。——原本应该返回“true”,但程序运行的结果却是“false”!

问题探索

起初,我以为是自己的算法思路存在漏洞,于是便在本地的Eclipse上进行调试。在调试代码的时候发生了一个小插曲——由于最后一个未能通过的测试用例太长,以至于无法直接复制粘贴到Eclipse中去。对于这个问题,我查阅了很多资料,还是未能得到解决。于是,我索性分别给这两个巨型字符串专门建立了两个.txt文档,通过读取文件的方式将这两个字符串的内容读进了程序中。这个内容我参考了另外一篇博客:Java 读取文本文件内容并转换成string。值得注意的是,我直接模仿这篇博客所写的代码在Eclipse上被报了错,经过一番探索才发现,在调用readLine()方法时,要用try-catch语句将对应的代码段包起来,这样系统就不会报错了。
必须像这样把调用readLine()方法的代码段包起来

Eclipse调试教程:Eclipse的单步调试
最后一个未通过的“巨无霸”测试用例(局部)
经过调试,我发现,上述代码经过第一轮循环,仅仅只遍历了sMap中的一个元素,执行完else if(tMap.get(ent.getKey())!=ent.getValue()) return false;这句代码之后返回了false,方法结束。可问题在于,经过我的检查,在程序跳出方法体的时候,it所遍历到的sMap中的字符的所对应的value值出现次数与相同字符在tMap中所记录的出现次数是一样的!在这种情况下,程序依旧无视tMap.get(ent.getKey())!=ent.getValue()这一判断条件,执行了这句代码后面对应的分支语句。这完全违背了该if分支的逻辑,并且,另外35个测试用例也都没有出现这一匪夷所思的情况。到底是怎么回事呢?

原理解释

我的第一想法是,可能需要给判断条件中!=两边的元素末尾各添加一个.intValue(),以彻底将它们转换为int值,避免在比较大小的时候出现错误。可我刚给左边的元素加上.intValue(),整条代码便被系统标了红,再将光标移到标红的位置,便看到了如下图所示的详细报错信息。
添加.intValue()后系统出现的报错信息
看到图中的报错信息,我顿时恍然大悟。原来,在原始代码中,!=两边的元素类型并不相同。左边是一个由HashMapgetKey()方法返回的Integer变量,而右边通过迭代器的getValue()方法得到的则是一个Object对象。两者的数据类型并不相同,因此在比较两者大小的时候会出现上述这种令人匪夷所思的错误。这种错误并不会直接被系统报出来,也不一定每次都会诱发故障(前35个测试用例就都返回了正确的结果),但如果不解决的话,说不准什么时候便会像最后一个测试用例这样出现问题,给程序带来不稳定因素。

修改

在得知了错误的原因之后,我们只需要将迭代器的getValue()方法返回的Object对象转换成和!=左边一样的int型变量即可。转换方法可参见这篇博客:将Java中Object转换成int或String类型的方法。在对这个问题进行修改之后,果然,程序得到了正确的运行结果,并通过了LeetCode后台的检验。
修改后的正确代码如下:

class Solution {
    public boolean isAnagram(String s, String t) {
        if(s==null||t==null||s.length()!=t.length())return false; 
        //若s和t有一个为空或两者的长度不一样,直接不可能是字母异位词
        HashMap<Character,Integer> sMap=new HashMap<>(); 
        HashMap<Character,Integer> tMap=new HashMap<>(); 
        for(int i=0;i<s.length();i++){
            if(!sMap.containsKey(s.charAt(i))){
                sMap.put(s.charAt(i),1);
            }else{
                sMap.put(s.charAt(i),sMap.get(s.charAt(i))+1);
            }
        } //记录s中出现的字符与对应的出现次数
        for(int i=0;i<t.length();i++){
            if(!tMap.containsKey(t.charAt(i))){
                tMap.put(t.charAt(i),1);
            }else{
                tMap.put(t.charAt(i),tMap.get(t.charAt(i))+1);
            }
        } //记录t中出现的字符与对应的出现次数
        Iterator<Map.Entry<Character,Integer>> it=sMap.entrySet().iterator(); //创建sMap的迭代器
        while(it.hasNext()){ //对sMap进行遍历
            Map.Entry ent=it.next();
            if(!tMap.containsKey(ent.getKey()))
            	return false; //判断是否tMap中是否含有针对相同字符的记录
            else if(tMap.get(ent.getKey())!=Integer.parseInt(String.valueOf(ent.getValue()))) 
            //注意将ent.getValue()由Object对象转换为int型变量
            	return false; //判断s和t中相同字符的出现次数是否相等
        }
        return true;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值