數組a[N],1至N-1這N-1個數存放在a[N]中,其中某個數重復一次,寫一個函數, 找出被重復的數字。要求每個數組元素只能訪問一次,不用輔助存儲空間。
由於題目要求每個數組元素只能訪問一次,不用輔助存儲空間,可以從原理上入手,采用數學求和法,因為只有一個數字重復一次,而數又是連續的,根據累加和原理,對數組的所有項求和,然后減去1至N-1的和,即為所求的重復數。程序代碼如下:
#include "stdafx.h"
#include <stdio.h>
void xor_findDup(int *a, int N)
{
int tmp1 = 0;
int tmp2 = 0;
for (int i = 0; i < N - 1; ++i)
{
tmp1 += (i + 1);
tmp2 += a[i];
}
tmp2 += a[N - 1];
int result = tmp2 - tmp1;
printf("%d\n", result);
}
int main()
{
int a[] = { 1, 2, 1, 3, 4 };
xor_findDup(a, 5);
getchar();
return 0;
}
效果如圖:

如果題目沒有要求每個數組元素只能訪問一次,不用輔助存儲空間,還可以用異或法和位圖法來求解。
(1)異或法
根據異或法的計算方式,每兩個相異的數執行異或運算之后,結果為1;每兩個相同的數異或之后,結果為0,任何數與0異或,結果仍為自身。所以數組a[N]中的N個數異或結果與1至N-1異或的結果再做異或,得到的值即為所求。
設重復數為A,其余N-2個數異或結果為B,N個數異或結果為A^A^B,1至N-1異或結果為A^B,由於異或滿足交換律和結合律,且X^X=0,0^X=X,則有(A^B)^(A^A^B)=A^B^B=A.
程序代碼如下:
#include "stdafx.h"
#include <stdio.h>
void xor_findDup(int * a, int N)
{
int i;
int result = 0;
for (i = 0; i < N; i++)
{
result ^= a[i];
}
for (i = 1; i < N; i++)
{
result ^= i;
}
printf("%d\n", result);
}
int main()
{
int a[] = { 1, 2, 1, 3, 4 };
xor_findDup(a, 5);
getchar();
return 0;
}
(2)位圖法。
位圖法的原理是首先申請一個長度為N-1且均為’0’組成的字符串,字符串的下標即為數組a[]中的元素,然后從頭開始遍歷數組a[N],取每個數組元素a[j]的值,將其對應的字符串中的對應位置置1,如果已經置過1,那么該數就是重復的數。由於采用的是位圖法,所以空間復雜度比較大,為O(N).
程序示例如下:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
void xor_findDup(int * arr, int NUM)
{
int *arrayflag = (int *)malloc(NUM*sizeof(int));
int i = 1;
while (i < NUM)
{
arrayflag[i] = false;
i++;
}
for (i = 0; i < NUM; i++)
{
if (arrayflag[arr[i]] == false)
{
arrayflag[arr[i]] = true;
}
else
{
printf("%d\n", arr[i]);
return;
}
}
}
int main()
{
int a[] = { 1, 2, 1, 3, 4 };
xor_findDup(a, 5);
getchar();
return 0;
}
