在不使用哈希表的情况下从Array中删除重复项

时间:2010-12-09 06:57:04

标签: arrays algorithm duplicates

我有一个可能包含重复元素的数组(元素的两个以上重复)。我想知道是否有可能找到并删除数组中的重复项:

  • 不使用哈希表(严格要求)
  • 不使用临时辅助数组。对复杂性没有限制。

P.S 这不是主页工作问题

在雅虎的技术采访中被问到我的朋友

7 个答案:

答案 0 :(得分:8)

对源数组进行排序。找到相等的连续元素。 (即std::unique在C ++中的作用)。总复杂度为N lg N,如果输入已经排序,则仅为N.

要删除重复项,您可以在线性时间内从数组中较早的元素复制数组中较晚的元素。只需保留指向容器新逻辑端的指针,并在每一步将下一个不同元素复制到该新逻辑端。 (再次,与std::unique完全一样(事实上,为什么不下载 an implementation of std::unique并完全按照它做的做法?:P))

答案 1 :(得分:5)

O(NlogN):用一个副本对连续的相同元素进行排序和替换。

O(N 2 ):运行嵌套循环以将每个元素与数组中的其余元素进行比较,如果找到重复,则将副本与数组末尾的元素交换并减少数组大小为1.

答案 2 :(得分:3)

  

对复杂性没有限制。

所以这是小菜一碟。

// A[1], A[2], A[3], ... A[i], ... A[n]

// O(n^2)
for(i=2; i<=n; i++)
{
    duplicate = false;
    for(j=1; j<i; j++)
        if(A[i] == A[j])
             {duplicate = true; break;}
    if(duplicate)
    {
        // "remove" A[i] by moving all elements from its left over it
        for(j=i; j<n; j++)
            A[j] = A[j+1];
        n--;
    }
}

答案 3 :(得分:2)

在二次时间内保留列表现有顺序的就地重复删除:

for (var i = 0; i < list.length; i++) {
  for (var j = i + 1; j < list.length;) {
    if (list[i] == list[j]) {
      list.splice(j, 1);
    } else {
      j++;
    }
  }
}

诀窍是在i + 1上启动内循环,而在删除元素时不增加内部计数器。

代码是JavaScript,splice(x, 1)删除了x的元素。

如果订单保存不是问题,那么您可以更快地完成:

list.sort();

for (var i = 1; i < list.length;) {
  if (list[i] == list[i - 1]) {
    list.splice(i, 1);
  } else {
    i++;
  }
}

哪个是线性的,除非你计算排序,你应该这样,所以它是排序的顺序 - 在大多数情况下是n×log(n)。

答案 4 :(得分:1)

在函数式语言中,您可以在一次传递中将排序和统一(这是一个真正的单词吗?)结合起来。 我们采用标准的快速排序算法:

- Take the first element of the input (x) and the remaining elements (xs)
- Make two new lists
- left: all elements in xs smaller than or equal to x
- right: all elements in xs larger than x
- apply quick sort on the left and right lists
- return the concatenation of the left list, x, and the right list
- P.S. quick sort on an empty list is an empty list (don't forget base case!)

如果您只想要唯一条目,请替换

left: all elements in xs smaller than or equal to x

left: all elements in xs smaller than x

这是一次通过O(n log n)算法。

F#中的示例实现:

let rec qsort = function
    | [] -> []
    | x::xs -> let left,right = List.partition (fun el -> el <= x) xs
               qsort left @ [x] @ qsort right

let rec qsortu = function
    | [] -> []
    | x::xs -> let left = List.filter (fun el -> el < x) xs
               let right = List.filter (fun el -> el > x) xs
               qsortu left @ [x] @ qsortu right

以交互模式进行测试:

> qsortu [42;42;42;42;42];;
val it : int list = [42]
> qsortu [5;4;4;3;3;3;2;2;2;2;1];;
val it : int list = [1; 2; 3; 4; 5]
> qsortu [3;1;4;1;5;9;2;6;5;3;5;8;9];;
val it : int list = [1; 2; 3; 4; 5; 6; 8; 9]

答案 5 :(得分:0)

由于这是一个面试问题,面试官通常会要求他们对这个问题进行精确处理。

由于不允许使用替代存储(即允许使用O(1)存储,因此您可能会使用某些计数器/指针),显然预计会发生破坏性操作,因此可能值得向面试官指出

现在真正的问题是:你想保留元素的相对顺序吗?即这个操作应该稳定吗?

稳定性极大地影响了可用的算法(从而影响了复杂性)。

最明显的选择是列出Sorting Algorithms,毕竟,一旦数据被排序,就很容易获得独特的元素。

但是如果你想要稳定性,你实际上不能对数据进行排序(因为你无法得到“正确”的顺序),因此我想知道如果涉及稳定性,它是否可以在小于O(N ** 2)的情况下解决。

答案 6 :(得分:0)

本身不使用哈希表,但我知道幕后它是一个哈希表的实现。不过,我想可以发帖,以防它可以提供帮助。这是在JavaScript中,并使用关联数组来记录重复项以传递

function removeDuplicates(arr) {
    var results = [], dups = []; 

    for (var i = 0; i < arr.length; i++) {

        // check if not a duplicate
        if (dups[arr[i]] === undefined) {

            // save for next check to indicate duplicate
            dups[arr[i]] = 1; 

            // is unique. append to output array
            results.push(arr[i]);
        }
    }

    return results;
}