例如,如果L = [1,4,2,6,4,3,2,6,3],那么我们希望1作为唯一元素。这是我想到的伪代码:
初始化字典以存储每个元素的出现次数:~O(n), 查看字典以查找值为1的元素:~O(n)
这确保总时间复杂度保持为O(n)。这看起来是正确的想法吗?
另外,如果对数组进行了排序,例如,时间复杂度会如何变化?我认为这将是二进制搜索的一些变体,它会将其减少到O(log n)。
答案 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;
}