如何正确比较 int 数组内容并去重:使用封装类实现深度相等判断

java 中 `int[]` 默认使用引用相等(`==`),`hashset` 的 `contains()` 无法按元素值判断是否重复;需封装数组为

自定义类型,并重写 `equals()` 和 `hashcode()`,使用 `arrays.equals()` 和 `arrays.hashcode()` 实现深度比较。

在处理二维整数数组(如矩阵行)的逻辑去重时,一个常见误区是直接将 int[] 存入 HashSet 并期望其自动按内容相等进行判重。但 Java 中数组是对象,int[] 类型未重写 equals() 和 hashCode(),因此 HashSet 内部调用的是 Object 的默认实现——即基于内存地址(引用)的比较。这意味着即使两个 int[] 元素完全相同(如 {1,2,3,4} 和 {1,2,3,4}),只要不是同一对象实例,contains() 就会返回 false,导致重复添加。

要解决该问题,核心思路是将原始数组封装为支持值语义(value-based)的不可变类型,并正确实现 equals() 与 hashCode()。推荐使用 Java 14+ 的 record(简洁安全),也可用普通类或 List(但后者有装箱开销)。

以下是修正后的关键代码片段(已适配 Codewars 题目逻辑):

record Row(int[] row) {
    @Override
    public int hashCode() {
        return Arrays.hashCode(row); // 基于元素内容生成哈希码
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Row row1 = (Row) o;
        return Arrays.equals(row, row1.row); // 深度比较数组内容
    }
}

在主逻辑中,所有 int[] 必须统一包装为 Row 实例:

private static final Set registeredM = new HashSet<>();

static public int count_different_matrices(int[][] matrices) {
    registeredM.clear(); // 注意:静态集合需重置,避免多次调用污染
    Arrays.stream(matrices)
          .forEach(m -> {
              List variants = unwrapPossibleMatrices(m);
              if (variants.stream().noneMatch(registeredM::contains)) {
                  registeredM.add(new Row(m));
              }
          });
    registeredM.forEach(e -> System.out.println(Arrays.toString(e.row())));
    return registeredM.size();
}

private static List unwrapPossibleMatrices(int[] m) {
    return Arrays.asList(
        new Row(m),
        new Row(new int[]{m[2], m[0], m[3], m[1]}),
        new Row(new int[]{m[3], m[2], m[1], m[0]}),
        new Row(new int[]{m[1], m[3], m[0], m[2]})
    );
}

关键注意事项:

  • 切勿复用原始 int[]:HashSet 永远不会按内容去重,必须全部转为封装类型;
  • Arrays.hashCode() 与 Arrays.equals() 是标准解法:它们专为数组内容比较设计,高效且语义明确;
  • 静态集合需手动清理:本例中 registeredM 是 static final,但方法需支持多次调用,故应在入口处调用 clear();
  • record 天然不可变且线程安全:避免因外部修改 row 数组导致哈希不一致(若用普通类,务必确保 row 字段 private final 且不暴露引用)。

通过此方案,输入 {{1,2,3,4},{3,1,4,2},{4,3,2,1},{2,4,1,3}} 将正确识别所有四行均互为旋转等价(题目定义的四种变换),最终只保留一个代表元,输出 1 —— 符合题意预期。