所谓主元素, 就是指在数组中出现次数超过N/2的元素, 给出大小为N的数组, 判断是否存在主元素, 若存在,求出主元素.
我的思路
BF解法就不讲了, 我一开始想到的是如果这组数组中数字的范围够小, 或者数字的类型够少, 完全可以用一个数组来记录各个数字出现的次数, 然后再遍历一次即可找出出现次数最多的, 最后判断这个次数是否超过了N/2, 这样算的话, 只需要O(N)的时间复杂度, 这也是典型的用空间换时间. 如果数字足够多, 范围足够大, 那就只能快排了, 排完之后这个题目其实也就是转化成了我说的上一种方式.
聪明人的解法(来源于网络)
首先我们来分情况, 假设这个元素存在的话, 我们先假设数组中第一个元素是该元素, 然后计数变量初始化为1, 此时从第二个元素开始遍历数组, 如果接下来这个元素是当前假定的主元素,那么计数变量+1, 否则计数变量-1, 当计数器数量即将要下降到0的时候, 将当前位置的元素设为主元素, 计数变量重新刷新为1. 那么一条很重要的属性就是遍历数组结束的时候的假定主元素就是该数组的首元素. 此时我们再假设这个元素可能不存在, 那么其实我们只需要确定我们刚才求出来的最后一个假定元素是不是主元素就可以了. 代码实现非常简单, 但其实要想到这个算法, 就不是这么容易了, 哎, 反正我是想不到...
int findMainElement(const int* array, size_t size) {
int candidate = array[0];
int counter = 1;
for (int i = 1; i < size; ++i) {
if (candidate == array[i]) {
++counter;
}
else if (counter == 1) {
candidate == array[i];
}
else {
--counter;
}
}
counter = 0;
for (int i = 0; i < size; ++i) {
if (candidate == array[i]) {
++counter;
}
}
if (counter * 2 > size) {
return candidate;
}
else {
return -1;
}
}