手动删除O(n)中的重复项

时间:2019-10-02 14:51:53

标签: algorithm

我需要删除列表中的所有重复项,但前提是列表a中的项目也与列表b中的相同。这是我当前的代码,但是要处理10万个项目,实际上需要几天的时间,有没有一种快速的方法?

任何帮助表示赞赏。

  List<int> ind = new List<int>();
            List<int> used = new List<int>();
            for (int i = 0; i < a.Count; i++)
            {
                for (int j = 0; j < a.Count; j++)
                {
                    if (i != j&&!used.Contains(i))
                    {
                        if (a[j] == a[i] && b[i] == b[j])
                        {
                            ind.Add(j);
                            used.Add(j);
                        }
                    }
                }
            }
            List<string> s2 = new List<string>();
            List<string> a2 = new List<string>();
            for (int i = 0; i < a.Count; i++)
            {
                if (!ind.Contains(i))
                {
                    s2.Add(a[i]);
                    a2.Add(b[i]);
                }
            }

6 个答案:

答案 0 :(得分:2)

许多此类问题的关键是正确的数据结构。为避免重复,您需要使用Set,因为它们会自动删除重复。

这是Java中的代码,我希望它与C#类似:

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

class Duplicates
{
    static List<Integer> list1 = new ArrayList<>();
    static List<Integer> list2 = new ArrayList<>();

    static final int SIZE = 100_000;
    static final int MAX_VALUE = 1000_000;

    public static void main(String[] args)
    {
        // populate the lists with random values for testing
        Random r = new Random();
        for(int i=0; i<SIZE; i++)
        {
            list1.add(r.nextInt(MAX_VALUE));
            list2.add(r.nextInt(MAX_VALUE));
        }
        Set<Integer> set1 = new HashSet<>(list1);
        Set<Integer> set2 = new HashSet<>(list2);

        // items that are in both lists
        Set<Integer> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);

        Set<Integer> notSeenYet = new HashSet<>(intersection);

        List<Integer> list1Unique = new ArrayList<Integer>();
        for(int n: list1)
        {
            if(intersection.contains(n)) // we may have to skip this one
            {
                if(notSeenYet.contains(n)) // no, don't skip, it's the first occurrence
                {
                    notSeenYet.remove(n);
                }
                else
                {
                    continue;
                }
            }
            list1Unique.add(n);
        }
        System.out.println("list 1 contains "+list1Unique.size()+" values after removing all duplicates that are also in list 2");

    }

} 

100k值只需不到一秒钟。

输出

  

列表1删除所有重复项后包含99591个值   也在清单2中

答案 1 :(得分:2)

这是要考虑的一般算法。我们可以从两个列表开始按升序排序。使用良好的排序算法(例如合并排序),这将花费O(NlgN)时间,其中N是列表的长度。支付完罚款后,我们只需在每个列表中维护两个指针。一般而言,一般算法将涉及遍历两个列表,如果有问题的值与a列表中的指针匹配,则在第一个b列表中搜索重复项。如果存在匹配项,则将从a列表中删除重复项,否则我们将继续走直到到达a列表的末尾。此过程仅为O(N),从而使最大的罚款成为O(NlgN)的初始排序。

答案 2 :(得分:2)

创建一个HashSet

首先,遍历列表b并将所有元素添加到HashSet中。

然后,遍历列表a的每个元素。当您访问某个元素时,请询问HashSet它是否已包含该元素。如果不是,则这是一个新元素,因此只需保留它即可。如果是这样,它就是重复项,您可以将其从a中删除。

HashSet可以在O(1)中执行Do you have this element?问题,因此对于整个列表,您有O(n)。

有关更多信息,请检查documentation

答案 3 :(得分:1)

要“删除重复项”,我的意思是“从n个相同的项目中,保留第一个并删除其余的n-1个”。如果是这样,那么这就是算法:

将列表b转换为B。还介绍集合A_dup。遍历列表a和每个项目:

  • 如果在A_dup中找到了项目,则将其从a中删除,
  • 否则,如果在集合B中找到了项目,则将其添加到A_dup
  • 重复。

检查集合(A_dupB中是否存在)是O(1)操作,也要在集合中添加新项目。因此,您剩下要遍历列表a,这总共给了我们O(n)。

答案 4 :(得分:0)

我认为您想做的是找到不同的对,对吧?

如果是这样,则可以使用Distinct var result = a.Zip(b, (x,y) => (x, y)).Distinct(); 以及C#元组(或使用匿名类型)在一行中完成该操作。

usedRange

答案 5 :(得分:0)

import java.util.*;
import java.util.stream.Collectors;

public class Test {
    public static void main(String args[]) {
        List<String> dupliKhaneList = new ArrayList<>();
        dupliKhaneList.add("Vaquar");
        dupliKhaneList.add("Khan");
        dupliKhaneList.add("Vaquar");
        dupliKhaneList.add("Vaquar");
        dupliKhaneList.add("Khan");
        dupliKhaneList.add("Vaquar");
        dupliKhaneList.add("Zidan");

        // Solution 1 if want to remove in list 
        List<String> uniqueList = dupliKhaneList.stream().distinct().collect(Collectors.toList());
        System.out.println("DupliKhane =>  " + dupliKhaneList);
        System.out.println("Unique 1 =>  " + uniqueList);

        // Solution 2 if want to remove using 2 list
        List<String> list1 = new ArrayList<>();
        list1.add("Vaquar");
        list1.add("Khan");
        list1.add("Vaquar");
        list1.add("Vaquar");
        list1.add("Khan");
        list1.add("Vaquar");
        list1.add("Zidan");

        List<String> list2 = new ArrayList<>();

        list2.add("Zidan");

        System.out.println("list1 =>  " + list1);
        System.out.println("list2 =>  " + list2);

        list1.removeAll(list2);

        System.out.println("removeAll duplicate  =>  " + list1);
    }
}

结果:

DupliKhane =>  [Vaquar, Khan, Vaquar, Vaquar, Khan, Vaquar, Zidan]
Unique 1 =>  [Vaquar, Khan, Zidan]
list1 =>  [Vaquar, Khan, Vaquar, Vaquar, Khan, Vaquar, Zidan]
list2 =>  [Zidan]
removeAll duplicate  =>  [Vaquar, Khan, Vaquar, Vaquar, Khan, Vaquar]