刷题笔记
2021.7.12—2021.7.14
1084 坏掉的键盘
关于string遍历的问题,在这个样例中,虽然在IDE中查找b[10]没有任何值,但是cout<<b[10]却不会有任何问题,cout<<b[11]就会报错
为了保险起见,还是在b串的末尾加上了’#’
#include<iostream>
#include<algorithm>
#include<string>
#include<unordered_set>
using namespace std;
/*
7_This_is_a_test
_hs_s_a_es
*/
bool los[200];
int main()
{
string a, b;
cin >> a >> b;
int cnt = 0;
//有可能第一个指针还没遍历完的时候,第二个指针就已经遍历完了,所以在第二个string后边加上了'#'
for (int i = 0, j = 0; i < a.size(); i++)
{
char x = toupper(a[i]), y = toupper(b[j]);
if (x == y) {
j++;
if (j == 9)
getchar();
}
else {
if (!los[x]) cout << x, los[x] = true;
}
}
return 0;
}
1108 求平均值
#include<iostream>
#include<string>
using namespace std;
const int N = 1010;
int cnt;
float sum;
int main()
{
string a[N];
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
bool flag = true;
size_t idx;
float t;
try {
t = stof(a[i], &idx); //这里的idx能指向成功转化的最后位数的下一个地址
}
catch (...) {
flag = false;
}
if (idx < a[i].size()) flag = false;
if (t < -1000 || t>1000) flag = false;
int k = a[i].find('.');
if (k != -1 && a[i].size() - k > 3) flag = false;
if (flag) cnt++, sum += t;
else printf("ERROR: %s is not a legal number\n", a[i].c_str());
}
if (cnt > 1) printf("The average of %d numbers is %.2lf\n", cnt, sum / cnt);
else if (cnt == 1) printf("The average of 1 number is %.2lf\n", sum);
else puts("The average of 0 numbers is Undefined");
return 0;
}
这题涉及到了很多库函数
-
stoi()
,stof()
这两个函数能把string
转化为int
/float
- 在字符串不合法的情况下,它们能抛出异常
- 能包含两个参数,第二个参数&idx能带出 成功转换的最后一位的下一个地址
-
使用
try{} catch(...){}
语句捕捉异常,记为不合法数字catch(...)
捕捉所有类型的异常
-
string类型的
.find(x)
函数 能在指定字符串中寻找第一个x的下标,并将其返回。如果在字符串中找不到x,那么返回值为-1
c++ 中的try catch 语句
size_t
1124 微博转发抽奖
这题用到了unordered_set来判重
#include<iostream>
#include<algorithm>
#include<string>
#include<unordered_set>
using namespace std;
const int N = 1010;
string name[N];
int main() {
int m, n, s;
cin >> m >> n >> s;
for (int i = 1; i <= m; i++) //这里要注意,s从1开始,所以i也要从1开始
cin >> name[i];
unordered_set<string> hash;
int i = s;
while(i<=m)
{
if (hash.count(name[i])) i++;
else {
cout << name[i] << endl;
hash.insert(name[i]);
i += n;
}
}
if (hash.empty()) puts("Keep going...");
return 0;
}
1125 PAT单位排行
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
struct School
{
string name;
int cnt;
double sum;
School() : cnt(0), sum(0) {}
bool operator< (const School& t) const //运算符重载,绝绝子
{
if (sum != t.sum) return sum > t.sum;
if (cnt != t.cnt) return cnt < t.cnt;
return name < t.name;
}
};
int main()
{
int n;
cin >> n;
unordered_map<string, School> hash;
while (n--)
{
string id, sch;
double grade;
cin >> id >> grade >> sch;
//将所有的大写字母都转化为小写字母
for (auto& c : sch)
c = tolower(c);
if (id[0] == 'B') grade = grade / 1.5;
else if (id[0] == 'T') grade = grade * 1.5;
hash[sch].sum += grade;
hash[sch].cnt++;
hash[sch].name = sch;
}
vector<School> schools;
for (auto item : hash) {
item.second.sum = (int)(item.second.sum + 1e-8); //需要注意这里的second,这里的second指的是<string,School>中的second
schools.push_back(item.second);
}
//进行多关键字排序
sort(schools.begin(), schools.end());
cout << schools.size() << endl;
int rank = 1;
for (int i = 0; i < schools.size(); i++)
{
auto s = schools[i];
if (i && s.sum != schools[i - 1].sum) rank = i + 1;
printf("%d %s %d %d\n", rank, s.name.c_str(), (int)s.sum, s.cnt);
}
return 0;
}
值得注意得点:
-
c++进行除法时,可能存在精度问题,比如 /1.5 时,出现了 2.99999999 取整后为2
- 解决方案:在除法后加上经验值
eps
(一般为1e-8)
- 解决方案:在除法后加上经验值
-
使用
unordered_map
把学校名字映射到一个结构体 -
重载运算符,进行多关键字排序
1153 解码PAT准考证
1058 霍格沃茨的A + B
1629 延迟的回文数
1579 插入还是归并
1484 最佳排名
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<unordered_map>
#include<cmath>
using namespace std;
/*
使用vector存各科成绩
*/
unordered_map<string, vector<int>> grades;
vector<int> q[4]; //A:q[0] C:q[1] M:q[2] E:q[3] 用于得到排名
//二分查找分数x在数组a中的下标
int get_rank(vector<int>& a, int x)
{
int l = 0, r = a.size() - 1;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (a[mid] <= x) l = mid;
else r = mid - 1;
}
return a.size() - r;
}
int main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++)
{
string id;
int t[4] = { 0 };
cin >> id;
for (int j = 1; j < 4; j++)
{
cin >> t[j];
t[0] += t[j];
}
t[0] = round(t[0] / 3.0);
for (int j = 0; j < 4; j++)
{
q[j].push_back(t[j]);
grades[id].push_back(t[j]);
}
}
for (int i = 0; i < 4; i++)
sort(q[i].begin(), q[i].end());
//处理查询
char names[] = "ACME";
while (m--)
{
string id;
cin >> id;
if (grades.count(id) == 0) puts("N/A");
else
{
int res = n + 1;
char c;
//根据id查找最好的名次
for (int i = 0; i < 4; i++)
{
int rank = get_rank(q[i], grades[id][i]);
if (rank < res)
{
res = rank;
c = names[i];
}
}
cout << res << ' ' << c << endl;
}
}
return 0;
}
主要注意的点:
- 这题使用
unordered_map<string,vector<int>>
实现id到成绩的映射 - 在给定分数的情况下,求排名的方法
-
- 二分法
-
- 模拟法
-
- 很久没有做二分的题目了,这里再次复习一下二分中需要注意的点:
- 如果希望得到的下标是左区间的右端点,使用
mid=(l+r+1)
,区间划分为[l,mid]
和[mid+1,r]
如果希望得到的是右区间的左端点,使用mid=(l+r)/2
,区间划分为[l,mid-1]
和[mid,r]
- 如果希望得到的下标是左区间的右端点,使用
1499 数字图书馆
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<sstream>
using namespace std;
/*比较复杂的信息存在结构体里比较方便*/
struct Book {
string id, name, author;
set<string> keywords;
string publisher, year;
};
int main()
{
int n, m;
cin >> n;
vector<Book> books;
while (n--)
{
string id, name, author;
cin >> id;
getchar(); //当想用getline的时候,需要把上一行的回车读取掉,否则读取的是一个回车
getline(cin, name);
getline(cin, author);
string line;
getline(cin, line);
stringstream ssin(line);
string keyword;
set<string> keywords;
while (ssin >> keyword)
keywords.insert(keyword);
string publisher, year;
getline(cin, publisher);
cin >> year;
books.push_back({ id, name, author, keywords, publisher, year });
}
cin >> m;
getchar();
string line;
while (m--)
{
getline(cin, line);
cout << line << endl;
string info = line.substr(3);
char t = line[0];
vector<string> res;
if (t == '1')
{
for (auto& book : books)
if (book.name == info)
res.push_back(book.id);
}
else if (t == '2')
{
for (auto& book : books)
if (book.author == info)
res.push_back(book.id);
}
else if (t == '3')
{
/*查询关键字*/
for (auto& book : books)
{
if (book.keywords.count(info))
res.push_back(book.id);
}
}
else if (t == '4')
{
for (auto& book : books)
if(book.publisher==info)
res.push_back(book.id);
}
else
{
for (auto& book : books)
if(book.year==info)
res.push_back(book.id);
}
if (res.empty()) puts("Not Found");
else
{
sort(res.begin(), res.end());
for (auto id : res) cout << id << endl;
}
}
return 0;
}
难点
- 数据的输入
- 使用在读取包含空格的字符串时,需要使用
getline(cin,string)
- 使用getline()时,需要注意上一格的回车是否已经被读入如果没有,就需要使用getchar()读取上一行的回车
- 使用在读取包含空格的字符串时,需要使用
- 数据的存储
- 使用结构体存储数据
- 使用set存储关键字(比较易于查找这个关键字)
1505 列表排序
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n;
struct Row{
string id,name;
int grade;
//由于重载只能重载一次,在这种3个排序的情况下不是很方便
}rows[N];
bool cmp1(Row a,Row b)
{
return a.id<b.id;
}
bool cmp2(Row a,Row b)
{
if(a.name!=b.name) return a.name<b.name;
return a.id<b.id;
}
bool cmp3(Row a,Row b)
{
if(a.grade!=b.grade) return a.grade<b.grade;
return a.id<b.id;
}
int main()
{
int c;
scanf("%d%d", &n,&c);
char id[10],name[10];
for(int i=0;i<n;i++)
{
int grade;
scanf("%s%s%d",id,name,&grade);
rows[i]={id,name,grade};
}
if(c==1) sort(rows,rows+n,cmp1);
else if(c==2) sort(rows,rows+n,cmp2);
else if(c==3) sort(rows,rows+n,cmp3);
for(int i=0;i<n;i++)
printf("%s %s %d\n",rows[i].id.c_str(),rows[i].name.c_str(),rows[i].grade);
return 0;
}
这个题目在算法上没有难度,但是涉及到了cin
、cout
和scanf
、printf
之间的效率问题
使用cin
以及cout
处理输入输出,在输入数据量大于100000的情况下容易超时
可以考虑更换为scanf
和printf
来处理输入输出
值得注意的点
-
如果更换为
scanf
和printf
处理输入输出,就一定要更换全部的scanf
和printf
,不然提速不明显- 原因:
cin
、cout
如果需要与scanf
和printf
同步会显著降低效率
- 原因:
-
scanf
读入string
的方法:引入中间数组,然后给字符串赋值(不能直接使用.c_str()
方法读取值!!!) -
printf
输出string
的方法:使用.c_str()
方法
1523 学生课程表
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<unordered_map>
#include<algorithm>
using namespace std;
unordered_map<string, vector<int>> students;
int main()
{
int n, k;
scanf("%d%d", &n, &k);
/*unordered_map实现对学生选课信息的映射*/
while (k--)
{
int a, b; //a课程有b个学生
scanf("%d%d", &a, &b);
for (int i = 0; i < b; i++)
{
string name;
char temp[100];
scanf("%s", temp);
name = temp;
students[name].push_back(a);
}
}
while (n--)
{
string query;
char temp[100];
scanf("%s", temp);
query=temp;
printf("%s %d", query.c_str(), students[query].size());
sort(students[query].begin(),students[query].end());
for (auto c : students[query])
{
printf(" %d", c);
}
printf("\n");
}
return 0;
}
这题又踩坑了,直接使用了 。正确的做法应该是引入一个中间.c_str( )
进行string
的赋值char
数组,然后将char
数组赋值给string