zoukankan      html  css  js  c++  java
  • 长度为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
    ",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
    ",i);
        if(-1 == inp[i]) continue;//外循环遇到-1时,证明该数被选中并剔除过
        else{
          printf("in else ==:
    ");
          for(j=i+1;j<size;j++){ //内循环,从i往后寻找与inp[i]不同的且不为-1的元素;
             if(inp[i] != inp[j] && -1 != inp[j]){
               printf("j==:%d
    ",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
    ",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(n2);
     
    方案:充分利用出现次数超过一半这个特点,使用两个变量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
    ",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
    ",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]# 
     
     
     
     
     
     
     
     
  • 相关阅读:
    Vue项目中svg图标不能正常显示
    Django Rest Framework
    Django contenttype
    Django CKEdirtor配置(图片上传,粘贴,文件上传)
    [SDOI2017] 数字表格
    [SDOI2015] 约数个数和
    [BZOJ4407] 于神之怒加强版
    [SRM625 Div1 Hard] Seatfriends
    [SRM613~] TaroCheckers
    [玲珑杯1138] 震惊,99%的中国人都会算错的问题
  • 原文地址:https://www.cnblogs.com/McQueen1987/p/3924724.html
Copyright © 2011-2022 走看看