暑假PAT甲级刷题笔记Ⅰ

刷题笔记

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;
}

主要注意的点:

  1. 这题使用unordered_map<string,vector<int>> 实现id到成绩的映射
  2. 在给定分数的情况下,求排名的方法
      1. 二分法
      1. 模拟法
  3. 很久没有做二分的题目了,这里再次复习一下二分中需要注意的点:
    • 如果希望得到的下标是左区间的右端点,使用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;
	
}

难点

  1. 数据的输入
    • 使用在读取包含空格的字符串时,需要使用getline(cin,string)
      • 使用getline()时,需要注意上一格的回车是否已经被读入如果没有,就需要使用getchar()读取上一行的回车
  2. 数据的存储
    • 使用结构体存储数据
    • 使用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;
}

这个题目在算法上没有难度,但是涉及到了cincoutscanfprintf之间的效率问题

使用cin以及cout处理输入输出,在输入数据量大于100000的情况下容易超时

可以考虑更换为scanfprintf来处理输入输出

值得注意的点

  1. 如果更换为scanfprintf处理输入输出,就一定要更换全部的scanfprintf,不然提速不明显

    • 原因:cincout如果需要与scanfprintf同步会显著降低效率
  2. scanf读入string的方法:引入中间数组,然后给字符串赋值(不能直接使用.c_str()方法读取值!!!)

  3. 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值