10 完成一半题目

文章介绍了一个关于在有限题目中为多位参与者分配不同知识点类型的优化算法。原算法时间复杂度为O(n^2),导致超时,改进后的算法利用快速排序降低到O(nlogn),有效解决了寻找最少知识点类型数量的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者: Turbo时间限制: 1S章节: 课程设计

一,问题描述 :

有 N 位扣友参加了微软与力扣举办的「以扣会友」线下活动。主办方提供了 2*N 道题目,整型数组 questions 中每个数字对应了每道题目所涉及的知识点类型。

若每位扣友选择不同的一题,请返回被选的 N 道题目至少包含多少种知识点类型。

示例 1:

输入:

4

2 1 6 2

输出:1

解释:共有 2 位扣友,在 4 道题目中选择 2 题。

可选择完成知识点类型为 2 的题目时,此时仅一种知识点类型,因此至少包含 1 种知识点类型。

示例 2:

输入:

12

1 5 1 3 4 5 2 5 3 3 8 6

输出:2

解释:共有 6 位扣友,在 12 道题目中选择题目,需要选择 6 题。

3位选择完成知识点类型为 3 的题目,3位选择完成知识点类型为 5 的题目,因此至少包含 2 种知识点类型。

二,输入说明 :

输入两行:

第一行为一个整数n代表数组questions的长度,n=2*N,N为扣友的数量。

第二行输入n个整数代表数组questions的元素。

提示:

    2 <= n <= 10^5

    1 <= questions[i] <= 1000

三,输出说明 :

输出一个整数表示结果。

代码

第一次做的时候TLE了,时间复杂度是n^2,所以就知道要找个更小的。

思路1 O(n2)
/*
*输入题目数n和每道题的知识点共m个
* N=n/2,从m中选择N个题目。
* 找到m数组中出现最多次的元素(每个元素都看自己后面有多少个一样的,然后找出最大的那个p),
* 找到后,N-t;
* 然后找到下一个最多次的元素......直到找完N个题目
* 最后输出类型数num
*/
int main()
{
    int n,m=0,num=0,N,i,j,t1,t=0,p,q=0,a[100005],b[100005];
    cin>>n;
    N=n/2;
    for(i=0;i<n;i++)cin>>a[i];
    while(N>0)
    {
       t=0;
       for(i=0;i<n;i++)//找到m数组中出现最多次的元素(每个元素都看自己后面有多少个一样的,然后找出最大的那个p)
       {
          t1=0;q=0;
          for(j=0;j<m;j++)//如果是已经处理过的就不用找了
          {
              if(a[i]==b[j])
              {
                 q=1;
                 break;
              }
          }
          if(q==0)//剩下的中再找最多的
          {
               for(j=i;j<n;j++)
               {
                    if(a[j]==a[i])t1++;
               }
               if(t1>t)
               {
                   t=t1;
                  p=a[i];
               }
          }
      }
      num++;
      b[m++]=p;
      N-=t;
   }
   cout<<num;
   return 0;
}

 比n^2还小就是nlogn,那么就想到了先用快速排序进行有序处理

思路2 O(nlogn)
/*
* 数据存入数组,按顺序排列,把相同的放在结构体数组(包含date和times)中
* 遍历结构体的times,直到>=N
*/
typedef struct question//使用结构体就变得很清晰了
{
    int date;
    int times;
}que;
int main()
{
    que a[100005];
    vector<int> vec;
    int i,j,n,num,m=0,max=1,s=0,t=0;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>num;
        vec.push_back(num);
    }
    sort(vec.begin(),vec.end());//nlogn,简化时间复杂度的关键就在这,思路一就是每次都需要从头开始导致n2
    a[0].date=vec[0];
    a[0].times=1;
    for(i=1;i<vec.size();i++)//把相同的放在结构体数组(包含date和times)中
    {
        if(vec[i]==a[m].date)
        {
            a[m].times++;
            max=max>a[m].times?max:a[m].times;
        }
        else
        {
            m++;
            a[m].date=vec[i];
            a[m].times++;
        }
    }
    //存完后按顺序(从大到小)把times加起来,t++,直到s>=n/2,输出t
    while(s<n/2)
    {
        for(i=0;i<m+1&&s<n/2;i++)
        {
            if(a[i].times==max)
            {
                s+=a[i].times;
                t++;
            }
        }
        max--;//这不会导致时间复杂度很高
    }
    cout<<t;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值