【问题标题】:Java array replacementsJava 数组替换
【发布时间】:2020-08-26 21:36:07
【问题描述】:

您好,我有 3 个整数数组。

  • 数组 #1 包含信息并包含重复项。
  • 数组 #2 包含可能在数组 1 中的值。
  • 数组 #3 有替换值。
  • 数组 #2 和数组 #3 大小相同且不包含重复项。

我想检查数组#2 中的元素是否在数组#1 中。 如果元素在数组#1 中,我希望将其替换为数组#3 中的元素。 #3 中替换原始元素的元素需要在数组中与 #2 具有相同的位置。 我可以做到的一种方法是:

for (int i = 0; i<arr1.length; i++){
  for (int a = 0; a<arr2.length; a++){
    if(arr1[i]==arr2[a]){
      arr1[i]=arr3[a];
      break;
    }
  }
}

我想知道是否有更快或更好的方法来做到这一点。

【问题讨论】:

    标签: java arrays replace integer iteration


    【解决方案1】:

    当前算法的时间复杂度为 O(n * m)n = 数组 #1 的长度,m = 数组 #2 的长度。

    有一种算法具有更好的时间复杂度。

    算法示意图:

    1. 对数组 #1 进行排序,跟踪元素如何在末尾反向排序 (O(n log(n)))
    2. 对数组 #2 进行排序,相应地置换数组 #3 中的元素 (O(m log(m)))
    3. 查找数组#1 中的所有元素,同时也在数组#2 中,并将它们替换为数组#3 中相同位置的元素 (O(n + m))
    4. 利用从 1 开始的跟踪对数组 #1 进行非排序。(O(n))

    总共得到O(n log(n) + m log(m) + n + m + n) ∈ O(n log(n) + m log(m))

    如果数组 #2 和 #3 也必须不打乱,则可以复制这些数组或在排序期间跟踪并取消打乱它们,因为取消打乱只需要O(m)

    【讨论】:

    • 不需要排序。 O(n + m) 的总体复杂度是可能的:请参阅this answer,了解如何通过数组 1 和 2 各一次来完成。
    【解决方案2】:

    Array #2 和 Array #3 不能很好地替代 HashMap。

    Map<T, T> replacements = new HashMap<>();
    for (int i = 0; i < arr2.length; i++) {
      replacements.put(arr2[i], arr3[i]);
    }
    for (int i = 0; i < arr1.length; i++) {
      if (replacements.containsKey(arr1[i]) {
        arr1[i] = replacements.get(arr1[i]);
      }
    }
    

    这将具有大约 O(n) 的时间复杂度。

    【讨论】:

      【解决方案3】:

      使用array1 中元素的Set 来确定其中是否有元素。
      如果集合包含其元素,则遍历 array2 并复制 form array3:

      Set<T> set = Arrays.stream(arr1).collect(toSet()); // O(n)
      for (int i = 0; i < arr2.length; i++){         // O(m)
          if (set.contains(arr2[i])) {
            arr2[i] = arr3[i];
          }
      }
      

      给定 array1 的大小为 n,而 array2 的大小为 m...
      集合上的所有操作都是常数时间(即 O(1)),因此构建集合成本 O(n)。
      遍历 array2 是 O(m) - 设置查找成本是 O(1)

      总成本 O(n + m) - 即“线性”。

      您当前的成本是 O(n * m) - 即“二次”。


      注意:您尚未指定数组的类型。如果它们是原始的(例如int),构建集合需要添加对boxed() 的调用,因为java 不支持原始集合:

      Arrays.stream(arr1).boxed().collect(toSet())
      

      【讨论】:

      • OP 说3 integer arrays。你应该使用Arrays.stream(arr1) 而不是Arrays.stream()
      • @saka1029 感谢您发现错字。全部修复?
      • 看来我可能有点不清楚。我希望将数组#3 中的值复制到数组#1 中。您的方法似乎没有返回数组 #1 中元素的位置。我希望示例代码能让我更清楚我想要做什么。
      • 您可能希望通过使用Collectors.toCollection(HashSet::new); 来指定Set 的类型。否则,不保证 Set 返回和设置构造的类型,以及 contains(...) 可能不会在线性/恒定时间内运行。
      • @Turing85 toSet() 总是返回一个HashSet - 自己阅读源代码。如果你仔细想想,没有其他明智的选择。尽管技术上您是正确的,根据方法合同没有保证,但出于实用性考虑,它将总是返回HashSet
      猜你喜欢
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-26
      • 2022-01-17
      • 2012-11-19
      • 1970-01-01
      相关资源
      最近更新 更多