题目如下:
题目 图书管理员
图书馆中每本书都有一个图书编码,可以用于快速检索图书,这个图书编码是一个正整数。
每位借书的读者手中有一个需求码,这个需求码也是一个正整数。如果一本书的图书编码恰好以读者的需求码结尾,那么这本书就是这位读者所需要的。
小 D 刚刚当上图书馆的管理员,她知道图书馆里所有书的图书编码,她请你帮她写一个程序,对于每一位读者,求出他所需要的书中图书编码最小的那本书,如果没有他需要的书,请输出-1。
输入
输入的第一行,包含两个正整数 n 和 q,以一个空格分开,分别代表图书馆里书的数量和读者的数量。 接下来的 n 行,每行包含一个正整数,代表图书馆里某本书的图书编码。 接下来的 q 行,每行包含两个正整数,以一个空格分开,第一个正整数代表图书馆里读者的需求码的长度,第二个正整数代表读者的需求码。
输出
输出有 q 行,每行包含一个整数,如果存在第 i 个读者所需要的书,则在第 i 行输出第 i 个读者所需要的书中图书编码最小的那本书的图书编码,否则输出-1。
备注
对于 20%的数据,1 ≤ n ≤ 2。 另有 20%的数据,q = 1。
另有 20%的数据,所有读者的需求码的长度均为1。
另有 20%的数据,所有的图书编码按从小到大的顺序给出。
对于 100%的数据,1 ≤ n ≤1,000,1 ≤ q ≤ 1,000,所有的图书编码和需求码均不超过 10,000,000。
题目很长,但是将题干翻译过来,其实就是输入几个数字,然后让你去查找符合后缀的数字而已。对此,我们只需要先把输入的图书编号添加某种标签后进行排序,再查找是否存在符合条件的最小编号即可。
那么要解决的问题可以拆分成几个小问题:
1、如何去存储数字?
2、如何去比较数字的大小?
3、如何根据需求码(后缀)快速找到符合要求的数字?
由于要考虑后缀的问题,我选取利用字符串的方式去存储数字,这里为了提高对结构体的熟练程度,我定义了如下结构体:
struct Book{
string index;
string info;
Book(string iptIndex) : index(iptIndex) {}
};
不必要地去考虑了实用性,结构体里面除了书籍编号,还有书籍的信息(尽管并没有用上)。
接下来就是去比较数字的大小,字符串全是数字,从通用性考虑,应当先比较字符串的长度(正如同百位数一定大于十位数一样),再依次去比较最高、次高、次次高位......:如果比较的位数数字不一样,那么就能判断两个字符串代表的数字的大小,依据此思路,则有:
bool compareNumbers(Book booka, Book bookb) {
string a= booka.index;
string b= bookb.index;
int asize = a.size();
int bsize = b.size();
if (asize != bsize) {
return asize < bsize;
}
for (int i = 0; i < asize; i++) {
if (a[i] != b[i]) {
return a[i] < b[i];
}
}
return false;
}
之后就是去搞索引,思路是按照字符串的长度和字符串的末尾
vector<vector<Book>> Database(100);
对于Database[ij],其中ij是一个十位数,i为十位上的数字,j为个位上的数字,里面的Book类型元素book都满足:book.index的长度为i,且末尾为j(由于按长度分类,故比较函数中先比较两个index的长度便不必要)。然后根据读者的需求的最后一位t从低长度到高长度,检查Database[it]的元素是否符合要求。
完整代码实现如下:
#include<bits/stdc++.h>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
struct Book{
string index;
string info;
Book(string iptIndex) : index(iptIndex) {}
};
bool compareNumbers(Book booka, Book bookb) {
string a= booka.index;
string b= bookb.index;
int asize = a.size();
int bsize = b.size();
if (asize != bsize) {
return asize < bsize;
}
for (int i = 0; i < asize; i++) {
if (a[i] != b[i]) {
return a[i] < b[i];
}
}
return false;
}
int main(){
vector<vector<Book>> Database(100);
int n,q;
string bookindex;
cin >> n >> q ;
for(int i=0;i<n;i++){
cin >> bookindex;
int digit = bookindex.size();
int tail = stoi(bookindex.substr(bookindex.size()-1,1));
Database[digit*10+tail].push_back(Book(bookindex));
}
for(int i=10;i<100;i++){
sort(Database[i].begin(),Database[i].end(),compareNumbers);
}
vector<string> need(q);
int unused;
for(int i=0;i<q;i++){
cin >> unused >> need[i];
}
for(int i=0;i<q;i++){
int digit = need[i].size();
int tail = stoi(need[i].substr(need[i].size()-1,1));
bool found = false;
for(int j=1;j<=9;j++){
for(Book book : Database[j*10+tail]){
if(book.index.size()>=digit){
string xtail = book.index.substr(book.index.size()-digit,digit);
if(xtail == need[i]){
cout << book.index << endl;
found = true;
break;
}
}
}
if(found) break;
}
if(!found) cout << "-1\n" ;
}
return 0;
}
值得注意的是,原先的代码中这一部分
if(book.index.size()>=digit){
string xtail = book.index.substr(book.index.size()-digit,digit);
if(xtail == need[i]){
cout << book.index << endl;
found = true;
break;
}
}
第一次写的时候并没有第一行的判断,这导致了测试用例的数据越界报错。我反复检查了数组存储时是否有越界,显然读取存储这一部分是没有问题的。最终才意识到运用substr函数时应当确认传入的参数合法,也就是提取的子串位置应当在母串内,这是我先前从未遇见的,这提示我日后编写代码时,需要关注传入函数的参数是否合法。
感谢你能看到这里。