《算法笔记》学习笔记 part2

一.  前言

    我开始写这篇笔记时,2019年研究生考试的初试成绩已经出来了,我的分数还算理想,但是由于同届选手很强,目前排名并不理想,看来在复试方面还得更加努力,争取逆袭了。

    在part1中我说过这份笔记将主要分两个部分。本篇笔记即为part2。内容为我刷PAT的题目得出的经验以及一些思考。

    希望能顺利的通过复试(如果能进复试的话...)

二. 题目 + 解答 + 小结

1.1002 写出这个数(https://pintia.cn/problem-sets/994805260223102976/problems/994805324509200384)

#include 
#include 
#include 
using namespace std;
string map[] = {"ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu"};
int main(){
	string str1, str2;
	cin >> str1;
	int all = 0;
	for(string::iterator hehe=str1.begin();hehe != str1.end();hehe++){
		int a = *hehe - '0';
		all += a;
	}
	stringstream ss;
	ss << all;
	str2 = ss.str();
	int count = 0; //trick
	for(string::iterator haha=str2.begin();haha != str2.end();haha++){
		if(count != 0)
			cout << " ";
		count ++;
		int a = *haha - '0';
		cout << map[a];
	}
}

【小结】想说两个东西。一是stringstream,这个主要是用来转换类型的(好用,详见https://www.cnblogs.com/hujunzheng/p/5042068.html);二个是如何避免最后一个空格不被输出,加一个count即可。

2.1004 成绩排名(https://pintia.cn/problem-sets/994805260223102976/problems/994805321640296448)

#include 
#include 
using namespace std;

struct Student{
	int grade;
	string id;
	string name;
}temp, Max, Min;

int main(){
	Max.grade = -1;
	Min.grade = 100;
	int T;
	cin >> T;
	while(T--){
		cin >> temp.name >> temp.id >> temp.grade;
		if(temp.grade > Max.grade)
			Max = temp;
		if(temp.grade < Min.grade)
			Min = temp;
	}
	cout << Max.name << " " << Max.id << endl;
	cout << Min.name << " " << Min.id;
	return 0;
}

【小结】本题不难,记录一点:我之前写结构体一直写的是typedef struct,其实在C++里完全可以采用以上这种更为简洁的写法。

3.1036 跟奥巴马一起编程(https://pintia.cn/problem-sets/994805260223102976/problems/994805285812551680)

【小结】本题不难,不贴代码了,就记一点:关于这个四舍五入要注意,比如对a四舍五入就要写成a/2+a%2。

4.1038 统计同成绩学生(https://pintia.cn/problem-sets/994805260223102976/problems/994805284092887040)

#include 
int main(){
	int score[1001] = {0};
	int n;
	scanf("%d", &n);
	for(int i=0;i

【小结】最开始做这道题一个点比较懵,就是不知道怎么分别读入10 20 30这样的数字,事实上只要想以上代码一样分别写scanf即可,我确实是之前刷题太少,继续加油。

5.1014 福尔摩斯的约会(https://pintia.cn/problem-sets/994805260223102976/problems/994805308755394560

#include 
#include 
#include 
using namespace std;

string week[] = {" ", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};

int main(){
	string str1, str2, str3, str4;
	cin >> str1;
	cin >> str2;
	string d;
	int h = 0;
	int len = min(str1.length(), str2.length());
	for(int i=0,count=1; i= 'A'){
			count++;
			int t = str1[i] - 'A' + 1;
			d = week[t];
		}
		if(str1[i]==str2[i] && count==2){
			if(str1[i]<10 && str1[i]>=0)
				h = str1[i];
			else if(str1[i]<='N' && str1[i] >= 'A'){
				int t = str1[i] - 'A' + 1;
				h = t + 9;
			}
		}
	}
	cin >> str3;
	cin >> str4;
	int len_1 = min(str3.length(), str4.length());
	int m = 0;
	for(int i=0; i= 97 && str3[i] <= 122){
			m = i;
			break;
		}else if(str3[i]==str4[i] && str3[i] >= 65 && str3[i] <= 90){
			m = i;
			break;
		}
	}
	if(m > 9)
		cout << d << " " << h << ":" << m <

【小结】本题这样提交上去是部分正确,目前我还不知道哪里不对,第二轮再来看看。

6. 1028 人口普查(https://pintia.cn/problem-sets/994805260223102976/problems/994805293282607104

【小结】本题不难,不贴代码了。记一个点:当本题没有一个有效数据时,若不特殊处理,输出0后会有空格,则会导致格式错误,所以必须要在最后特殊处理一下。

7.1013 数素数 (https://pintia.cn/problem-sets/994805260223102976/problems/994805309963354112)

#include 
#include 
using namespace std;

bool isPrime(int n){
	if(n <= 1)
		return false;
	int sqr = (int)sqrt(1.0*n);
	for(int i=2; i<= sqr; i++)
		if(n % i == 0)
			return false;
	return true;
}

int prime[10001], pNum = 0;//存素数
void find_prime(){
	for(int i=1; i<1000001; i++){
		if(isPrime(i) == true)
			prime[pNum++] = i;
		if(pNum == 10000)
			break;
	}
}

int main(){
	int m, n;
	cin >> m >> n;
	find_prime();
	int left = prime[m-1];
	int right = prime[n-1];
	for(int i=0, count=0; i=left && prime[i]<=right){
			count++;
			if(count % 10 == 1)
				cout << prime[i];
			else if(count % 10 == 0)
				cout << endl;
			else
				cout << " " << prime[i];
		}
	}
}

【小结】又出现了一道部分正确的题目,目前也还没看出来哪里不对。这里关于如何在输出最后不加空格做个记录:可以先输出第一个数,然后在以后的每次输出的前面加空格,从而就可避免上述问题。

8. 1009 说反话(https://pintia.cn/problem-sets/994805260223102976/problems/994805314941992960) 

#include 
#include 
#include 
using namespace std;

int main(){
	vector vi;
	string t;
	getline(cin, t);
	string re;//存放一个个单词
	for(int i=0; i=0; i--){
		if(flag == 0){
			cout << vi[i];
			flag++;
		}
		else
			cout << " " <

【小结】通过这道题我对于vector, string的使用更加熟悉了。这里要提两点:一是若想将一个字符加入string,要用push_back(),其它几个都会失败,原因是push_back(i)中的i是一个元素,而其他函数普遍是添加字符串的;二是string的输入问题,由于单纯的cin输入遇到空格会停止,所以这里要有getline来输入一整行。

9.1091 N-自守数(https://pintia.cn/problem-sets/994805260223102976/problems/1071785664454127616)

#include 
#include 
#include 
#include 
using namespace std;

int zishou(int n, int len){
	for(int i=1; i<10; i++){
		int r = i*n*n;
		if(r % (int)pow(10.0, len) == n)
			return i;
	}
	return -1;
}

int main(){
	int T;
	cin >> T;
	while(T--){
		string a;
		cin >> a;
		int len = a.size();
		istringstream aa(a);
		int i;
		aa >> i;
		int res = zishou(i, len);
		if(res == -1)
			cout << "No" << endl;
		else
			cout << res << " " << res*i*i << endl;
	}
}

【小结】两个点:一是pow()这个函数,我用的VS2008对数学函数的参数检查更为严格,pow(2, 45)会引起一个错误提示如下:
error C2668: “pow”: 对重载函数的调用不明确......其解决方案是当试图匹配参数列表“(int,int)”时,使用为pow(2.0, 45);另一点依然是类型转换,本题中我将字符串转化为了整型。(ps:我在part1中有一个类型转换的专题)

10.1026 程序运行时间(https://pintia.cn/problem-sets/994805260223102976/problems/994805295203598336)

#include 
using namespace std;
typedef long long ll;

int main(){
	double begin,end;
	while(cin >> begin >> end){
		ll time = double((end-begin)/100)+0.5;
		int h = time / 3600;
		int m = time % 3600 / 60;
		int s = time % 60;
		printf("%02d:%02d:%02d\n", h, m, s);
	}
}

【小结】这个题目我之前用cout输出花了很多时间,然而却忘了printf的自动补齐功能,如上;另外while(cin >> begin >> end)的写法也值得收藏。

11.1005 继续(3n+1)猜想(https://pintia.cn/problem-sets/994805260223102976/problems/994805320306507776)

#include 
#include 
using namespace std;

int num[10001] = {0};
int save[101] = {0};

bool com(int a, int b){
	return a > b;
}

int main(){
	int T;
	cin >> T;
	while(T--){
		int a;
		cin >> a;
		if(num[a] == 0)
			num[a] = 1;
		while(a != 1){
			if(a % 2 == 0)
				a /= 2;
			else
				a = (a*3 + 1)/2;
			num[a] = 2;
		}
	}
	int count = 0;
	for(int i=0; i<10001; i++)
		if(num[i] == 1)
			save[count++] = i;
	sort(save, save+count, com);
	for(int i=0, flag=0; i

【小结】这道题主要是思路比较重要,将各个数字当作数组下标来处理是个非常好的思路。

12.1010 一元多项式求导 (https://pintia.cn/problem-sets/994805260223102976/problems/994805313708867584)

#include 
#include 
using namespace std;

void reverse(int a[], int range_a, int range_b){ //对一个数组进行逆序处理
	for(int i=0; i<=(range_b-range_a)/2; i++)
		swap(a[range_a+i], a[range_b-i]);
}

int main(){
	int n, m_1, pos=0;
	int A[101] = {0};
	cin >> n >> m_1;
	int m = m_1 % n;
	int n_1 = n;
	while(n_1--){
		int value;
		cin >> value;
		A[pos++] = value;
	}
	if(m != 0){
		reverse(A, 0, n-m-1);
		reverse(A, n-m, n-1);
		reverse(A, 0, n-1);
	}
	for(int i=0, flag=0; i

【小结】这道题主要就是注意一下两个特殊情况:一是m为0时,二是m超过n时。

13.1012 数字分类 (https://pintia.cn/problem-sets/994805260223102976/problems/994805311146147840)

【小结】这道题有个坑,不处理会过不了最后一个点。那就是对于A2,运算之后的结果是可能为0的,所以要特别处理

14.1027 打印沙漏(https://pintia.cn/problem-sets/994805260223102976/problems/994805294251491328)

【小结】注意题目没有说符号后面有空格!不要想当然!

15.1090 危险品装箱(https://pintia.cn/problem-sets/994805260223102976/problems/1038429484026175488)

#include 
#include 
#include 
using namespace std;

int main(){
	int N, M;
	map> mp;
	scanf("%d %d", &N, &M);
	while(N--){
		int i = 0;
		int a, b;
		scanf("%d %d", &a, &b);
		mp[a].push_back(b);
		mp[b].push_back(a);
	}
	vector result;
	while(M--){
        int num, flag = 0, h[100000] = {0};
        scanf("%d", &num);
        vector v(num);//初始化size为num
        for(int i=0; i

【小结】通过这道题知道了两个东西:1.vector可以初始化,这样可以避免每次都分配内存;2.注意 if(h[mp[v[i]][j]] == 1) 这句话,这是这道题比较复杂的情况,但是让我知道map确实很强大。

16.1025 PAT Ranking(https://pintia.cn/problem-sets/994805342720868352/problems/994805474338127872)

#include 
#include 
using namespace std;

struct Stu{
	long long id;
	int score;
	int final_rank;
	int local_id;
	int local_rank;
}stu[30010];

bool cmp(Stu a, Stu b){
	if(a.score != b.score)
		return a.score > b.score;
	else
		return a.id < b.id;
}

int main(){
	int N;
	scanf("%d", &N);
	int count = 0; //总人数
	for(int i=1; i<=N; i++){
		int num;
		scanf("%d", &num);
		for(int j=0; j0 && stu[i].score != stu[i-1].score){
			r = i+1;
		}
		printf("%lld ", stu[i].id);
		printf("%d %d %d\n", r, stu[i].local_id, stu[i].local_rank);
	}
	return 0;
}

【小结】从这道题学到了如果要对学生成绩排名,要先进行排序。然后才能对100 100 99排出 1 1 3这种排名。对了,上面这个代码还有一个点过不了,之后再来看看。

17.最大公约数相关(利用欧几里得算法,亦称辗转相除法)

int gcd(int a, int b){
    if(b == 0)
        return a;
    else
        return gcd(b, a % b);
}

18.1083 是否存在相等的差(https://pintia.cn/problem-sets/994805260223102976/problems/994805260780945408)

#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(){
	int N;
	scanf("%d", &N);
	map mp;
	for(int i=0, value=1; i::reverse_iterator ri=mp.rbegin(); ri!=mp.rend(); ri++){
		if(ri->second > 1)
			printf("%d %d\n", ri->first, ri->second);
	}
}

【小结】本题记录下map逆向遍历的方法,使用reverse_iterator结合rbegin和rend即可。

19.1049 数列的片段和(https://pintia.cn/problem-sets/994805260223102976/problems/994805275792359424)

#include 
using namespace std;

int main(){
    double ans = 0;
    int n;
    cin >> n;
    double input;
    for(int i=0;i

【小结】这道题看似像在找全子集,但实际上可以通过找规律做出来!见下图:

《算法笔记》学习笔记 part2_第1张图片

20.1054 求平均值(https://pintia.cn/problem-sets/994805260223102976/problems/994805272659214336)

【小结】这道题很坑!注意若k=1,那么输出为number而不是numbers,读题要仔细!

21.1033 旧键盘打字 (https://pintia.cn/problem-sets/994805260223102976/problems/994805288530460672)

【小结】这道题注意,‘_’是代表空格,也就是说输入的是真的空格,而不是下划线。所以输入要用getline,不能用cin(将空格当作结束符)

22.1095 解码PAT准考证(https://pintia.cn/problem-sets/994805260223102976/problems/1071786104348536832)

【小结】这道题比较复杂,学到了很多东西。记录如下:

  • 如果数组定义较大,放在main之外,不然直接退出
  • 使用cin时要注意,如果之后要用getline(),那么必须在getline()之前再加个getline()。这是因为cin的结束符在结束后,还在缓存区,在使用下个getline()之前必须要把前面cin遗留的结束符处理掉。
  • 在switch case语句段中,如果要在case中定义变量,则需要对case语句段加上{ }
  • 这个点直接举个例子吧:vector > vi_pair。注意两个'>','>' 之间一定要加个空格! 

你可能感兴趣的:(学习笔记)