找出數組中唯一重復的數(轉)
阿新 • • 發佈:2017-08-14
置1 while repos += 一個 交換 ack 得到 最大數
題目:
數組a[N],1至N-1這N-1個數存放在a[N]中,其中某個數重復一次。寫一個函數,找出被重復的數字。
方法一:異或法。
數組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 <stdio.h> #include <stdlib.h> #include <math.h> #include<time.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 argc, char* argv[]) { int a[] = {1,2,1,3,4}; xor_findDup(a,5); return 0; }
方法二:數學法。
對數組的所有項求和,減去1至N-1的和,即為所求數。
#include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.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 argc, char* argv[]) { int a[] = {1,2,4,3,4}; xor_findDup(a,5); return 0; }
對於求和,可以直接根據公式定義一個宏。#define sum(x) (x*(x+1)/2)
#include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.h> #define sum(x) (x*(x+1)/2) void xor_findDup(int * a,int N) { int tmp1 = sum((N-1));//註意N-1要加括號 int tmp2 = 0; for (int i=0; i<N; ++i) { tmp2+=a[i]; } int result=tmp2-tmp1; printf("%d\n",result); } int main(int argc, char* argv[]) { int a[] = {1,2,4,2,3}; xor_findDup(a,5); return 0; }
方法三:標誌數組法
申請一個長度為n-1且均為‘0‘組成的字符串。然後從頭遍歷a[n]數組,取每個數組元素a[i]的值,將其對應的字符串中的相應位置置1,如果已經置過1的話,那麽該數就是重復的數。就是用位圖來實現的。 如果考慮空間復雜度的話,其空間O(N)
#include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.h> #define sum(x) (x*(x+1)/2) 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 argc, char* argv[]) { int a[] = {1,3,2,4,3}; xor_findDup(a,5); return 0; }
方法四:固定偏移量法
a[N],裏面是1至N-1。原數組a[i]最大是N-1,若a[i]=K在某處出現後,將a[K]加一次N,做標記,當某處a[i]=K再次成立時,查看a[K]即可知道K已經出現過。該方法不用另外開辟O(N)的內存空間,但是在查重之後要將數組進行恢復。
#include <stdio.h> #include <stdlib.h> #include <math.h> #include<time.h> void xor_findDup(int * arr,int NUM) { int temp=0; for(int i=0; i<NUM; i++) { if(arr[i]>=NUM) temp=arr[i]-NUM; // 該值重復了,因為曾經加過一次了 else temp=arr[i]; if(arr[temp]<NUM) { arr[temp]+=NUM; //做上標記 } else { printf("有重復 %d\n",temp); return; } } printf("無重復"); return ; } void clear(int *data,int num)//清理數據 { for(int i=0;i<num;i++) { if(data[i]>num) data[i]-=num; } } int main(int argc, char* argv[]) { int a[] = {2,4,3,4,1}; xor_findDup(a,5); clear(a,5); return 0; }
方法五:符號標誌法
上個方法出現後是加N,也可以出現後加個負號,就是符號標誌法。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include<time.h> void xor_findDup(int * arr,int NUM) { int temp=0; for(int i=0; i<NUM; i++) { if(arr[i]<0) temp=0-arr[i]; // 該值重復了,因為曾經加過一次了 else temp=arr[i]; if(arr[temp]>0) { arr[temp]=0-arr[temp]; //做上標記 } else { printf("有重復 %d\n",temp); return; } } printf("無重復"); return ; } void clear(int *data,int num)//清理數據 { for(int i=0;i<num;i++) { if(data[i]<0) data[i]=0-data[i]; } } int main(int argc, char* argv[]) { int a[] = {3,2,1,4,1}; xor_findDup(a,5); clear(a,5); return 0; }
以上的方法對數組元素的值的範圍是有限制的,如果數組元素的值不是在1至N-1範圍時,可以先求出數組元素的最大值。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include<time.h> int do_dup_mal(int arr[], int n, int *pre, int *back) { int MAX = -1; int i = 0; int sameVal = -1; *pre = *back = -1; for (int j=0; j<n; j++) { if (arr[j] > MAX) MAX = arr[j];//找出數組中的最大數 } char *arrayflag = new char[MAX+1] ; if (NULL == arrayflag) return -1; memset(arrayflag, 0, MAX+1 ); // ‘\0‘ == 0 for(i=0; i<n; i++) { if(arrayflag[arr[i]] == ‘\0‘) arrayflag[arr[i]] = ‘\1‘; // 置出現標誌 else { sameVal = arr[i]; //返回已經出現的值 *back = i; break; } } delete[] arrayflag; if (i < n) { for (int j=0; j<n; j++) { if (sameVal == arr[j]) { *pre = j; return true; } } } return false; } void main(int argc, char *argv[]) { int prePos = -1, backPos = -1; int myArry[11]; myArry[0] = 1; myArry[1] = 3; myArry[2] = 3; myArry[3] = 4; myArry[4] = 5; myArry[5] = 22; myArry[6] = 7; myArry[7] = 13; myArry[8] = 9; myArry[9] = 2; myArry[10] = 12; if (do_dup_mal(myArry, 11, &prePos, &backPos) ) printf("%d\n",myArry[prePos]); }
找出數組中唯一重復的數(轉)