分治法---众数问题

1.问题描述: 

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

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

对于给定的多重集S,计算S的众数与重数。

2.思路:

1).首先假设中间的元素是众数
2). 然后由两边向中间遍历,直到左右都出现值等于众数的数,记录下众数和重数;
3). 这样就将一个数组分为三部分,我们再对左右部分执行上述步骤;若左边数组的个数大于中位数的个数,则递归左边数组,同理右边相同;

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

ps:如果出现多组众数,以最后一组为最终答案。

3.Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
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 < mid && a[l] != a[mid]; 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); 
}

int main(){
	
    scanf("%d",&n);
    
	for(int i = 0; i < n; i ++ )
	    scanf("%d",a + i);
	
	sort(a,a + n); //排序(后续操作均是基于升序)
	
	int l = 0;
	int r = n - 1;
	
	split(l,r);
	
	printf("%d\n%d\n",a[idx],ans);
	
	return 0;
}


4.代码运行截图:

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那就随便一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值