1. 程式人生 > >找出數組中唯一重復的數(轉)

找出數組中唯一重復的數(轉)

置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]);  
}  
     

  

找出數組中唯一重復的數(轉)