Arrays 如何在洗牌连续整数数组中找到重复元素?

Arrays 如何在洗牌连续整数数组中找到重复元素?,arrays,algorithm,duplicates,Arrays,Algorithm,Duplicates,我最近在某个地方遇到了一个问题: 假设您有一个1001个整数的数组。整数是按随机顺序排列的,但您知道每个整数都在1和1000之间(包括1和1000)。此外,每个数字在数组中只出现一次,只有一个数字出现两次。假设您只能访问数组的每个元素一次。描述一个算法来寻找重复的数字。如果您在算法中使用了辅助存储,您能找到不需要它的算法吗 我想知道的是第二部分,即不使用辅助存储器的。你有什么想法吗?只要把它们全部加起来,然后减去如果只使用1001个数字所期望的总数 例如: 把所有的数字加起来。最后的总和将是1+

我最近在某个地方遇到了一个问题:

假设您有一个1001个整数的数组。整数是按随机顺序排列的,但您知道每个整数都在1和1000之间(包括1和1000)。此外,每个数字在数组中只出现一次,只有一个数字出现两次。假设您只能访问数组的每个元素一次。描述一个算法来寻找重复的数字。如果您在算法中使用了辅助存储,您能找到不需要它的算法吗


我想知道的是第二部分,即不使用辅助存储器的。你有什么想法吗?

只要把它们全部加起来,然后减去如果只使用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;
}