作者: 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;
}