Codewars题目中:修改Java代码实现int数组元素级相等判断
数组元素相等判断问题的解决方案
问题背景
我在解决编程题时,遇到了数组相等判断的问题:我需要判断多个数组是否是同一矩阵的变体(通过旋转等操作得到),但HashSet的contains()方法总是把元素相同的数组判定为不同对象,导致结果不符合预期。
我的代码
public static void main(String[] args) { int[][] ms; ms = new int[][] {{1, 2, 3, 4}, {3, 1, 4, 2}, {4, 3, 2, 1}, {2, 4, 1, 3}}; System.out.println(count_different_matrices(ms)); } private static final Set<int[]> registeredM = new HashSet<>(); static public int count_different_matrices(int[][] matrices) { Arrays.stream(matrices).forEach(m -> { if(unwrapPossibleMatrices(m).stream().noneMatch(registeredM::contains)) { registeredM.add(m); } }); registeredM.forEach(e -> System.out.println(Arrays.toString(e))); return registeredM.size(); } static private List<int[]> unwrapPossibleMatrices(int[] m) { return Arrays.asList(new int[][]{m, {m[2], m[0], m[3], m[1]}, {m[3], m[2], m[1], m[0]}, {m[1], m[3], m[0], m[2]} }); }
控制台输出
[1, 2, 3, 4] [2, 4, 1, 3] [4, 3, 2, 1] [3, 1, 4, 2] 4
问题点
我预期输出仅为[1, 2, 3, 4],但实际输出了4个数组。原因是Java中int[]的equals()方法默认比较对象引用地址,而非数组元素是否相同,导致HashSet无法识别元素相同的数组。
解决方案
方法1:转换为List<Integer>存储(推荐)
将数组转为List<Integer>,因为List的equals()和hashCode()方法是基于元素实现的,能被HashSet正确识别:
修改后的代码:
import java.util.*; public class MatrixCounter { public static void main(String[] args) { int[][] ms = new int[][] {{1, 2, 3, 4}, {3, 1, 4, 2}, {4, 3, 2, 1}, {2, 4, 1, 3}}; System.out.println(count_different_matrices(ms)); } private static final Set<List<Integer>> registeredM = new HashSet<>(); static public int count_different_matrices(int[][] matrices) { Arrays.stream(matrices).forEach(m -> { // 生成当前数组的所有变体 List<int[]> variants = unwrapPossibleMatrices(m); // 检查是否有变体已在集合中 boolean hasExistingVariant = variants.stream() .map(arr -> Arrays.asList(Arrays.stream(arr).boxed().toArray(Integer[]::new))) .anyMatch(registeredM::contains); if (!hasExistingVariant) { // 将当前数组转为List存入集合 registeredM.add(Arrays.asList(Arrays.stream(m).boxed().toArray(Integer[]::new))); } }); registeredM.forEach(System.out::println); return registeredM.size(); } static private List<int[]> unwrapPossibleMatrices(int[] m) { return Arrays.asList(new int[][]{m, {m[2], m[0], m[3], m[1]}, {m[3], m[2], m[1], m[0]}, {m[1], m[3], m[0], m[2]} }); } }
方法2:遍历集合用Arrays.equals比较
如果不想转换集合类型,可以在判断时遍历registeredM,用Arrays.equals逐个比较数组元素:
修改count_different_matrices方法:
private static final Set<int[]> registeredM = new HashSet<>(); static public int count_different_matrices(int[][] matrices) { Arrays.stream(matrices).forEach(m -> { List<int[]> variants = unwrapPossibleMatrices(m); // 遍历所有变体,检查集合中是否有元素与变体元素相等 boolean hasMatch = variants.stream() .anyMatch(variant -> registeredM.stream().anyMatch(r -> Arrays.equals(r, variant))); if (!hasMatch) { registeredM.add(m); } }); registeredM.forEach(e -> System.out.println(Arrays.toString(e))); return registeredM.size(); }
这种方式无需转换类型,但每次判断都要遍历集合,适合数据量较小的场景。
方法3:使用TreeSet自定义比较器
通过TreeSet传入自定义比较器,实现基于元素的数组比较:
private static final Set<int[]> registeredM = new TreeSet<>((a, b) -> { // 先比较长度 if (a.length != b.length) { return Integer.compare(a.length, b.length); } // 逐个比较元素 for (int i = 0; i < a.length; i++) { int cmp = Integer.compare(a[i], b[i]); if (cmp != 0) { return cmp; } } return 0; });
注意:TreeSet是有序集合,且比较器需要保证一致性(即compare(a,b)==0时,a.equals(b)理论上也应返回true,但数组的equals仍比较引用,所以这种方式不完全符合Set的严格规范,仅适合特定场景)。
内容的提问来源于stack exchange,提问作者BJagger
相关产品推荐
相关产品推荐

