k等分主元素问题:找出在一个长度为的数组中存在出现次数大于
的元素
问题分析:首先可以确定的是,这样的元素数量最多存在个,该结论很容易得出,此处不再详细论证。该问题是主元素问题的扩展,同样可以使用摩尔投票法解决,当
与
相比不大时,时间复杂度为
,空间复杂度为
。下面以
为例,设计并实现算法
思路与分析:在原始的摩尔投票法中,每次选出的是一组两个不相同的元素并删除,直到无法继续选出元素组,这样会使得主元素只可能在剩下的元素中存在,那么如果每次选出一组三个互不相同的元素呢?在这种情况下,无法继续选出元素组的原因可能是:1. 数组中无剩余元素;2. 数组中剩余元素只有两种取值;3. 数组中剩余元素只有一种取值
-
数组中无剩余元素:说明
为3的倍数,由于找出元素并删除的操作进行了
次,而每次的三个元素互不相同,则每个元素最多只出现了
次,此时不存在k等分主元素
-
数组中剩余元素只有两种取值:说明
为
,
或
,同样地,无论是哪种情况,都能说明剩下的两个元素是唯一可能的两个k等分主元素。假设找出元素并删除的操作进行了
次,分析如下:
-
为
时,一定有
,而被删除的每个元素最多出现次数即为
,因此它们都不可能是k等分主元素
-
为
或
时,同样一定有
,因此同理,被删除的元素都不可能是k等分主元素
-
- 数组中剩余元素只有一种取值:同理,说明被删除的元素都不可能是k等分主元素,同时该数组中不再可能有两个k等分主元素,而是最多只有一个k等分主元素
算法实现:类似于一组包含两个元素的摩尔投票算法的实现,包含三个元素的摩尔投票算法使用两个变量和两个计数器去模拟每轮选出三个互不相同元素的过程,只是需要注意一些实现细节,并且最后不能省略对两个可能的k等分主元素的检验
int* majorityElement(int* nums, int numsSize, int* returnSize){
int x;
int y;
int count_x;
int count_y;
int* res = NULL;
int n;
int i;
res = (int *)malloc(2 * sizeof(int));
n = 0;
count_x = 0;
count_y = 0;
for(i = 0; i < numsSize; i++)
{
// 将原本的count == 0和nums[i] == x两个条件合并
if((count_x == 0 || nums[i] == x) && nums[i] != y)
{
count_x++;
x = nums[i];
}
else if(count_y == 0 || nums[i] == y)
{
count_y++;
y = nums[i];
}
else
{
count_x--;
count_y--;
}
}
/* 对x和y需要进行额外的检测,因为不能保证x和y一定满足要求 */
count_x = 0;
for(i = 0; i < numsSize; i++)
{
if(x == nums[i]) count_x++;
}
if(count_x > numsSize / 3) res[n++] = x;
count_y = 0;
for(i = 0; i < numsSize; i++)
{
if(y == nums[i]) count_y++;
}
if(count_y > numsSize / 3 && x != y) res[n++] = y;
*returnSize = n;
return res;
}