Arrays 如何在洗牌连续整数数组中找到重复元素?
我最近在某个地方遇到了一个问题: 假设您有一个1001个整数的数组。整数是按随机顺序排列的,但您知道每个整数都在1和1000之间(包括1和1000)。此外,每个数字在数组中只出现一次,只有一个数字出现两次。假设您只能访问数组的每个元素一次。描述一个算法来寻找重复的数字。如果您在算法中使用了辅助存储,您能找到不需要它的算法吗Arrays 如何在洗牌连续整数数组中找到重复元素?,arrays,algorithm,duplicates,Arrays,Algorithm,Duplicates,我最近在某个地方遇到了一个问题: 假设您有一个1001个整数的数组。整数是按随机顺序排列的,但您知道每个整数都在1和1000之间(包括1和1000)。此外,每个数字在数组中只出现一次,只有一个数字出现两次。假设您只能访问数组的每个元素一次。描述一个算法来寻找重复的数字。如果您在算法中使用了辅助存储,您能找到不需要它的算法吗 我想知道的是第二部分,即不使用辅助存储器的。你有什么想法吗?只要把它们全部加起来,然后减去如果只使用1001个数字所期望的总数 例如: 把所有的数字加起来。最后的总和将是1+
我想知道的是第二部分,即不使用辅助存储器的。你有什么想法吗?只要把它们全部加起来,然后减去如果只使用1001个数字所期望的总数 例如:
把所有的数字加起来。最后的总和将是1+2+…+1000+个重复的数字。将所有数字相加。整数1..1000之和为(1000*1001)/2。与你得到的不同的是你的数字。如果你知道我们有确切的数字1-1000,你可以将结果相加,然后从总数中减去
500500
(sum(11000)
)。这将给出重复数,因为有一种非常简单的方法可以做到这一点。。。1到1000之间的每个数字只出现一次,重复出现的数字除外。。。。1…1000的和是500500。因此,算法是:
sum = 0
for each element of the array:
sum += that element of the array
number_that_occurred_twice = sum - 500500
总和=0
对于数组的每个元素:
sum+=数组的该元素
发生两次的次数=总和-500500
无额外存储需求(循环变量除外)
int length=(sizeof数组)/(sizeof数组[0]);
for(int i=1;i
参数和调用堆栈是否算作辅助存储
int-sumlaining(int*remaining,int-count){
如果(!计数){
返回0;
}
返回剩余[0]+sumlaining(剩余+1,计数-1);
}
printf(“重复的是%d”,剩余的(数组,1001)-500500);
编辑:尾部调用版本
int-sumselaining(int*remaining,int-count,int-sumSoFar){
如果(!计数){
返回苏姆索法;
}
返回sumsalving(剩余+1,计数-1,sumSoFar+剩余[0]);
}
printf(“重复的是%d”,剩余的(数组,1001,0)-500500);
更新2:有些人认为使用XOR查找重复的数字是一种欺骗。对此,我的官方回应是:“我不是在寻找一个重复的数字,我是在一个位集数组中寻找一个重复的模式。XOR绝对比添加操作位集更合适。”——)
更新:在我睡觉之前,为了好玩,这里有一个“一线”替代解决方案,它不需要额外存储(甚至不需要循环计数器),只接触每个阵列元素一次,是非破坏性的,并且根本不可扩展:-)
printf(“答案:%d\n”,
数组[0]^
数组[1]^
数组[2]^
//继续键入。。。
数组[999]^
数组[1000]^
1 ^
2 ^
//继续键入。。。
999^
1000
);
请注意,编译器将在编译时实际计算该表达式的后半部分,因此“算法”将在1002次操作中执行
如果在编译时也知道数组元素的值,编译器会将整个语句优化为一个常量。:-)
原始解决方案:不符合问题的严格要求,即使它可以找到正确答案。它使用一个额外的整数来保持循环计数器,并访问每个数组元素三次——两次在当前迭代中读取和写入,一次在下一次迭代中读取
在遍历数组时,至少需要一个附加变量(或CPU寄存器)来存储当前元素的索引
除此之外,这里还有一个破坏性算法,可以安全地将任意N扩展到MAX_INT
for(int i=1;i<1001;i++)
{
数组[i]=数组[i]^array[i-1]^i;
}
printf(“答案:%d\n”,数组[1000]);
我将把弄明白为什么这一点的练习留给您,并给出一个简单的提示:-):
a^a=0
0^a=a
来解释弗朗西斯·佩诺夫的解决方案
(通常)问题是:给定一个任意长度的整数数组,该数组只包含重复了偶数次的元素,除了一个重复了奇数次的值,求出该值
解决办法是:
acc = 0
for i in array: acc = acc ^ i
你目前的问题是适应。诀窍是你要找到重复两次的元素,所以你需要调整解决方案来弥补这个怪癖
acc = 0
for i in len(array): acc = acc ^ i ^ array[i]
这就是Francis的解决方案最终所做的,尽管它破坏了整个阵列(顺便说一句,它只能破坏第一个或最后一个元素…)
但是,由于索引需要额外的存储空间,我认为如果您还使用了一个额外的整数,您将被原谅。。。这种限制很可能是因为他们想阻止您使用数组
如果他们需要
O(1)
空间(1000可以被视为N,因为它是任意的)。Franci Penov的非破坏性解决方案
这可以通过使用XOR
运算符来完成
假设我们有一个大小为5
的数组:4,3,1,2,2
它们位于索引中:
0,1,2,3,4
现在对所有元素和所有索引执行异或。我们得到2
,它是重复的元素。这个哈
acc = 0
for i in len(array): acc = acc ^ i ^ array[i]
n = 1000
s = sum(GivenList)
r = str(n/2)
duplicate = int( r + r ) - s
n = 1000
s = sum(GivenList)
r = str(n/2)
duplicate = int( r + r ) - s
for i=0 to n-1
begin:
diff = a[i]-i;
dup = dup + diff;
end
// where dup is the duplicate element..
SUM = mySum + x + y;
PROD = myProd* x*y;
x*y = PROD/myProd; x+y = SUM - mySum;
private static int findDuplicated(int[] array) {
if (array == null || array.length < 2) {
System.out.println("invalid");
return -1;
}
int[] checker = new int[array.length];
Arrays.fill(checker, -1);
for (int i = 0; i < array.length; i++) {
int value = array[i];
int checked = checker[value];
if (checked == -1) {
checker[value] = value;
} else {
return value;
}
}
return -1;
}
private static int findDuplicatedWithoutAux(int[] array) {
if (array == null || array.length < 2) {
System.out.println("invalid");
return -1;
}
for (int i = 0; i < array.length; i++) {
int value = array[i];
for (int j = i + 1; j < array.length; j++) {
int toCompare = array[j];
if (value == toCompare) {
return array[i];
}
}
}
return -1;
}