总结:找出数组中出现次数大于n/k的元素(假设数组中必定存在)

参考博客:
https://blog.csdn.net/mdj67887500/article/details/7038850
https://blog.csdn.net/mdj67887500/article/details/7039624
如有侵权,联系删除。
本博客主要是记录模板,至于讲解的话,请参见原博客。

1、k=2,即求数组中出现次数大于数组长度一半的元素。
① 如果数组a是有序数组,那么一个在线处理就可以搞定;
②更一般的情况,a不确定是否有序,那么就要采用下面的方法了。
两种方法时间复杂度是O(n)的。

思路:
因为必定存在一个数出现次数大于n/2,每次删除两个不同的元素,最后剩下的就是要求的元素。
证明:
设目标数为 t a r g e t target target,出现次数为 t i m e > n 2 time>\frac{n}{2} time>2n ;
①当删除两个不同的元素,若其中一个是 t a r g e t target target,则 t i m e − − , n − = 2 time--,n-=2 timen=2
因为 t i m e > n 2 time>\frac{n}{2} time>2n
所以 t i m e − 1 > n 2 − 1 = ( n − 2 ) 2 time-1>\frac{n}{2}-1=\frac{(n-2)}{2} time1>2n1=2(n2)
②当删除两个不同的元素,两个元素都不是 t a r g e t target target,只需要改 n − = 2 n-=2 n=2
t i m e > n − 2 2 time>\frac{n-2}{2} time>2n2

代码:

int find_two(int a[],int n)
{
    int tmp=a[0],cnt=0;
    for(int i=1; i<=n; i++)
    {
        if(cnt==0)
        {
            tmp=a[i];
            cnt++;
        }
        else if(tmp==a[i])
            cnt++;
        else
            cnt-;
    }
    return tmp;
}

2、k>2
note:出现次数大于 n k \frac{n}{k} kn的数至多有 k − 1 k-1 k1个, e g : n 3 eg:\frac{n}{3} eg:3n 至多有2个
复杂度:O(nlog(k))

#include <bits/stdc++.h>
#include <cstdio>
//#define local
using namespace std;

typedef unsigned long long ull;
typedef long long ll;
const int N = 5e6+5;
const int inf = 0x3f3f3f3f;
int n;
int a[N];

struct node
{
    int v;
    mutable int c;
};
struct cmp
{
   bool operator()(const node& a, const node& b)
   {
        return a.v<b.v;
   }
};
int find_k(int a[],int n,int k)
{
    int siz=0;//记录t中不同的元素个数,t的大小
    set<node,cmp> t;
    for(int i=1;i<=n;i++)
    {
        node p;
        p.v=a[i];
        p.c=1;
        set<node,cmp>::iterator pos=t.find(p);
        if(pos==t.end())//没有找到b[i]
        {
            t.insert(p);
            siz++;
            if(siz==k)//t的大小,不同元素数量==k
            {
                for(set<node,cmp>::iterator it=t.begin();it!=t.end();)
                {
                    if(it->c >1)
                    {
                        (it->c)--;
                        it++;
                    }
                    else t.erase(it++);
                }
                siz=t.size();//更新siz的值
            }
        }
        else
        {
            (pos->c)++;
        }
    }
     for(set<node>::iterator it=t.begin();it!=t.end();it++)//检验
     {
         if(it->c >= n/k)
            return it->v;
     }
}
int main()
{
#ifdef local
    freopen("input.txt","r",stdin);
#endif // local
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    printf("%d",find_k(a,n,2));
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值