在堆空间有限的列表中查找重复项

时间:2019-07-03 20:38:22

标签: java algorithm

有N +1个长度的只读列表,介于1到N之间。 列表中有重复的项目,但可能还有更多。 对于示例N = 3,列表[1,3,1,3]中的项目 我需要一种算法来打印重复的项目。(无论项目有多少次) 根据以上示例,结果为1,3 我需要Java中的一种解决方案,该解决方案可以处理堆砌(可以在短时间内运行许多项目)

我试图创建一个新的HashSet并将列表中的项目添加到集合中,如果它已经包含该项目,则将其保存到ArrayList中。

public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();

    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(1);
    list.add(2);
    list.add(5);

    Set<Integer> set = new HashSet();
    List<Integer> duplicatedList = new ArrayList<>();   

    for (Integer item : list) {
    if(set.contains(item)) {
        duplicatedList.add(item);
    }
    set.add(item);
}
System.out.println(duplicatedList +" "+ list);

它有效,但是我认为这不太有效。是否有针对此问题的更有效解决方案?

1 个答案:

答案 0 :(得分:1)

如果要限制堆的使用,请从原始列表中删除非重复项,而不是创建新列表。还可以使用BitSet来跟踪已经看到的数字。

List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,1,2,5));
int N = list.size() - 1;

BitSet present = new BitSet(N);
for (Iterator<Integer> iter = list.iterator(); iter.hasNext(); ) {
    int value = iter.next();
    if (! present.get(value)) {
        present.set(value);
        iter.remove();
    }
}
System.out.println(list);

输出

[1, 2]

如果原始列表是只读的,则构建一个有问题的新列表。

List<Integer> list = Arrays.asList(1,2,3,4,1,2,5);

BitSet present = new BitSet();
List<Integer> duplicatedList = new ArrayList<>();
for (Integer item : list) {
    if (present.get(item))
        duplicatedList.add(item);
    else
        present.set(item);
}
System.out.println(duplicatedList +" "+ list);

输出

[1, 2] [1, 2, 3, 4, 1, 2, 5]

主要改进是使用BitSet而不是Set<Integer>,这取决于数字范围限制在1到N之间的事实,因此使用的空间要少得多(除非在极端条件下)。