GitHub代码地址:https://github.com/Chaomin702/Algorithm.git
问题描述:
大小为 N 的数组
A ,其主要元素是一个出现次数超过 N/2 的元素(从而这样的元素最多有一个)。例如,数组
3,3,4,2,4,4,2,4,4
有一个主要元素,而数组
3,3,4,2,4,4,2,4
没有主要元素。如果没有主要元素,那么你的程序应该指出来。
下面是求解该问题的一个算法概要。
首先找出主要元素的一个候选元(这是难点)。这个候选元是唯一有可能是主要元素的元素。第二步确定是否这个候选元是主要元素。为了找出候选元,构造第二个数组 B 。比较
A1 和 A2 ,如果它们相等则取其中之一加到数组 B 中;否则什么都不做;然后比较A3 和 A4 ,按同样的方式处理,其次类推直到读完这个数组,然后递归的寻找数组B中的候选元,它也是 A 的候选元. (为什么?)a, 递归如何终止?
b, 当N是奇数时, 如何处理?
c, 该算法的运行时间是多少?
d, 我们如何避免使用附加数组
B ?e, 编写一个程序求解主要元素.
思路
首先先考虑
N
为偶数的情况。
我们需要回答这样一个问题:
反证法
假设
其中 M 是数组B的大小。
显然,
而
其中 l 是
l 所覆盖的元素最多只有
所以 A 中候选元的个数要小于
好了,到此,我们是时候拿起减而治之这个有力的武器了。
我们可以将问题
A
化简为
当然,别忘记
N
为奇数的情况,我们还需要做些小修改。
当
1. 如果找到主元确实存在,那么直接返回主元即可。
2. 否则,第
N
个元素可能是主元,我们需要遍历数组来确定它是否真的是主元。
时间复杂度分析
对于偶数:
不难解出
对于奇数,确认主元存在需要 O(n) 的时间,遍历数组也需要 O(n) 的时间,总之是 O(n) 的时间。
最后附上代码
bool isMainElement(vector<int> &v){
int count = 1;
int s = v.back();
for (int i = 0; i < v.size() - 1; i++){
if (v[i] == s)
count++;
}
if (count>v.size() / 2)
return true;
else
return false;
}
int findMainElement(vector<int> &v){
if (v.empty()) return -1;
if (v.size() == 1) return v[0];
vector<int> u;
for (int i = 0; i + 1 < v.size(); i = i + 2){
if (v[i] == v[i + 1])
u.push_back(v[i]);
}
int res = findMainElement(u);
if (v.size() % 2 != 0 && res == -1 && isMainElement(v))
return v.back();
else
return res;
}