Java暴力实现列表独有元素查找 代码运行结果异常求助
问题描述
编写暴力解法实现需求:检查第二个整数列表相较于第一个列表存在的独有/频次超出的元素,纸笔推演逻辑符合预期,但代码实际运行返回非预期结果。题目为经典的缺失数字问题:给定两个列表,第一个列表arr是第二个列表brr的子集(元素顺序打乱,可能存在重复元素),要求返回brr中所有没在arr里出现够对应次数的元素,按升序排列。
原实现代码
public static List<Integer> getMissingNumber (List<Integer> arr, List<Integer> brr){ Integer[] value = new Integer[brr.size()]; value = brr.toArray(value); for(int i=0; i<arr.size();i++){ for(int j=0; j<brr.size(); j++){ if(arr.get(i)==brr.get(j)){ value[j]=0; break; } } } Arrays.sort(value); List<Integer> exect_value = new ArrayList<Integer>(); for(int i=0;i<value.length;i++) { if(value[i]!=-1) { exect_value.add(value[i]); } } return Arrays.asList(value); }
异常定位
问题集中在双层循环匹配逻辑段,代码如下:
for(int i=0; i<arr.size();i++){ for(int j=0; j<brr.size(); j++){ if(arr.get(i)==brr.get(j)){ value[j]=0; break; } } }
测试运行情况
- 测试用例1:
arr长度为6,元素为[7,2,5,3,5,3];brr长度为8,元素为[7,2,5,4,6,3,5,3],预期输出为arr中缺失的元素[4,6],该用例运行结果符合预期。 - 测试用例2:
arr长度为10,元素为[11,4,11,7,13,4,12,11,10,14];brr长度为15,元素为[11,4,11,7,3,7,10,13,4,8,12,11,10,14,12],实际运行得到的value数组为[0, 0, 11, 0, 3, 7, 0, 0, 4, 8, 0, 11, 10, 0, 12],预期应为[0, 0, 0, 0, 3, 7, 0, 0, 0, 8, 0, 0, 10, 0, 12],数组中多了未被正确标记为0的元素[11,4,11]。
根因分析
代码共有3处明确错误:
- 重复匹配已占用的位置:内层循环比对时,始终拿
arr元素和原始brr的元素做对比,完全没有判断value[j]是否已经被之前的匹配标记为0。只要遇到和当前arr元素值相等的brr元素,不管这个位置是不是已经被用来匹配过之前的元素,都会直接标记然后break,导致重复的同值元素会反复命中brr中最靠前的同值位置,后面的同值位置永远没有机会被匹配到。
以第二个测试用例里的11为例:arr中共有3个11,每次匹配11时,内层循环从头扫描,第一个碰到的永远是brr索引0位置的11,反复给value[0]赋值0后直接break,brr中索引2、索引11位置的两个11从来没被匹配过,自然不会被标记为0,就留在了结果里,多出来的4也是同样的原因。 - Integer对象比对错误:用
==比对两个Integer对象,比较的是对象引用地址而不是实际数值,当数值超出JVM整数缓存池范围(默认-128~127)时,会出现值相等但判断为不相等的隐藏问题。 - 结果过滤与返回逻辑错误:标记已匹配元素时用的是赋值0,但过滤时判断条件是
value[i]!=-1,0本身满足这个条件,会被全部加入结果;且最后返回的是Arrays.asList(value),根本不是前面遍历处理的exect_value列表,就算标记逻辑正确,返回值也不符合预期。
修正后的暴力实现参考
public static List<Integer> getMissingNumber (List<Integer> arr, List<Integer> brr){ Integer[] value = brr.toArray(new Integer[brr.size()]); for(int i=0; i<arr.size();i++){ for(int j=0; j<brr.size(); j++){ // 跳过已标记的位置,用equals比对Integer实际值 if(value[j] != 0 && arr.get(i).equals(value[j])){ value[j] = 0; break; } } } Arrays.sort(value); List<Integer> exect_value = new ArrayList<>(); for(int i=0;i<value.length;i++) { // 过滤掉标记为0的已匹配元素 if(value[i] != 0) { exect_value.add(value[i]); } } return exect_value; }
内容的提问来源于stack exchange,提问作者Sakib X Hossain
相关产品推荐
相关产品推荐

