一道STL(vector)的练习题。
题目链接在此。
题意
有N名学生,K门课程,给出每门课程的选课学生。然后有N个查询,每个查询是某位学生的名字,要求输出每个查询的学生一共选了多少门课,以及每门课的编号。(当然输入、输出都是有限制的)
思路及实现
我想到的是两种思路:
第一种:
以课程为主体,将选择这门课的学生的名字加入到该门课程的学生列表中。
第二种:
以学生为主体,将该学生选择的课程的课程编号加入到该名学生的选课列表中。
在使用了第一种思路实现之后,最后一个点是超时的。因为数据量较大,只要用了string或者map的都会在最后一点测试点超时,并且在PAT上,大数据要尽量避免使用cin和cout进行输入输出。
下面是第一种思路的实现:
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
//某课程注册的学生列表类
struct courseReg{
int courseNum; //课程编号
vector< string > stuName; //学生姓名
int stuNum; //注册该课程的学生数目
courseReg(){
stuNum = 0; //初始化注册该课程的学生数为0
}
};
int main(){
int n,k; //n:学生数目, k:课程数目
scanf("%d %d",&n, &k);
courseReg cr[k];
for(int i = 0; i < k; i++){
int courseNum, stuNum; //courseNum:课程号 stuName:学生数目
scanf("%d %d",&courseNum, &stuNum);
cr[i].courseNum = courseNum;
cr[i].stuNum = stuNum;
string tempStuName;
for(int j = 0; j < stuNum; j++){ //读入注册课程编号为courseNum的学生列表
cin >> tempStuName;
cr[i].stuName.push_back(tempStuName);
}
}
string query; //查询的学生姓名
vector<int> print; //输出的课程号数组
int count = 0; //某学生已选课程的数量
for(int i = 0; i < n; i++){ //n个查询
cin >> query;
for(int j = 0; j < k; j++){
for(int m = 0; m < cr[j].stuNum; m++){
if(cr[j].stuName[m] == query){
count++;
print.push_back(cr[j].courseNum);
}
}
}
sort(print.begin(), print.end());
cout << query << " " << count;
for(int index = 0; index < count; index++){
cout << " ";
cout << print[index];
}
cout << endl;
count = 0; //置为count
print.clear(); //清空print
}
return 0;
}
下面来看一下以学生为主体的实现:
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 26*26*26*10 + 1;
//学生姓名的映射
int getStuId(char name[]){
int stuId = 0;
for(int i = 0; i < 3; i++){
stuId = stuId*26 + (name[i] - 'A');
}
stuId = stuId*10 + (name[3] - '0');
return stuId;
}
vector<int> courseList[M]; //学生选课列表
int main(){
int n,k;
scanf("%d %d",&n, &k); //学生总数,课程数量
int courseId, stuNum; //课程编号, 学生数量
for(int i = 0; i < k; i++){
scanf("%d %d", &courseId, &stuNum);
char stuName[5];
for(int j = 0; j < stuNum; j++){ //读取某课程选课学生姓名
scanf("%s",&stuName);
int stuId = getStuId(stuName);
courseList[stuId].push_back(courseId);
}
}
for(int i = 0; i < n; i++){ //读取查询,并输出结果
char stuName[5];
scanf("%s", &stuName);
int stuId = getStuId(stuName);
sort(courseList[stuId].begin(), courseList[stuId].end());
printf("%s ",stuName);
printf("%d",courseList[stuId].size());
for(int j = 0; j < courseList[stuId].size(); j++){
printf(" %d", courseList[stuId][j]);
}
printf("\n");
}
return 0;
}
这种思想的实现主要是借助了 字符串hash 的处理方法(getStuId函数),对比上一种方法,降低了在比对查询的学生姓名时的时间复杂度。
关于字符串hash的问题,可以看这篇博客。
除此之外,以上还有一个需要注意的地方:courseList数组需要开成全局,否则会内存超限,导致程序abort。
从这个题目的两种思路我们应该可以得出一个 结论:在程序中,应该以稍后需要查询的内容为主体(索引),以减少查询的时间复杂度。