【问题标题】:How do I check if two simple 2D arrays have the same 1D arrays? (order and repetitions doesn't matter)如何检查两个简单的二维数组是否具有相同的一维数组? (顺序和重复无关紧要)
【发布时间】:2022-01-07 01:12:13
【问题描述】:

我的主要目标是返回一个二维数组 int[ ] 的所有元素 int[ ] 是否存在于另一个二维数组中。

我已经尝试使用Arrays.deepEquals(),但在这种情况下,元素的顺序很重要,这不是目的。

  • 例如,Int[ ][ ] 数组的长度不会超过 15。
  • Int[ ][ ] 数组的长度始终相同。
  • Int[ ][ ] 数组顺序无关紧要,但 Int[ ] 数组可以。
  • Int[ ] 数组始终是一对。

预期:

int[][] array1 = {{1, 2}, {2, 2}, {0, 1}, {3,4}} // Main Array

int[][] array2 = {{0, 1}, {2, 2}, {3,4} {1, 2}}} // Expected: true

int[][] array3 = {{6, 3}, {1, 2}, {7,4} {0, 1}}} // Expected: false
  

这是我的解决方案/尝试:

// Check if an int[] array (element) belongs to an int[][] array.

public static boolean inVector(int[][] 2dArray, int[] 1dArray) {

    for (int i = 0; i < 2dArray.length; i++) {
        for (int j = 0; j < 2dArray[i].length; j++) {

            if (1dArray[0] == 2dArray[i][0] && 1dArray[1] == 2dArray[i][1]) {
                return true;
            }
        }
    }

    return false;
}


// Check if all int[] arrays of an int[][] belong to another int[][] array.

// This is not working properly

public boolean allBelongs() {

  boolean belongs = false;

  for (int i = 0; i < array1.length; i++) {
     
     if (inVector(array1, array2()[i])) {
        belongs = true;
     }
     
     else {
        belongs = false;
     }
  }

    return belongs;
}

编辑:我解决了问题,颠倒了解决方案的逻辑。发表了自己的答案。

【问题讨论】:

  • 您有具体的性能要求吗?您希望数组有多大?
  • 例如,如果数组通常非常小,最简单和最快的解决方案可能是嵌套循环,循环遍历第一个数组中的每个子数组 A,然后遍历第二个数组中的每个子数组 B ,检查A是否深等于B,如果每个A都是这样,则返回true,否则返回false
  • 不,我没有任何性能要求。
  • Int[ ] 数组总是成对的。 :)
  • 例如,我希望 int[ ] [ ] 数组的长度不超过 15。

标签: java arrays java-8 equals deepequals


【解决方案1】:

您可以使用IntBuffer,它可以包装int[] 数组并提供反映数组内容的equalshashCode 实现。

public static boolean sameSubArrays(int[][] array1, int[][] array2) {
    if(array1 == array2) return true;
    HashSet<IntBuffer> set = new HashSet<>();
    for(int[] a: array1) set.add(IntBuffer.wrap(a));
    for(int[] a: array2) if(!set.contains(IntBuffer.wrap(a))) return false;
    return true;
}

这很简单并且在线性时间内运行,因此可以处理大型数组。它具有您的测试用例的预期结果。

int[][] array1 = {{1, 2}, {2, 2}, {0, 1}, {3,4}};
int[][] array2 = {{0, 1}, {2, 2}, {3, 4}, {1, 2}};
System.out.println(sameSubArrays(array1, array2)); // true

但它不考虑重复。如果出现次数必须与内容相同的子数组匹配,则必须扩展解决方案以使用映射来计算出现次数。

public static boolean sameSubArrays(int[][] array1, int[][] array2) {
    if(array1 == array2) return true;
    if(array1.length != array2.length) return false;
    HashMap<IntBuffer, Integer> map = new HashMap<>();
    for(int[] a: array1) map.merge(IntBuffer.wrap(a), 1, Integer::sum);
    for(int[] a: array2)
        if(map.merge(IntBuffer.wrap(a), -1, Integer::sum) < 0) return false;
    return true;
}

由于您的示例没有重复,它仍然具有相同的结果。

【讨论】:

  • 您的第一个 sn-p 是否检查它们是否相等,或者只是 array2 是 array1 的子集?看起来它会为非空 array1 和空 array2 返回 true。
  • @AndyTurner 第一个 sn-p 检查array2 的所有子数组是否也是array1 的子数组。你可以通过长度检查来增加它,但它仍然不能处理重复,所以即使那样,array2 也可能只包含一个子数组的重复。因此,对于“包含所有其他数组”检查,您必须使用第二个 sn-p。
  • 感谢您的回答霍尔格。我认为这是最简单最正确的做法。
【解决方案2】:

此解决方案应该有效。如果数组相对较小(例如 2 x 4),它可能会比其他解决方案更快:

import java.util.Arrays;

class Main {
  public static boolean isSubarrayUnordered(int[][] child, int[][] parent) {
    for (int[] childSubarray : child) {
      boolean found = false;
      for (int[] parentSubarray : parent) {
        if (Arrays.equals(childSubarray, parentSubarray)) {
          found = true;
          break;
        }
      }
      if (!found) return false;
    }
    return true;
  }

  public static void main(String[] args) {
    int[][] array1 = {{1, 2}, {2, 2}, {0, 1}, {3, 4}};
    int[][] array2 = {{0, 1}, {2, 2}, {3, 4}, {1, 2}};
    int[][] array3 = {{1, 2}, {2, 2}, {0, 999}, {3, 4}};

    System.out.println("array1 in array2? " + isSubarrayUnordered(array1, array2));
    System.out.println("array1 in array3? " + isSubarrayUnordered(array1, array3));
  }
}

对于中等大小的数组(可能有数百到数千个元素),创建两个数组的排序副本并在两个数组上都有两个迭代器itChild, itParent 可能会更快。对于itChild的每个元素,如果itParent的当前元素相等(使用Arrays.equals,则同时推进itChilditParent。否则,仅推进itParent。重复直到没有更多itChild 中的元素(返回true)或itParent 中没有更多元素(返回false)。

对于非常大的数组(数百万到数十亿个元素),创建副本的成本可能非常昂贵。您可能希望使用sha256 哈希之类的东西创建数组的压缩表示,然后仅比较元素的哈希值。但是,如果数组非常大,则返回错误答案的可能性很小。

【讨论】:

  • 你为什么在你的方法中使用装箱的Boolean?请注意,对于较大的数组,您认为太复杂了;有a much simpler solution
  • 没有理由加框Boolean,编辑我的答案将其删除。
  • “你想的太复杂了”——在幕后,你的链接解决方案中的IntBuffer 使用hashCode 进行有效的equals 比较,所以核心思想并不复杂。此外,如果数据非常大,那么 sha256 将比 IntBuffer 快得多,因为在元素 相等的情况下,您必须比较每个元素。如果数组是 M X N(大小为 N 个子数组),则每个相等性检查都是 O(N) 与 O(1) 与 sha256。但是,是的,我同意IntBuffer 是一个不错的简单解决方案。
  • 感谢您的回答布兰登。它帮助我弄清楚用不同的方法我可以解决问题,而不是验证所有int[] 是否存在于int[][] 中,我可以验证一个int[] 是否不存在。
  • 要计算 sha256,无论如何你都必须遍历整个数组,因为相等的散列并不能证明数组相等(对于大数组),你还必须比较元素。
【解决方案3】:

我可以验证 ONE int[] 是否不存在,而不是验证 int[][] 中是否存在 ALL int[]。

public boolean allBelongs() {

  for (int i = 0; i < array1.length; i++) {
 
    if (!inVector(array1, array2()[i])) {
       return false;
    }
  }

  return true;
}

【讨论】:

    猜你喜欢
    • 2014-05-15
    • 2017-11-24
    • 2016-09-12
    • 1970-01-01
    • 2012-06-13
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    相关资源
    最近更新 更多