【问题标题】:How to remove duplicate pairs from an ArrayList in Java?如何从 Java 中的 ArrayList 中删除重复对?
【发布时间】:2021-08-08 13:27:12
【问题描述】:

我有一个 ArrayList,其中包含整数对(比如 int i、int j)。但它可能包含重复对(如(int i, int j)(int j, int i))。现在如何以 O(n) 的时间复杂度从中删除重复项。

更新代码:

class Pair<t1,t2>
{
    int i, j;
    Pair(int i,int j){
        this.i=i;
        this.j=j;
    }

}

public class My 
{
    public static void main(String[] args) {
        Pair p;
        List<Pair<Integer,Integer>> src = Arrays.asList(new Pair(1,2), 
            new Pair(2,3), new Pair(2,1),new Pair(1,2));
        HashSet<String> dest  = new HashSet();

        for(int i=0; i < src.size(); i++) {
            p=src.get(i);
            if(dest.contains(p.j+" "+p.i)) {
                System.out.println("duplicacy");
            }  
            else {
                dest.add(p.i+" "+p.j);
            }
         
        }
        System.out.println("set is = "+dest);
     
        List<Pair<Integer,Integer>> ans=new ArrayList();
        String temp;
        int i,j;
        Iterator<String> it=dest.iterator();
        while(it.hasNext()) 
        {
            temp=it.next();
            i=Integer.parseInt(temp.substring(0,temp.indexOf(' ')));
            j=Integer.parseInt(temp.substring(temp.indexOf(' 
               ')+1,temp.length()));
            ans.add(new Pair(i,j));
         }
    
         for(Pair i_p:ans) {
             System.out.println("Pair = "+i_p.i+" , "+i_p.j);
         }

     }//end of main method
 }//end of class My

这段代码运行良好,但我想知道它的性能,我的意思是它的整体时间复杂度?

【问题讨论】:

  • 你说的是javafx.util.Pair吗?你能展示你的代码和你尝试过的东西吗? (1, 2)(2, 1) 的副本吗?您还应该显示您的输入和预期输出。

标签: java performance arraylist


【解决方案1】:

只循环遍历Pairs列表,并在HashSet处理的pair中顺便收集,它是反向复制:

List<Pair<Integer,Integer>> lp = Arrays.asList(new Pair(1,2),
                                               new Pair(2,3),
                                               new Pair(1,2),
                                               new Pair(2,1));
Set<Pair<Integer,Integer>> sp = new HashSet<>();

List<Pair<Integer,Integer>> ulp = lp.stream()
                                    .collect(ArrayList::new,
                                             (l,p)-> { Pair<Integer,Integer> p1 = new Pair(p.getValue(), p.getKey());
                                                       if (!(sp.contains(p))&&!(sp.contains(p1))){
                                                           l.add(p);
                                                           sp.add(p);
                                                           sp.add(p1);
                                                        }} , List::addAll);

System.out.println(ulp);

【讨论】:

  • 这不起作用。它对待 (1,2) , (1,2) 和 (2,1) 不同。
【解决方案2】:

由于 HashSet 的 contains() 运行时间为 O(1)(参见 this 和其他参考资料),您可以使用以下方法,即总体 O(n): p>

import java.util.*;
import javafx.util.*;

public class Main
{
    public static void main(String[] args) {
           List<Pair<Integer,Integer>> src = Arrays.asList(new Pair(1,2), new Pair(2,3), new Pair(2,1));
           HashSet<Pair<Integer,Integer>> dest  = new HashSet();

            for(int i=0; i < src.size(); i++) {
                if(dest.contains(src.get(i)) || 
                    dest.contains(new Pair(src.get(i).getValue(),src.get(i).getKey()))) {
                    
                }else {
                    dest.add(src.get(i));
                }
            }
            
            System.out.println(dest);

    }
}

编辑 1

您可以使用Map.Entry 代替javafx.util.pair。没有Javafx的程序如下。

import java.util.*;

public class Main
{
    public static void main(String[] args) {
           List<Map.Entry<Integer,Integer>> src = Arrays.asList(new AbstractMap.SimpleEntry(1,2), 
                new AbstractMap.SimpleEntry(2,3), new AbstractMap.SimpleEntry(2,1));
           HashSet<Map.Entry<Integer,Integer>> dest  = new HashSet();

            for(int i=0; i < src.size(); i++) {
                if(dest.contains(src.get(i)) || 
                    dest.contains(new AbstractMap.SimpleEntry(src.get(i).getValue(),src.get(i).getKey()))) {
                    
                }else {
                    dest.add(src.get(i));
                }
            }
            
            System.out.println(dest);

    }
}

【讨论】:

  • 它不起作用。它对待他们不同。我认为因为它们是像 (1,2) 这样的对象,所以与另一个 (1,2) 对象不同。那么你能帮我解决这个问题吗?
  • 我对其进行了测试,它确实有效。是的,对象是不同的,在这段代码中我检查了所有成员。只需复制并粘贴并运行即可查看结果。
  • 您能否向我提供您在解决方案中使用的带有 getValue() 和 getkey() 方法的类 Pair 的实际定义。
  • 将我的代码复制并粘贴到Java online compiler 中,您可以看到它适用于 O(n) 而不是 O(3n)。 Pair 来自 javafx.util 。见this
  • 不使用 javafx 包你能做到吗,因为我不能在竞争性编程中使用那个包。
【解决方案3】:
  • 如果可以修改Pair类,只需实现equals()hashCode()

    public class Pair {
        private int a;
        private int b;
    
        public Pair(int a, int b) {
            this.a = a;
            this.b = b;
        }
    
        @Override
        public boolean equals(Object o) { 
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pair pair = (Pair) o;
            return (a == pair.a && b == pair.b) || (a == pair.b && b == pair.a);
        }
    
        @Override
        public int hashCode() {
            return Objects.hashCode(new HashSet<>(Arrays.asList(a,b))); 
        }
    
        @Override
        public String toString() {
            return "Pair{" +
                    "a=" + a +
                    ", b=" + b +
                    '}';
        }
    }
    

    然后创建一个新的Set&lt;Pair&gt;

    List<Pair> pairs = Arrays.asList(new Pair(1, 2), new Pair(2, 1), new Pair(3, 2));
    
    Set<Pair> pairSet = new HashSet<>(pairs);
    
    System.out.println(pairSet);
    

    输出:

    [Pair{a=1, b=2}, Pair{a=3, b=2}]
    
  • 如果不能修改Pair

    List<Pair> pairs = Arrays.asList(new Pair(1, 2), new Pair(2, 1), new Pair(3, 2));
    
    Set<Pair> pairSet = pairs.stream()
          .map(pair -> new HashSet<>(Arrays.asList(pair.getA(), pair.getB())))
          .distinct()
          .map(integers -> {
              Iterator<Integer> iterator = integers.stream().iterator();
              return new Pair(iterator.next(), iterator.next());
          })
          .collect(Collectors.toSet());
    
    System.out.println(pairSet);
    

    输出:

    [Pair{a=1, b=2}, Pair{a=2, b=3}]
    

如果需要,您可以将 Set 转换回列表:

List<Pair> list = new ArrayList<>(set);

但这很可能是不必要的。

【讨论】:

  • 修改 Pair 类很有趣。但是你确定你的第二种方法需要 O(N) 吗?它包含 map 和一个 collect 方法!!!
  • 每张地图都需要 O(n),收集最大值也需要 O(n)。总体为3n,大于n。然而两者都有线性复杂度 O(n)。
  • @MostNeededRabbit,你能解释一下你创建的 hashCode() 方法的内容吗?
  • @Cristiano 我想生成一个哈希码,它会忽略第一个值是分配给第一个字段还是第二个字段。一套没有顺序,我这里用了。
猜你喜欢
  • 2015-08-25
  • 1970-01-01
  • 2013-12-24
  • 2020-03-06
  • 2015-12-24
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
  • 2018-05-29
相关资源
最近更新 更多