我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字
Posted
技术标签:
【中文标题】我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字【英文标题】:How can we find a repeated number in array in O(n) time and O(1) space complexity 【发布时间】:2011-09-10 10:02:44 【问题描述】:我们如何在 O(n) 时间和 O(1) 复杂度内找到数组中的重复数字? 例如 数组 2,1,4,3,3,10 输出为 3
编辑: 我尝试了以下方式。 我发现如果 no 奇怪地重复,那么我们可以通过执行 xor 来实现结果。所以我想使奇数的元素不重复甚至不重复,并且每个均匀重复的不重复。但是为此,我需要从 O(n) 中的输入数组中找出唯一的元素数组,但找不到方法。
【问题讨论】:
空间复杂度为 O(1) 我不知道你为什么有data-structures
标签。
【参考方案1】:
假设数组中的数字值有一个上限(我曾经使用过的所有编程语言中的所有内置整数类型都是这种情况——例如,假设它们是 32 -bit 整数)有一个使用常量空间的解决方案:
-
创建一个包含 N 个元素的数组,其中 N 是输入数组中整数值的上限,并将所有元素初始化为
0
或 false
或类似的值。我将其称为 lookup 数组。
循环输入数组,并使用每个数字来索引查找数组。如果您找到的值为1
或true
(等),则输入数组中的当前数字是重复的。
否则,将查找数组中的对应值设置为1
或true
,以记住我们已经看到了这个特定的输入数字。
技术上,这是 O(n) 时间和 O(1) 空间,它不会破坏输入数组。实际上,您需要按自己的方式运行这样的程序才能真正运行(例如,如果在输入中谈论 64 位整数是不可能的)。
【讨论】:
是的,我也想到了那个解决方案,但复杂度是 O(K*n),其中 k 不是比特数。如果 k>logn,那么 O(nlogn) 将是有效的解决方案。 这个解决方案在空间中的 O(1) 怎么样?如果我们有 0,1,2,3... 2^32-1,2^32-1 作为输入,则需要一个大小为 2^32 位的数组,大小等于 = 2^27 个整数.这肯定不是 O(1)。 @NitinGarg:你对 O(1) 的定义是错误的。这个解决方案需要一个大小为2^32
的数组不管输入是什么,因此它是O(1)。
@Jon - 通过同样的技术,您可以迭代数组 2^32 次,每次迭代都会查找单个数字的重复项(仅使用布尔值来存储我是否找到了一个,并且如果我找到另一个,那么我有一个副本)。从技术上讲,它是 O(n),当然也是 O(1) 空间。
@Jon - 对于整数排序,我可以创建一个包含 2^32 个元素的数组 X,所有元素都初始化为 0。现在我遍历整数的原始序列 (a1,a2...ai. .. a) 并在每一步将 X[ai] 加 1。最后,我只需要在 X 上进行一个循环,花费 n + 2^32(恒定时间)来获得排序后的序列。【参考方案2】:
如果不了解数组中可能的值的更多信息,您将无法做到。
对于 O(1) 空间要求,最快的方法是对数组进行排序,使其至少为 O(n*log(n))。
【讨论】:
【参考方案3】:使用位操作...在一个循环中遍历列表。
-
通过移动 i 的值来检查掩码是否为 1。
如果是这样,打印出重复值 i。
如果未设置该值,请设置它。
*如果您只想显示一个重复值一次,请添加另一个整数显示并设置其位,如下例所示。
**这是在 java 中,我不确定我们是否会达到它,但您可能还想使用 Integer.MAX_VALUE 添加检查。
public static void repeated( int[] vals )
int mask = 0;
int show = 0;
for( int i : vals )
// get bit in mask
if( (( mask >> i ) & 1) == 1 &&
(( show >> i ) & 1) == 0 )
System.out.println( "\n\tfound: " + i );
show = show | (1 << i);
// set mask if not found
else
mask = mask | (1 << i);
System.out.println( "new: " + i );
System.out.println( "mask: " + mask );
【讨论】:
别忘了这个逻辑只有在你有一种类型的值时才有效,要么都是正的,要么是负的。对于 (-17, 15) 等值,上述操作将失败【参考方案4】:如果不知道有关输入数组的任何限制规则,这是不可能的,要么内存复杂度会依赖于输入大小,要么时间复杂度会更高。
上面的 2 个答案实际上是接近您所要求的最佳答案,一个权衡是时间,第二个权衡是在内存中,但您不能让它在 O(n) 时间和 O(1 ) 某些未知输入数组中的复杂性。
【讨论】:
【参考方案5】:我也遇到了这个问题,我的解决方案是使用 hashMap 。python 版本如下:
def findRepeatNumber(lists):
hashMap =
for i in xrange(len(lists)):
if lists[i] in hashMap:
return lists[i]
else:
hashMap[lists[i]]=i+1
return
【讨论】:
他想要一个 o(1) 空间。你的空间是 o(n) ;)【参考方案6】:只有当你有特定的数据时才有可能。例如,所有数字的范围都很小。然后您可以将重复信息存储在源数组中,而不影响整个扫描和分析过程。
简化示例:您知道所有数字都小于 100,然后您可以使用额外的零标记数字的重复计数,例如当 9 出现两次时将 900 代替 9。
当 NumMax-NumMin 时很容易
http://www.geeksforgeeks.org/find-the-maximum-repeating-number-in-ok-time/
【讨论】:
【参考方案7】:public static string RepeatedNumber()
int[] input = 66, 23, 34, 0, 5, 4;
int[] indexer = 0,0,0,0,0,0
var found = 0;
for (int i = 0; i < input.Length; i++)
var toFind = input[i];
for (int j = 0; j < input.Length; j++)
if (input[j] == toFind && (indexer[j] == 1))
found = input[j];
else if (input[j] == toFind)
indexer[j] = 1;
return $"most repeated item in the array is found";
【讨论】:
O(n^2) 时间【参考方案8】:你可以这样做
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void main ()
clrscr();
int array[5],rep=0;
for(int i=1; i<=5; i++)
cout<<"enter elements"<<endl;
cin>>array[i];
for(i=1; i<=5; i++)
if(array[i]==array[i+1])
rep=array[i];
cout<<" repeat value is"<<rep;
getch();
【讨论】:
你确定你得到答案了吗?如果重复的数字不在一起怎么办?以上是关于我们如何在 O(n) 时间和 O(1) 空间复杂度内找到数组中的重复数字的主要内容,如果未能解决你的问题,请参考以下文章