2.19 找出主要元素

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 为偶数的情况。
我们需要回答这样一个问题:B中的候选元也是 A 中的候选元。

反证法

假设m A 的候选元在数组B中的出现次数, n 是数组B中其他元素的个数,即:

m+n=M

其中 M 是数组B的大小。
显然,m<n
2m+2n+l=N

其中 l Ai Ai+1 不相同的元素个数。
l 所覆盖的元素最多只有l/2 A 的候选元。所以说,A的候选元个数为 2m+l/2
2m+l2N2=4m+N2m2nN2=mn<0

所以 A 中候选元的个数要小于N/2,假设矛盾,证毕。


好了,到此,我们是时候拿起减而治之这个有力的武器了。
我们可以将问题 A 化简为B,而问题规模减小一半,不断的重复,直至数组规模为1或者0。
当然,别忘记 N 为奇数的情况,我们还需要做些小修改。

N为奇数时,先从前 N1 个元素中寻找主元:
1. 如果找到主元确实存在,那么直接返回主元即可。
2. 否则,第 N 个元素可能是主元,我们需要遍历数组来确定它是否真的是主元。

时间复杂度分析

对于偶数:

T(n)=T(n/2)+n

不难解出

O(n)=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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值