Algorithm 在数组中查找两个重复数字的算法,无需排序
有一个大小为n的数组(数字介于0和n-3之间),只有2个数字重复。元素随机放置在数组中 例如{2,3,6,1,5,4,0,3,5}n=9,重复的数字是3和5 找到重复数字的最佳方法是什么Algorithm 在数组中查找两个重复数字的算法,无需排序,algorithm,search,Algorithm,Search,有一个大小为n的数组(数字介于0和n-3之间),只有2个数字重复。元素随机放置在数组中 例如{2,3,6,1,5,4,0,3,5}n=9,重复的数字是3和5 找到重复数字的最佳方法是什么 注意[您不应该使用排序]对数组排序似乎是最好的解决方案。一个简单的排序将使搜索变得微不足道,并将占用更少的时间/空间 否则,如果您知道数字的域,请创建一个包含那么多bucket的数组,并在遍历数组时递增每个bucket。大概是这样的: int count [10]; for (int i = 0; i <
注意[您不应该使用排序]对数组排序似乎是最好的解决方案。一个简单的排序将使搜索变得微不足道,并将占用更少的时间/空间 否则,如果您知道数字的域,请创建一个包含那么多bucket的数组,并在遍历数组时递增每个bucket。大概是这样的:
int count [10];
for (int i = 0; i < arraylen; i++) {
count[array[i]]++;
}
int计数[10];
for(int i=0;i
然后只需在数组中搜索任何大于1的数字。这些是有重复项的项目。只需要在原始数组中传递一次,在计数数组中传递一次。对于每个数字:检查它是否存在于数组的其余部分。将每个元素插入集合/哈希表中,首先检查它是否已经存在。如果不进行排序,您将跟踪已访问的数字 在psuedocode中,这基本上是(这样做,所以我不只是给你答案): 如果您知道可能的输入域是什么,则有一个O(n)解决方案。例如,如果输入数组包含0到100之间的数字,请考虑下面的代码。
bool flags[100];
for(int i = 0; i < 100; i++)
flags[i] = false;
for(int i = 0; i < input_size; i++)
if(flags[input_array[i]])
return input_array[i];
else
flags[input_array[i]] = true;
bool标志[100];
对于(int i=0;i<100;i++)
标志[i]=假;
对于(int i=0;i
当然还有额外的内存,但这是最快的 检查这篇关于这个主题的旧而好的论文:
- (PDF)
编辑:正如其他人所指出的,结合平方和,你可以使用这个,我只是在计算中有点慢。好的,似乎我就是不能休息一下:) 最简解 当然,你不会像数学课教你解平方方程那样去解它 首先,以2^32的模计算所有值,即允许溢出。
然后检查对{p,q}:{0,S1},{1,S1-1}。。。根据表达式(2)查找候选项(由于模和平方运算,可能有2个以上)
最后检查找到的候选对象是否真的存在于数组中两次。这个怎么样:
for (i=0; i<n-1; i++) {
for (j=i+1; j<n; j++) {
if (a[i] == a[j]) {
printf("%d appears more than once\n",a[i]);
break;
}
}
}
for(i=0;i问题的一些答案:包含作为子问题的解决方案,您可以根据自己的目的采用这些解决方案
例如,这里有一个相关部分来自:
bool有多个重复项(int*a、int m、int n)
{
/**O(m)在时间上,O(1)在空间上(对于'typeof(m)==typeof(*a)==int')
[]数组是否有重复项。
前提条件:所有值都在[n,n+m)范围内。
功能:它使用符号位标记访问的项目。
*/
断言((INT_MIN-(INT_MIN-1))==1);//检查n==INT_MIN
对于(int*p=a;p!=&a[m];++p){
*p-=(n-1);//[n,n+m)->[1,m+1)
断言(*p>0);
}
//确定:是否存在重复项
bool has_dups=false;
对于(int i=0;i=0);
断言(j0)
a[j]*=-1;//标记
否则{//已经看到了
has_dups=true;
打破
}
}
//恢复阵列
对于(int*p=a;p!=&a[m];++p){
如果(*p<0)
*p*=-1;//取消标记
//[1,m+1)->[n,n+m)
*p+=(n-1);
}
返回已重复;
}
程序保持数组不变(数组应该是可写的,但其值在退出时恢复)
它适用于高达INT_MAX
(在64位系统上为9223372036854775807
)的数组大小。您知道数组包含从0到n-3的每个数字以及两个重复的数字(p&q)。为简单起见,现在忽略0大小写
您可以计算数组上的和和与积,结果是:
1 + 2 + ... + n-3 + p + q = p + q + (n-3)(n-2)/2
如果你从整个数组的和中减去(n-3)(n-2)/2,你得到
sum(Array) - (n-3)(n-2)/2 = x = p + q
现在对产品执行相同的操作:
1 * 2 * ... * n - 3 * p * q = (n - 3)! * p * q
prod(Array) / (n - 3)! = y = p * q
您现在可以使用以下术语:
x = p + q
y = p * q
=> y(p + q) = x(p * q)
如果你转换这个术语,你应该能够计算p和q这是Python of的答案(它的一个修订版)的实现,它不使用模运算。它是一个单通算法,O(log(n))在空间中。如果固定宽度(例如32位)如果使用整数,则它只需要两个固定宽度的数字(例如,对于32位:一个64位数字和一个128位数字)。它可以处理任意大的整数序列(它一次读取一个整数,因此整个序列不需要存储在内存中)
例如:
>>> two_repeated([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
以上代码的更详细版本如下所示:
def two_repeated_seq(arr):
"""Return the only two duplicates from `arr`.
>>> two_repeated_seq([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
"""
n = len(arr)
assert all(0 <= i < n - 2 for i in arr) # all in range [0, n-2)
assert len(set(arr)) == (n - 2) # number of unique items
s1 = (n-2) + (n-1) # s1 and s2 have ~ 2*(k+1) and 4*(k+1) digits
s2 = (n-2)**2 + (n-1)**2 # where k is a number of digits in `max(arr)`
for i, j in enumerate(arr):
s1 += j - i
s2 += j*j - i*i
"""
s1 = (n-2) + (n-1) + sum(arr) - sum(range(n))
= sum(arr) - sum(range(n-2))
= sum(range(n-2)) + p + q - sum(range(n-2))
= p + q
"""
assert s1 == (sum(arr) - sum(range(n-2)))
"""
s2 = (n-2)**2 + (n-1)**2 + sum(i*i for i in arr) - sum(i*i for i in range(n))
= sum(i*i for i in arr) - sum(i*i for i in range(n-2))
= p*p + q*q
"""
assert s2 == (sum(i*i for i in arr) - sum(i*i for i in range(n-2)))
"""
s1 = p+q
-> s1**2 = (p+q)**2
-> s1**2 = p*p + 2*p*q + q*q
-> s1**2 - (p*p + q*q) = 2*p*q
s2 = p*p + q*q
-> p*q = (s1**2 - s2)/2
Let C = p*q = (s1**2 - s2)/2 and B = p+q = s1 then from Viete theorem follows
that p and q are roots of x**2 - B*x + C = 0
-> p = (B + sqrtD) / 2
-> q = (B - sqrtD) / 2
where sqrtD = sqrt(B**2 - 4*C)
-> p = (s1 + sqrt(2*s2 - s1**2))/2
"""
sqrtD = (2*s2 - s1**2)**.5
assert int(sqrtD)**2 == (2*s2 - s1**2) # perfect square
sqrtD = int(sqrtD)
assert (s1 - sqrtD) % 2 == 0 # even
p = (s1 - sqrtD) // 2
q = s1 - p
assert q == ((s1 + sqrtD) // 2)
assert sqrtD == (q - p)
return p, q
def两次重复(arr):
“”“从'arr'返回仅有的两个副本。”。
>>>两个重复序列([2,3,6,1,5,4,0,3,5])
(3, 5)
"""
n=长度(arr)
断言所有(0)假设数组为
a[0]、a[1]、a[2]……a[n-1]
sumA=a[0]+a[1]+..+a[n-1]
sumASquare=a[0]*a[0]+a[1]*a[1]+a[2]*a[2]+..+a[n]*a[n]
sumFirstN=(N*(N+1))/2其中N=N-3所以
sumFirstN=(n-3)(n-2)/2
同样地
sumFirstNSquare=N*(N+1)*(2*N+1)/6=(N-3)(N-2)(2n-5)/6
假设重复的元素为=X和Y
所以X+Y=sumA-sumFirstN;
X*X+Y*Y=苏马斯广场-苏马斯广场;
通过解这个二次方程,我们可以得到X和Y的值。
时间复杂度=O(n)
空间复杂度=O(1)
对于(i=1;i为什么我们要尝试做数学(特别是解二次方程)这些都是昂贵的运算。解决这一问题的最佳方法是构造一个大小为(n-3)位的位图,即,(n-3)+7/8字节。最好对这个内存执行calloc,这样每个位都将
1 * 2 * ... * n - 3 * p * q = (n - 3)! * p * q
prod(Array) / (n - 3)! = y = p * q
x = p + q
y = p * q
=> y(p + q) = x(p * q)
def two_repeated(iterable):
s1, s2 = 0, 0
for i, j in enumerate(iterable):
s1 += j - i # number_of_digits(s1) ~ 2 * number_of_digits(i)
s2 += j*j - i*i # number_of_digits(s2) ~ 4 * number_of_digits(i)
s1 += (i - 1) + i
s2 += (i - 1)**2 + i**2
p = (s1 - int((2*s2 - s1**2)**.5)) // 2
# `Decimal().sqrt()` could replace `int()**.5` for really large integers
# or any function to compute integer square root
return p, s1 - p
>>> two_repeated([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
def two_repeated_seq(arr):
"""Return the only two duplicates from `arr`.
>>> two_repeated_seq([2, 3, 6, 1, 5, 4, 0, 3, 5])
(3, 5)
"""
n = len(arr)
assert all(0 <= i < n - 2 for i in arr) # all in range [0, n-2)
assert len(set(arr)) == (n - 2) # number of unique items
s1 = (n-2) + (n-1) # s1 and s2 have ~ 2*(k+1) and 4*(k+1) digits
s2 = (n-2)**2 + (n-1)**2 # where k is a number of digits in `max(arr)`
for i, j in enumerate(arr):
s1 += j - i
s2 += j*j - i*i
"""
s1 = (n-2) + (n-1) + sum(arr) - sum(range(n))
= sum(arr) - sum(range(n-2))
= sum(range(n-2)) + p + q - sum(range(n-2))
= p + q
"""
assert s1 == (sum(arr) - sum(range(n-2)))
"""
s2 = (n-2)**2 + (n-1)**2 + sum(i*i for i in arr) - sum(i*i for i in range(n))
= sum(i*i for i in arr) - sum(i*i for i in range(n-2))
= p*p + q*q
"""
assert s2 == (sum(i*i for i in arr) - sum(i*i for i in range(n-2)))
"""
s1 = p+q
-> s1**2 = (p+q)**2
-> s1**2 = p*p + 2*p*q + q*q
-> s1**2 - (p*p + q*q) = 2*p*q
s2 = p*p + q*q
-> p*q = (s1**2 - s2)/2
Let C = p*q = (s1**2 - s2)/2 and B = p+q = s1 then from Viete theorem follows
that p and q are roots of x**2 - B*x + C = 0
-> p = (B + sqrtD) / 2
-> q = (B - sqrtD) / 2
where sqrtD = sqrt(B**2 - 4*C)
-> p = (s1 + sqrt(2*s2 - s1**2))/2
"""
sqrtD = (2*s2 - s1**2)**.5
assert int(sqrtD)**2 == (2*s2 - s1**2) # perfect square
sqrtD = int(sqrtD)
assert (s1 - sqrtD) % 2 == 0 # even
p = (s1 - sqrtD) // 2
q = s1 - p
assert q == ((s1 + sqrtD) // 2)
assert sqrtD == (q - p)
return p, q
suppose array is
a[0], a[1], a[2] ..... a[n-1]
sumA = a[0] + a[1] +....+a[n-1]
sumASquare = a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + .... + a[n]*a[n]
sumFirstN = (N*(N+1))/2 where N=n-3 so
sumFirstN = (n-3)(n-2)/2
similarly
sumFirstNSquare = N*(N+1)*(2*N+1)/6 = (n-3)(n-2)(2n-5)/6
Suppose repeated elements are = X and Y
so X + Y = sumA - sumFirstN;
X*X + Y*Y = sumASquare - sumFirstNSquare;
So on solving this quadratic we can get value of X and Y.
Time Complexity = O(n)
space complexity = O(1)
for(i=1;i<=n;i++) {
if(!(arr[i] ^ arr[i+1]))
printf("Found Repeated number %5d",arr[i]);
}
int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
using namespace std;
main()
{
//int arr[] = {2, 9, 6, 1, 1, 4, 2, 3, 5};
int arr[] = {1,1,2,10,3,3,4,5,5,6,6};
int i = 0;
vector<int> vec;
int var = arr[0];
for(i = 1 ; i < sizeof(arr)/sizeof(arr[0]); i += 2)
{
var = var ^ arr[i];
if(var != 0 )
{
//put in vector
var = arr[i-1];
vec.push_back(var);
i = i-1;
}
var = arr[i+1];
}
for(int i = 0 ; i < vec.size() ; i++)
printf("value not repeated = %d\n",vec[i]);
}
value not repeated= 2
value not repeated= 10
value not repeated= 4
int arr[] = {2, 3, 6, 1, 5, 4, 0, 3, 5};
int num = 0, i;
for (i=0; i < 8; i++)
num = num ^ arr[i] ^i;
int[] numArray = new int[] { 1, 2, 3, 4, 5, 7, 8, 3, 7 };
for (int i = 0; i < numArray.Length; i++)
{
for (int j = i + 1; j < numArray.Length; j++)
{
if (numArray[i] == numArray[j])
{
//DO SOMETHING
}
}
int[] array = { 1, 2, 3, 4, 5, 4, 4, 1, 8, 9, 23, 4, 6, 8, 9, 1,4 };
int[] myNewArray = null;
int a = 1;
void GetDuplicates(int[] array)
for (int i = 0; i < array.Length; i++)
{
for (int j = i + 1; j < array.Length; j++)
{
if (array[i] == array[j])
{
a += 1;
}
}
Console.WriteLine(" {0} occurred {1} time/s", array[i], a);
IEnumerable<int> num = from n in array where n != array[i] select n;
myNewArray = null;
a = 1;
myNewArray = num.ToArray() ;
break;
}
GetDuplicates(myNewArray);
Bucket 0 : Sum ( x where: x & 2 power 0 == 0 )
...
Bucket i : Sum ( x where: x & 2 power i == 0 )
A XOR B = Array[i] XOR Array[i-1] XOR ... 0, XOR n-3 XOR n-2 ... XOR 0
for(i=0;i< n;i++)
xor=xor^arr[i]
for(i=1;i<=n-3;i++)
xor=xor^i;
xor=xor & -xor //Isolate the last digit
for(i = 0; i < n; i++)
{
if(arr[i] & xor)
x = x ^ arr[i];
else
y = y ^ arr[i];
}
for(i = 1; i <= n-3; i++)
{
if(i & xor)
x = x ^ i;
else
y = y ^ i;