Java按HashMap键值过滤二维数组 筛选指定数量候选人问题排查
问题排查与修复
核心Bug根因
筛选候选人的逻辑错误使用了while循环,导致单个候选人会重复占用同岗位的所有剩余名额:
- 业务逻辑上单个候选人最多只能占对应岗位1个招聘名额,匹配到岗位且有剩余名额时,只需要做1次判断、扣减1次名额即可,不需要循环
- 现有
while逻辑下,遇到第一个匹配岗位且有剩余名额的候选人时,会反复进入循环:虽然Set会自动去重不会重复存储人名,但AtomicInteger的计数会被持续递减,直接把该岗位的剩余名额全扣在这一个候选人身上,后续同岗位符合要求的候选人自然没有名额可选。
以第二组测试用例为例,developer岗招聘2人,遍历到第一个developer岗候选人Bill时:
- 第一次进循环:添加Bill到结果集,名额从2减到1,此时循环条件依然满足(岗位匹配、剩余名额1>0)
- 第二次进循环:Bill已经在Set中不会重复添加,但名额还是会被减到0,直接把2个名额全用完,后续排序靠后的John自然不会被选中。
其他可优化问题
- 内层循环遍历全量Map entry匹配岗位效率极低:每个候选人只对应一个应聘岗位,直接通过岗位key从Map中取剩余名额即可,不需要遍历所有岗位,时间复杂度可以从O(m*n)降到O(m)(m为候选人数,n为岗位数)
- 使用
TreeSet存储结果会默认按姓名字典序排序,和实际录取优先级无关,如果业务要求按录取优先级输出,应该替换为LinkedHashSet按插入顺序存储。
修复后的核心筛选逻辑
把原来的双层循环+while的逻辑替换为以下代码即可:
// 用LinkedHashSet保留录取顺序,更符合招聘场景的输出要求 Set<String> res = new LinkedHashSet<>(); for (String[] candidate : candidates) { String applyPost = candidate[1]; AtomicInteger remainCount = hm.get(applyPost); // 单个候选人只做一次判断,不需要循环 if (remainCount != null && remainCount.get() > 0) { res.add(candidate[0]); remainCount.decrementAndGet(); } }
结果验证
- 第一组测试用例(developer招1、project招1):排序后按优先级依次录取Bill(占用developer名额)、Steve(占用project名额),输出
[Bill, Steve]符合预期 - 第二组测试用例(developer招2、project招1):依次录取Bill(developer剩余1个名额)、Steve(project名额用完)、John(developer剩余名额用完),输出
[Bill, John, Steve]符合预期
内容的提问来源于stack exchange,提问作者PRD
相关产品推荐
相关产品推荐

