長度為n的數組,有一個數重復出現了n/2+1次,找出(三種方法)


問題:

長度為n的數組,有一個數重復出現了n/2+1次,找出這個數;
 
解決:
比較直接的思路是遍歷每個元素,讓其與剩下其他元素比較,相等一次計數器sum++,直到sum=n/2+1為止;
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int fun(int inp[],int size)
{
  assert(inp!=NULL && size>1);
  int i=0,j=0;
  for(;i<size-1;i++){
     int sum = 1;
     for(j=i+1;j<size;j++){
        if(inp[i]==inp[j]) sum++;
     }
     if(size/2+1 == sum) return inp[i];
  }
  return -1;
}

int main(){
  int input[]={1,2,5,2,1,8,2,2,2,2};
  int ret = fun(input,10);
  printf("result = %d\n",ret);
  return 0;
}

結果如下:

[root@admin Desktop]# ./a.out
result = 2
[root@admin Desktop]# 
 
方法2:
有n/2+1個重復的,那我們每次從數組中提取出來一對不同的數,到最后數組中剩余的,就只能是重復的數了;
比如{1,3,1,2,1};
依次提取出1/3 , 1/2,剩余的就是1;
 
方案:
1.掃描一遍數組,找到不相同兩個數,都置為-1;
2.最后剩下的,全都是重復數字;
 
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

int fun(int inp[],int size)
{
  assert(inp != NULL && size>2);
  int i=0,j=0;
  for(;i<size-1;i++){//外循環,保證每個數都被遍歷到
    printf("i==:%d\n",i);
    if(-1 == inp[i]) continue;//外循環遇到-1時,證明該數被選中並剔除過
    else{
      printf("in else ==:\n");
      for(j=i+1;j<size;j++){ //內循環,從i往后尋找與inp[i]不同的且不為-1的元素;
         if(inp[i] != inp[j] && -1 != inp[j]){
           printf("j==:%d\n",j);
           inp[i]=inp[j]=-1;//找到后都置為-1
           break;
         }
         if(size-1 == j) return inp[i];//如果j走到頭都沒找到,證明剩下的都與inp[i]重復
      }
    }
  }
  return -1;//失敗,返回-1
}

int main()
{
  int input[] = {1,2,3,1,2,1,1,6,1,1};
  int ret = fun(input,10);
  printf("the number is:%d\n",ret);
  return 0;
}

結果:

[root@admin Desktop]# ./a.out
i==:0
in else ==:
j==:1
i==:1
i==:2
in else ==:
j==:3
i==:3
i==:4
in else ==:
j==:5
i==:5
i==:6
in else ==:
j==:7
i==:7
i==:8
in else ==:
the number is:1
[root@admin Desktop]# 

 

方法3:
這個方法不是我想到的,感覺思路極其巧妙,掃描一遍即可,且復雜度只有0(n),上面兩個算法復雜度都為O(n 2);
 
方案:充分利用出現次數超過一半這個特點,使用兩個變量candidate和vote,分別代表候選人和票數,遍歷數組按如下方式投票和更換候選人:

1.若當前數的值與候選人candidate一樣,則把候選人的票數加1;

2.若當前數與候選人不一樣,則把它的票數減1,如果減掉后票數小於0,則把候選人踢掉,用當前數作為新的候選人;

3.最后剩下的候選人就是出現次數超過一半的數。

 

算法的正確性證明: 數組中,數值相同的數都會投贊成票,數值不同的都會投反對票,有一個數出現的次數超過一半,其它數得到的反對票必然大於一半,所以其它數中,任何一個得票都會小於0,遭到淘汰。剩下來的只能是超過一半的那個數。

 
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

int fun(int inp[],int size)
{
  assert(inp != NULL && size>2);
  int i=0,candidate=inp[0],vote=0;
  for(;i<size;i++){
    printf("i = %d; candidate is:%d; vote=%d\n",i,candidate,vote);
    if(inp[i] == candidate) vote++;
    else{
       vote--;
       if(vote < 0){
         candidate = inp[i];
         vote = 1;
       }
    }
  }
  return candidate;
}

int main()
{
  int input[] = {1,2,3,1,2,1,1,6,1,1};
  int ret = fun(input,10);
  printf("the number is:%d\n",ret);
  return 0;
}

結果:

[root@admin Desktop]# ./a.out
i = 0; candidate is:1; vote=0
i = 1; candidate is:1; vote=1
i = 2; candidate is:1; vote=0
i = 3; candidate is:3; vote=1
i = 4; candidate is:3; vote=0
i = 5; candidate is:2; vote=1
i = 6; candidate is:2; vote=0
i = 7; candidate is:1; vote=1
i = 8; candidate is:1; vote=0
i = 9; candidate is:1; vote=1
the number is:1
[root@admin Desktop]# 

 

 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



猜您在找 長為N的數組,元素范圍是0-N-1,其中只有一個數是重復的,找出這個重復元素 給定一個長度為N的數組,找出出現次數大於n/2,n/3的數,要求時間復雜度O(n),空間復雜度O(1) 判斷一個數是否是素數的 n 多種方法 給你一個長度為 n 的數組,其中只有一個數字出現了大於等於 n/2 次,問如何使用優秀的 時空復雜度快速找到這個數字。 劍指Offer(Java版)第五十六題:在一個長度為n的數組里的所有數字都在0到n-1的范圍內。 數組中某些數字是重復的,但不知道有幾個數字是重復的。 也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如,如果輸入長度為7的數組{2,3,1,0,2,5,3},那么對應的輸出是第一個重復的數字2。 面試題3:在一個長度為n的數組里的所有數字都在0到n-1的范圍內。 數組中某些數字是重復的,但不知道有幾個數字是重復的。也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如,如果輸入長度為7的數組{2,3,1,0,2,5,3},那么對應的輸出是第一個重復的數字2。 JS判斷一個數組中是否有重復值的三種方法 JS判斷一個數組中是否有重復值的三種方法 在一個長度為n的數組里的所有數字都在0到n-1的范圍內。 數組中某些數字是重復的,但不知道有幾個數字是重復的。也不知道每個數字重復幾次。請找出數組中任意一個重復的數字。 例如,如果輸入長度為7的數組{2,3,1,0,2,5,3},那么對應的輸出是重復的數字2或者3 JS判斷一個數組中是否有重復值的三種方法
 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM