您将获得一个n + 2个元素的数组。数组的所有元素都在1到n的范围内。除了出现两次的两个数字外,所有元素都会出现一次。找到两个重复的数字。
例如,array = {4,2,4,5,2,3,1}和n = 5
伙计我知道这个问题的4个可能的解决方案,但最近我遇到了一个我无法解释的解决方案.Below是解决方案的算法
traverse the list for i= 1st to n+2 elements
{
check for sign of A[abs(A[i])] ;
if positive then
make it negative by A[abs(A[i])]=-A[abs(A[i])];
else // i.e., A[abs(A[i])] is negative
this element (ith element of list) is a repetition
}
Example: A[] = {1,1,2,3,2}
i=1 ; A[abs(A[1])] i.e,A[1] is positive ; so make it negative ;
so list now is {-1,1,2,3,2}
i=2 ; A[abs(A[2])] i.e., A[1] is negative ; so A[i] i.e., A[2] is repetition,
now list is {-1,1,2,3,2}
i=3 ; list now becomes {-1,-1,2,3,2} and A[3] is not repeated
now list becomes {-1,-1,-2,3,2}
i=4 ;
and A[4]=3 is not repeated
i=5 ; we find A[abs(A[i])] = A[2] is negative so A[i]= 2 is a repetition,
This method modifies the original array.
这个算法如何产生正确的结果,即它是如何工作的。人们不会把这作为一个家庭作业问题,因为这个问题最近在微软的采访中被提出过。
答案 0 :(得分:14)
您将获得一个n + 2数组 元素。数组的所有元素 在1到n的范围内。和所有元素 发生一次,除了两个数字 发生两次
让我们稍微修改一下,只使用n
,而不是n+2
和问题陈述的第一部分,它就变成了
你得到一个n数组 元素。数组的所有元素 在1到n的范围内
所以现在你知道你有一个数组,数组中的数字从1开始,并且对于数组中的每个项目都加一。因此,如果您有10个项目,则数组将包含1到10个数字,5个项目,1到5个等等。
接下来,存储在数组中的数字可用于索引数组。即,您可以随时说A[A[i]]
,其中i <= A的大小,例如A={5,3,4,1,2}; print A[A[2]]
现在,让我们添加一个重复的数字。 该算法获取数组中每个数字的值,并访问该索引。我们知道如果我们两次访问相同的索引,我们知道我们发现了重复 我们怎么知道我们是否两次访问同一指数? 是的,我们改变了我们访问的每个索引中的数字符号,如果符号已经改变,我们知道我们已经在这里,因此,这个索引(不是存储在索引中的值)是一个重复的数字。 / p>
你可以通过保留第二个布尔数组来实现相同的结果,初始化为false。那个algroithm变成了
A={123412}
B={false, false, false, false}
for(i = 1; i <= 4; i++)
{
if(B[A[i]])
// Duplicate
else
B[A[i]] = true;
}
然而,在MS问题中,您正在更改A中元素的符号,而不是在B中设置布尔值。
希望这有帮助,
答案 1 :(得分:2)
您正在做的是以两种方式使用数组值:它们具有数字并且它们具有符号。你“存储”了这样一个事实,即你在阵列的第n个位置看到了一个数字n
,而没有丢失那个位置的原始值:你只是在改变符号。
你从一切积极的事情开始,如果你发现你想要“保存”你已经看到你当前价值的事实已经是负面的事实,那么这个价值已经可以看到了。
例如: 因此,如果您第一次看到4,则将第四个点上的符号更改为负数。这并没有改变第四点,因为当你去那里时你正在使用[abs],所以不用担心。 如果你看到另外4个,你再次检查第4个位置,看它是否定的:presto:a double。
答案 2 :(得分:1)
当你在位置i找到一些元素时,让我们说n,然后你使A[abs(A(i))]=A[abs(n)]
为负。因此,如果您发现另一个包含n的位置j,您还将检查A[abs(A(j))]=A[abs(n)]
。既然你发现它是负面的,则重复n:)
答案 3 :(得分:0)
简单,使用Hashtable。
对于每个项目,检查它是否已经存在O(1),如果不存在,则将其添加到哈希表O(1)。
当你找到一个已经存在的项目时......就是这样。
答案 4 :(得分:0)
我知道这不是你问题的真正答案,但是如果我真的不得不在一个真实的项目中编写这个代码,我会从像quicksort这样的算法开始,并在我的比较函数中开始,/ p>
int Compare(int l, int r)
{
if(l == r)
{
// duplicate; insert into duplicateNumbers array if it doesn't exist already.
// if we found 2 dupes, quit the sort altogether
}
return r - l;
}
我会将此归结为可能的解决方案中的“性能和可维护性之间的良好平衡”。
答案 5 :(得分:0)
查找两个重复元素的最佳方法是使用 XOR 方法。
此解决方案仅适用于数组具有正整数且数组中的所有元素都在 1 到 n 范围内的情况。 正如我们所知 A XOR A = 0。我们在数组中有 n + 2 个元素,其中有 2 个重复元素(比如重复元素是 X 和 Y),并且我们知道元素的范围是从 1 到 n。 XOR 数组中从 1 到 n 的所有数字。结果是 X XOR Y。 1 XOR 1 = 0 和 1 XOR 0 = 1 与此逻辑在 X XOR Y 的结果中,如果任何第 k 位设置为 1,则意味着第 k 位在 X 中或在 Y 中都不是 1。 使用上述步骤将数组中的所有元素从 1 到 n 分为 2 组,一组具有第 k 位设置为 1 的元素,第二组具有第 k 位设置为 0 的元素。 让我们将第 k 位作为最右边的设置位(阅读如何找到最右边的设置位) 现在我们可以声称这两个组负责生产 X 和 Y。 Group -1:异或所有第 k 位为 1 的元素将产生 X 或 Y。 Group -2:XOR 所有第 k 位为 0 的元素将产生 X 或 Y。 请参阅下图以获得更多理解。(点击图表可放大)。
public class TwoRepeatingXOR {
public static void twoRepeating(int [] A, int n){
int XOR = A[0];
int right_most_bit, X=0, Y=0, size = A.length;
for (int i = 1; i <=n ; i++)
XOR ^= i;
for (int i = 0; i <size ; i++)
XOR ^= A[i];
//Now XOR contains the X XOR Y
//get the right most bit number
right_most_bit = XOR & ~(XOR-1);
//divide the elements into 2 groups based on the right most set bit
for (int i = 0; i <size ; i++) {
if((A[i] & right_most_bit)!=0)
X = X^A[i];
else
Y = Y^A[i];
}
for (int i = 1; i <=n ; i++) {
if((i&right_most_bit)!=0)
X = X^i;
else
Y = Y^i;
}
System.out.println("Two Repeated elements are: " + X + " and " + Y);
}
public static void main(String[] args) {
int [] A = {1,4,5,6,3,2,5,2};
int n = 6;
twoRepeating(A, n);
}
}