數組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; }