在包含重复项的无序数组中查找唯一元素

时间:2016-02-19 02:15:10

标签: python arrays algorithm big-o

例如,如果L = [1,4,2,6,4,3,2,6,3],那么我们希望1作为唯一元素。这是我想到的伪代码:

初始化字典以存储每个元素的出现次数:~O(n), 查看字典以查找值为1的元素:~O(n)

这确保总时间复杂度保持为O(n)。这看起来是正确的想法吗?

另外,如果对数组进行了排序,例如,时间复杂度会如何变化?我认为这将是二进制搜索的一些变体,它会将其减少到O(log n)。

5 个答案:

答案 0 :(得分:7)

您可以使用collections.Counter

from collections import Counter

uniques = [k for k, cnt in Counter(L).items() if cnt == 1]

复杂性永远是O(n)。您只需要遍历列表一次(这是Counter正在做的事情)。排序并不重要,因为字典分配总是O(1)。

答案 1 :(得分:7)

使用^运算符,有一个非常简单的解决方案是O(n):序列的XOR元素。变量的结束值将是唯一编号的值。

证明很简单:对一个数字进行异或后产生零,所以由于除了一个数字之外的每个数字都包含它自己的副本,因此对它们进行异或的净结果将为零。将唯一数字与零进行异或运算得出数字本身。

答案 2 :(得分:1)

您概述的算法基本上是正确的,这是@BrendanAbel基于Counter的解决方案所做的。我鼓励您在没有Counter的情况下自己实施算法,这是一个很好的练习。

即使数组已排序,也不能击败O(n)(除非数组按出现次数排序!)。唯一元素可以在数组中的任何位置,直到找到它,您无法缩小搜索空间(与二进制搜索不同,您可以在每次测试中消除剩余可能性的一半)。

答案 3 :(得分:1)

在一般情况下,重复项可以存在多次,我不认为您可以将复杂性降低到 O(N)以下,但对于特殊情况, dasblinkenlight 的答案,人们可​​以做得更好。

如果数组已经排序,如果存在重复项偶数次,就像所示的简单示例中的情况一样,您可以在中找到唯一元素二进制搜索的 O(log N)时间。您将搜索a[2*n] != a[2*n+1]

的位置
size_t find_unique_index(type *array, size_t size) {
    size_t a = 0, b = size / 2;
    while (a < b) {
        size_t m = (a + b) / 2;
        if (array[2 * m] == array[2 * m + 1]) {
            /* the unique element is the the right half */
            a = m + 1;
        } else {
            b = m;
        }
    }
    return array[2 * m];
}

答案 4 :(得分:-1)

如果已经对数组进行了排序,则可以使用二进制搜索的变体。它会将您的成本降低到 O(lg N)。你只需要搜索左右适当的位置。这是你的问题的C / C ++实现。(我假设数组已经排序)

#include<stdio.h>
#include<stdlib.h>

// Input: Indices Range [l ... r)
// Invariant: A[l] <= key and A[r] > key
int GetRightPosition(int A[], int l, int r, int key)
{
    int m;

    while( r - l > 1 )
    {
        m = l + (r - l)/2;

        if( A[m] <= key )
            l = m;
        else
            r = m;
    }

    return l;
}

// Input: Indices Range (l ... r]
// Invariant: A[r] >= key and A[l] > key
int GetLeftPosition(int A[], int l, int r, int key)
{
    int m;

    while( r - l > 1 )
    {
        m = l + (r - l)/2;

        if( A[m] >= key )
            r = m;
        else
            l = m;
    }

    return r;
}

int CountOccurances(int A[], int size, int key)
{
    // Observe boundary conditions
    int left = GetLeftPosition(A, 0, size, key);
    int right = GetRightPosition(A, 0, size, key);


    return (A[left] == key && key == A[right])?
        (right - left + 1) : 0;
 }
int main() {
    int arr[] = {1,1,1,2,2,2,3};
    printf("%d",CountOccurances(arr,7,2));
    return 0;
}