Java中从HashMap移除键时触发java.lang.NullPointerException问题
LeetCode《Top K Frequent Elements》代码空指针异常问题
我在解决LeetCode《Top K Frequent Elements》题目时,代码执行到hm.remove(currentGreatestValue);这一行抛出了java.lang.NullPointerException异常。我的需求是在迭代过程中从HashMap移除键,以此获取下一个最大元素,相关代码如下:
class Solution { public int[] topKFrequent(int[] nums, int k) { HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>(); for (int i=0; i<nums.length; i++){ if (!hm.containsKey(nums[i])){ hm.put(nums[i], 1); } else { int occurances = hm.get(nums[i]); occurances = occurances + 1; hm.put(nums[i], occurances); } } int mostOccuredValues[] = new int[k]; Iterator hmIterator = hm.entrySet().iterator(); int currentGreatestValue=0; int currentValue; int nextGreatestIndex=0; for (int i=0; i<k; i++){ while (hmIterator.hasNext()) { Map.Entry mapElement = (Map.Entry)hmIterator.next(); currentValue = (int)mapElement.getKey(); if (currentValue>currentGreatestValue){ currentGreatestValue = currentValue; } } mostOccuredValues[nextGreatestIndex] = hm.get(currentGreatestValue); nextGreatestIndex = nextGreatestIndex + 1; hm.remove(currentGreatestValue); } return mostOccuredValues; } }
错误原因
- 迭代器耗尽:仅初始化一次
hmIterator,第一次循环遍历完后,迭代器已走到末尾,后续循环中while (hmIterator.hasNext())不会执行,currentGreatestValue保留上一次的值。当该值已被移除后,hm.get(currentGreatestValue)返回null,赋值给int类型数组时触发空指针异常。 - 核心逻辑偏离题目要求:当前代码是比较键的数值大小,而题目需要的是按元素出现频率(HashMap的值)取前k个元素,即便解决空指针问题,结果也不符合题目要求。
- 直接修改HashMap的潜在风险:在迭代器遍历后直接调用
hm.remove(),若后续复用同一迭代器,会触发ConcurrentModificationException,不过这里的问题先出在迭代器耗尽。
修复方案
方案1:按频率排序(推荐,符合题目要求)
先统计元素频率,再将键值对按频率降序排序,取前k个键即可:
class Solution { public int[] topKFrequent(int[] nums, int k) { HashMap<Integer, Integer> freqMap = new HashMap<>(); // 简化频率统计逻辑 for (int num : nums) { freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); } // 将entry按频率降序排序 List<Map.Entry<Integer, Integer>> entryList = new ArrayList<>(freqMap.entrySet()); entryList.sort((a, b) -> b.getValue() - a.getValue()); // 提取前k个元素的键 int[] result = new int[k]; for (int i = 0; i < k; i++) { result[i] = entryList.get(i).getKey(); } return result; } }
方案2:迭代移除方式(满足你移除键的需求,同时修正逻辑)
每次循环前重新遍历HashMap找到当前频率最高的键,移除后再进入下一轮循环:
class Solution { public int[] topKFrequent(int[] nums, int k) { HashMap<Integer, Integer> freqMap = new HashMap<>(); for (int num : nums) { freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); } int[] result = new int[k]; int index = 0; for (int i = 0; i < k; i++) { int maxFreq = -1; Integer targetKey = null; // 每次循环重新遍历找频率最高的键 for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) { if (entry.getValue() > maxFreq) { maxFreq = entry.getValue(); targetKey = entry.getKey(); } } // 存入结果并移除该键 result[index++] = targetKey; freqMap.remove(targetKey); } return result; } }
内容的提问来源于stack exchange,提问作者user883311
相关产品推荐
相关产品推荐

