摩尔投票算法及其变种的应用(一)

主元素问题:找出在一个长度为的数组中存在出现次数大于的元素,已知这样的元素一定存在

常见解法:

  • 排序法:首先能确定的是,这样的元素如果有则仅有一个,那么排序后这样的元素一定是数组的中间元素
  • 字典计数法:暴力解法,用字典记录每个元素出现的次数即可找出所求元素。

摩尔投票法

  • 优势:执行一遍该算法所需的时间复杂度为,优于排序法,空间复杂度为,优于字典计数法
  • 执行过程:重复从数组中找出一对不相同的元素,将其从数组中删除,直到最后不剩下任何元素或者剩下的元素全部相同
  • 算法分析:
    • 不剩下任何元素:说明为偶数,由于找出元素并删除的操作进行了次,而每次的两个元素不相同,则每个元素最多只出现了次,此时不存在主元素。
    • 剩下的元素全部相同:可能有两种情况:为偶数或者为奇数。而无论哪种情况,都能说明剩下的元素是唯一可能的主元素。假设找出元素并删除的操作进行了次,分析如下:
      • 为偶数时,一定有,而被删除的每个元素最多出现次数即为,因此它们都不可能是主元素。
      • 为奇数时,一定有,因此同理,被删除的元素都不可能是主元素
  • 求解主元素问题:根据分析可知,执行摩尔投票算法到最后如果剩下元素,则这个元素是唯一可能的主元素,因此只需要再遍历一遍数组,判断该元素出现的次数是否符合主元素的规定即可,在主元素问题中由于一定存在主元素,因此摩尔投票算法也一定会剩下元素,而且无需判断即可断定其为所求主元素
  • 代码实现:
int majorityElement(int* nums, int numsSize){
    int x;
    int count;
    int i;
    
    /*
     * 利用count模拟摩尔投票算法的执行过程:
     * 1. count第p次为0时令x为nums[i],count第p+1次为0时令x为nums[j],
          令k属于[i, j - 1],每次nums[k] = x时count++,否则count--
     * 2. 显然区间[i, j - 1]的长度为偶数,假设为len,
          那么一定有数量为len/2的k属于[i, j - 1]使得nums[k] = x
     * 3. 因此可以认为在两次count为0的过程中,选出了len/2对元素,
          每对元素包含一个值为nums[i]的元素和一个值不等于nums[i]的元素
     * 4. 当数组遍历完成时,此时x的值就是上一轮选择结束后数组里剩余元素的值,也就是所求的众数
     */
    count = 0;
    for(i = 0; i < numsSize; i++)
    {
        if(count == 0) x = nums[i];
        if(x == nums[i])
            count++;
        else
            count--;
    }

    // 当数组遍历完成时,此时x的值就是上一轮选择结束后数组里剩余元素的值,也就是所求的众数
    return x;
}

你可能感兴趣的:(摩尔投票算法及其变种的应用(一))