老生常谈:主元素问题



问题:

有整型数组a[1…n],如果整数x在数组a中出现的次数多于半数,则x称为多数元素。

初级方法:

  1. 计算每一个元素出现的次数,算法复杂度O(NlogN)
  2. 可以寻找中间值元素,因为多数元素在序列中必为中间值元素,时间复杂度是O(n)

分析此问题:
容易证明引理:在原序列中去除两个不同的元素后,那么在原序列中的多数元素在新序列中还是多数元素。

因此在以上引理的支持下,规模为n的问题就规约为求解规模为n-2的问题,于是我们可以得到一个时间复杂度也是O(n)、但是隐藏常数会比寻找中间值的方法要小的算法。

算法基本思路:

(1)在寻找多数元素的过程中,将计数器初始化为1,遇到相同元素则计数器加1,遇到不同元素则计数器减1,一直到计数器等于0或遍历完整个序列。由此可见,计数器的值表示当前元素抵消掉不同元素后的出现次数;

(2)当计数器在遍历完整个序列前就已经是0,则忽略掉已经遍历过的元素(可以看作两两抵消不影响序列中的多数元素),跳到下一个元素然后计数器重新置1,重复上述步骤,一直到遍历完整个序列;

(3)当遍历完整个序列后,算法会返回一个值,此时我们还需要检测一次这个值是否真的是多数元素,即遍历统计一次。这一步不可或缺。因为上述两个步骤到了遍历完序列后必将返回一个值,无论序列有无多数元素。此值存在两种情况,第一,它真的是多数元素;第二,它只是序列后面的某个元素刚好抵消完序列。所以我们必须检测一次。

算法的实现

寻找候选者算法:

int Candidate(int* A, int m , int n)  
{//寻找A[m...n]中多数元素候选者
     c=A[m];
     count=1;
     for(j=m+1;count>0&&j<n;j++)  {
        if(A[j]==c)
           count++;
        else 
           count--;
    }
    if(j==n)
       return c;
    else
       return canditate(j); //对A[j...n]寻找多数元素候选者。
}

寻找数组多数元素的算法

bool Majority(int* A, int n, int* major) { 

    c = conditate(A, 0, n-1); 

    for (i=0; i<n; ++i) 

        if (A[j] == c) 

            count++; 

    if ( count > n/2 ){ 

        *major = c;// major即为所求 

        return 1; 

    }else  

        return  0; //返回0表示不存在多数元素 

}    

转载自:https://blog.csdn.net/u013279723/article/details/77074822


猜你喜欢

转载自blog.csdn.net/mikeoperfect/article/details/80378500