【问题标题】:Java: Intersection of Two Ordered Sequences of Integers [duplicate]Java:两个有序整数序列的交集[重复]
【发布时间】:2012-09-06 14:25:05
【问题描述】:

可能重复:
Java Compare Two Lists

如果我有两个有序的数字序列(我在这里有很大的灵活性,可以将我的数据放在列表、集合、数组等中),那么提取匹配项最有效的方法是什么?例如,如果我有:

[1, 2, 4, 6, 9]和[2, 3, 4],我想回[2, 4]。

显然有很多方法可以解决这个问题;我很好奇最有效的方法是什么。

【问题讨论】:

标签: java arrays integer


【解决方案1】:

两个指针(索引),每个列表一个。从每个列表的开头开始

只要找到匹配项,就将其存储起来。

如果没有匹配项,请检查哪个列表在当前索引中具有最低值并增加该列表的索引。检查匹配。这样做直到您到达列表之一的末尾。

与列表总和的大小成线性关系(更糟糕的情况)。没有办法做得更好。

【讨论】:

    【解决方案2】:

    所以你想要 to 集合的交集? 您可以使用来自 apache commons 的 CollectionUtils.intersection。或者更好的是来自 Guava Sets.intersection 的那个(这是通用的)。

    【讨论】:

      【解决方案3】:

      如果您将这两个序列存储到 Sets 中,您可以使用 Set.retainAll() 其中:

      仅保留此集合中包含在指定集合中的元素(可选操作)。换句话说,从这个集合中移除所有不包含在指定集合中的元素。如果指定的集合也是一个集合,则此操作有效地修改此集合,使其值为两个集合的交集。

      例如:

      Set<Integer> s1 = new TreeSet<Integer>();
      s1.add(1);
      s1.add(2);
      s1.add(6);
      
      Set<Integer> s2 = new TreeSet<Integer>();
      s2.add(2);
      s2.add(6);
      
      s2.retainAll(s1);
      
      for (Integer i: s2)
      {
          System.out.println(i);
      }
      

      输出:

      2 6

      【讨论】:

      • 这不会在线性时间内运行。它将遍历目标集合,在原始集合中搜索(为树集排序 log(n)),并一个一个删除。
      • @greyfairer 第一个集合不需要是树集,它可以是一个哈希集,它给你一个 O(1) 的包含。
      • @assylias 但我的观察是,如果它是一组较短的数组,则需要更多时间来构建 Hashset 它自己。
      【解决方案4】:

      这是intersection 的两个集合,我猜Set 是最好的选择。

      请看Collection.retainAll()

      仅保留此集合中包含在指定集合中的元素(可选操作)。换句话说,从这个集合中移除所有不包含在指定集合中的元素。

      更有效的方法是

      public static void main(String[] args) {
          int[] firstArray = { 1, 3, 5, 8, 10 };
          int[] secondArary = { 3, 8 };
          //Arrays.sort(firstArray); If arrays needs to be sorted
          //Arrays.sort(secondArary);
          System.out.println(Arrays
                  .toString(intersection(firstArray, secondArary)));
      
      }
      
      private static Integer[] intersection(int firstArray[], int secondArary[]) {
          int i = 0;
          int j = 0;
          ArrayList<Integer> list = new ArrayList<Integer>();
          while (i < firstArray.length && j < secondArary.length) {
              if (firstArray[i] < secondArary[j])
                  i++;// Increase I move to next element
              else if (secondArary[j] < firstArray[i])
                  j++;// Increase J move to next element
              else {
                  list.add(secondArary[j++]);
                  i++;// If same increase I & J both
              }
          }
          return list.toArray(new Integer[0]);
      }
      

      【讨论】:

        【解决方案5】:

        我会将这两个列表创建为java.util.Set,将一组复制到一个临时变量并在这个临时集上调用retainAll(&lt;otherSet&gt;)。那么临时集合将留在两个集合的交集处。

        【讨论】:

        • 这不会在线性时间内运行。它将遍历目标集合,在原始集合中搜索(通过哈希码查找 HashSet),并逐个删除。
        【解决方案6】:

        我会使用TreeLists 并执行以下操作:

        TreeList<Integer> list1 = ...
        TreeList<Integer> list2 = ...
        
        Iterable<Integer> result = Iterables.filter(list1, Predicates.in(list2));
        

        这使用 Guava 的 Iterables 和 Predicates。

        【讨论】:

          猜你喜欢
          • 2020-05-31
          • 1970-01-01
          • 2012-03-03
          • 1970-01-01
          • 1970-01-01
          • 2011-01-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多