c语言分治法求众数重数_分治法求众数 - osc_twlari2q的个人空间 - OSCHINA - 中文开源技术交流社区...

分治法求众数

Problem Description

给定含有n个元素的多重集合S,每个元素在S中出现的次数称为该元素的重数。多重集S中重数最大的元素称为

众数。例如,S={1,2,2,2,3,5}。多重集S的众数是2,其重数为3。

求众数方法很多,现要求你用分治算法来试一试,并分析其效率。

编程任务:对于给定的由n个自然数组成的多重集S,采用分治算法编程计算S的众数及其重数。

Input

第1行多重集S中元素个数n;接下来的一行为集合S,有n个自然数。( n < 1000000 )

Output

结果输出:输出2个数,第1个数为众数,第2个为其重数。

当有多个同样重数的众数,优先输出数值更小的数的众数。

Sample Input

6

1 2 2 2 3 5

Sample Output

2 3

Hint

提示陆续写上来,不着急,先自行思考和讨论……

Solution

题目说要用分治的解法,不过如果想过这题,一个for循环也是暴力统计求解。

但既然是要学算法,那我们当然要用分治的思想啦!

分治策略

1.我们首先假设中间的元素是众数

2. 然后由两边向中间遍历,直到左右都出现值等于众数的数,记录下众数和重数

3. 这样就将一个数组分为三部分,我们再对左右部分执行上述步骤

4. 注意:使用分治策略解决众数问题需要原集合有序,在原集合无序的情况下需要对其排序,建议数据输入之后先进行排序

当真正理解了分治的思想,这题就迎刃而解啦。这题的分治体现在将数组分为三部分进行众数的统计,可以参考下图理解。

Code

#include

#include

#include

#include

using namespace std;

typedef long long ll;

typedef pairpi;

const int maxn=1e5+100;

const int N=1e6+100;

const int M=1e5+100;

const int mod=1e9+7;

int n,m,T;

int a[N];

int ans=0; //众数的重数

int idx=0; //众数的下标

void split(int l,int r) //分治算法

{

if(l>r)return;

int ll=l; //记录原来的l位置

int rr=r; //记录原来的r位置

int mid=(l+r)>>1;

for(; l

for(; r>mid&&a[r]!=a[mid]; r--); //寻找众数的最右边

//经过两个for循环后,众数个数就是r-l+1

if(ans<=r-l+1) //更新答案

{

if(ans==r-l+1)

{

idx=min(mid,idx);

}

else

idx=mid;

ans=r-l+1;

}

if(l-1-ll+1>=ans) //剪枝

split(ll,l-1); // 对左边部分分治

if(rr-r-1+1>=ans) //剪枝

split(r+1,rr); // 对右边部分分治

}

void solve()

{

scanf("%d",&n);

for(int i=0; i

scanf("%d",a+i);

sort(a,a+n); //先排序,方便统计众数个数

int l=0;

int r=n-1;

split(l,r);

printf("%d %d\n",a[idx],ans);

}

int main()

{

#ifdef LOCAL

freopen("in.txt","r",stdin);

freopen("out.txt","w",stdout);

#endif

solve();

/*

*

*  ┏┓   ┏┓+ +

* ┏┛┻━━━┛┻┓ + +

* ┃       ┃

* ┃   ━   ┃ ++ + + +

* ████━████+

* ◥██◤ ◥██◤ +

* ┃   ┻   ┃

* ┃       ┃ + +

* ┗━┓   ┏━┛

*   ┃   ┃ + + + +Code is far away from

*   ┃   ┃ + bug with the animal protecting

*   ┃    ┗━━━┓ 神兽保佑,代码无bug

*   ┃        ┣┓

*   ┃        ┏┛

*  ┗┓┓┏━┳┓┏┛ + + + +

*    ┃┫┫ ┃┫┫

*    ┗┻┛ ┗┻┛+ + + +

*/

}

最后感谢小伙伴们的学习噢~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值