PAT个人学习笔记(不定期维护更新)

PAT笔记

基础语法补充

cout位数控制

c o u t cout cout通过 < i o m a n i p > <iomanip> <iomanip>包下的 s e t p r e c i s i o n ( x ) setprecision(x) setprecision(x)即可转换成输出x位数据,含整数小数一起

*补充:precision设置后的输出会自动四舍五入

例程如下:

#include <iostream>
#include <iomanip>

using namespace std;

int main(){
	double num;
	cin>>num;
	cout<<setprecision(3)<<num<<endl;
}

效果如下:
在这里插入图片描述
在这里插入图片描述

而在 s e t p r e c i s i o n setprecision setprecision前加上同为 < i o m a n i p > <iomanip> <iomanip>包下的 f i x e d fixed fixed关键字即可将输出类型锁定为浮点型,从而将 s e t p r e c i s i o n ( x ) setprecision(x) setprecision(x)中的 x x x固定到对小数点后位数的控制完成预期效果!

例程如下:

#include <iostream>
#include <iomanip>

using namespace std;

int main(){
	double num;
	cin>>num;
	cout<<fixed<<setprecision(3)<<num<<endl;
}

效果如下:
在这里插入图片描述
在这里插入图片描述

可能为空的字符串输入!!!

PTA-1033 旧键盘打字

解题思路非常清晰,使用 m a p map map进行哈希查找即可完成。

坑点在于题目只保证第二行输入非空,即第一行输入可能为空,此时使用cin是无法正常读入的。

必须使用 g e t l i n e ( c i n , a ) getline(cin, a) getline(cin,a)其中 a a a为任一字符串变量。

这样就可以将空行读入为空字符串""!!!

修正后的题解如下:

#include<iostream>
#include<map>
#include<string>

using namespace std;

int main(){
    map<char, int> bad_dic;
    string s1, s2;
    getline(cin, s1);
    cin>>s2;
    string s = "";
    if(s1==""){
        cout<<s2;
        return 0;
    }
    for(auto c:s1){
        bad_dic[c]=1;
    }
    for(auto c:s2){
        char temp = c;
        if('a'<=c&&c<='z'){
            temp=c+'A'-'a';
        }
        if(('A'<=c&&c<='Z')&&(bad_dic.count('+'))){
            continue;
        }
        if(!bad_dic.count(temp)){
            s+=c;
        }
    }
    cout<<s;
}

带空格的字符串读入

PTA-1044 火星数字

关键在于当一行中输入的字符串带空格且需要多行读入时,此时应采用下列模板进行输入:

int N; cin>>N;
/**

* This line was a key line
* It's like a input-wakeup code here
* We will get an empty line without this code

*/
getchar();
for(auto i = 0; i < N; i++){
	string str;
	getline(cin, str);
}

最大公约数gcd

PTA-1034 有理数四则运算

涉及要求公约数的数字较大时,cmath库中的gcd函数则需要进行覆写如下:

long long gcd(long long t1, long long t2) {
    return t2 == 0 ? t1 : gcd(t2, t1 % t2);
}

否则会出现溢出的情况!!!

规则化输入scanf妙用!

PTA-1034 有理数四则运算

当输入的数据在有效数字间参杂其他字符如本题的:
num1/num2 num3/num4

此时若采用字符串处理会平添 O ( n ) O(n) O(n)的时间复杂度,并且soti只能转成int不能转成long long,还存在溢出情况,因此可以使用 < c s t d i o > <cstdio> <cstdio>库下的 s c a n f scanf scanf函数进行规则化输入如下:

scanf("%lld/%lld %lld/%lld",&a,&b,&c,&d);

即scanf的输入数据已占位符表示,可以灵活进行输入!!!

而cin无法进行这样的选择性/规则化输入。

cin单行输入句子存为字符串

PTA-1042 字符统计

当输入数据格式为在一行之内给出一个句子字符串时,不能简单地使用cin对单个字符串变量进行读取!!!

错误例程如下:

string s;
cin>>s;

正确作法:

string s = "";
while(cin.peek()!='\n'){
	char c; cin>>c;
	s += c;
	// If you need do some operations on single input character like statistic
	/* f() here refers to the operation you want to do on c */
	f(c); 
}

细说浮点数

PTA-1049 数列的片段和
细说浮点数

cout中的三目运算符

PTA-1051 复数乘法

在coding时常常需要在一个cout中进行带条件的输出,如果全用if-else来实现的话,代码不免过于冗长,而解决if-else冗长的一个常见工具则是三目运算符(condition)?result1:result2

e.g. 给定一个正整数N,随后N行输入N个整数,请将其符号和其一同输出,结尾不应有空行,样例如下:
输入数据:

3
-1
0
1

输出数据

-1
0
+1

if-else写法:

#include<iostream>
#include<vector>
using namespace std;
vector<int> input;
int main(){
	int N; cin>>N;
	for(int i = 0; i < N; i++){
		int temp; cin>>temp;
		input.push_back(temp);
	}
	for(int i = 0; i < N-1; i++){
		if(input[i]>0){
			cout<<'+';
		}
		cout<<input[i]<<endl;
	}
	if(input[N-1]>0){
		cout<<'+';
	}
	cout<<input[N-1];
}

三目运算符写法:

#include<iostream>
#include<vector>
using namespace std;
vector<int> input;
int main(){
	int N; cin>>N;
	for(int i = 0; i < N; i++){
		int temp; cin>>temp;
		input.push_back(temp);
	}
	for(int i = 0; i < N-1; i++){
		cout<<(input[i]>0?"+":"")<<input[i]<<endl;
	}
	cout<<(input[N-1]>0?"+":"")<<input[N-1];
}

*特别注意:
1)cout中待输出的三目表达式应被括号包裹住!
2)要表征某一条件下不需输出时,需要用字符串“”表示,使用字符‘’则会报错!(因为无空字符)

My Own 巧妙题解

PTA-1035 插入排序与归并排序

源码如下:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

vector<vector<int>> insertion;
vector<vector<int>> merge_array;

void insertion_sort(vector<int> array){
    for(int i = 0; i < array.size(); i++){
        vector<int> temp = array;
        sort(temp.begin(), temp.begin()+i+1);
        insertion.push_back(temp);
    }
    return;
}

void merge_sort(vector<int> array){
	int unit = 2;
	int len = array.size();
	while(unit<=len){
		vector<int> temp = array;
		int i = 0;
		while(i+unit<=len){
			sort(temp.begin()+i, temp.begin()+i+unit);
			i+=unit;
		}
		sort(temp.begin()+i, temp.end());
		merge_array.push_back(temp);
		unit += unit;
	}
	sort(array.begin(), array.end());
	merge_array.push_back(array);
    return;
}

int main(){
    int N;
    cin>>N;
    vector<int> input;
    vector<int> mid;
	for(int i = 0; i < N; i++){
    	int ori;
		cin>>ori;
    	input.push_back(ori);
	}
	for(int i = 0; i < N; i++){
    	int mi;
		cin>>mi;
    	mid.push_back(mi);
	}
	insertion_sort(input);
	merge_sort(input);
	
	// insert
	// insertion[0] with no operation
	for(int i = 1; i < N; i++){
		if(mid==insertion[i]){
			cout<<"Insertion Sort"<<endl;
			for(int j = 0; j < N-1; j++){
				cout<<insertion[i+1][j]<<" ";
			}
			cout<<insertion[i+1][N-1];
			return 0;
		}
	}
	
	// merge
	for(int i = 0; i < merge_array.size(); i++){
		if(mid==merge_array[i]){
			cout<<"Merge Sort"<<endl;
			for(int j = 0; j < N-1; j++){
				cout<<merge_array[i+1][j]<<" ";
			}
			cout<<merge_array[i+1][N-1];
			return 0;
		}
	}
	
}

核心思路:模拟——使用 < a l g o r i t h m > <algorithm> <algorithm>库下的 s o r t sort sort函数进行排序模拟来完成对每一次排序得到的序列进行记录

插入排序模拟如下

思路:通过对前 i i i个元素进行快排来模拟完成插入。

进一步优化——将 t e m p temp temp等效于前次操作的结果即 i n s e r t i o n . b a c k ( ) insertion.back() insertion.back()来缩短快排操作次数。

*注意:插入排序的第0次操作等同于位操作,遍历结果序列时应从1开始!!!

void insertion_sort(vector<int> array){
	insertion.push_back(array);
    for(int i = 1; i < array.size(); i++){
        vector<int> temp = insertion.back();
        sort(temp.begin(), temp.begin()+i+1);
        insertion.push_back(temp);
    }
    return;
}

归并排序模拟如下

思路:通过对每一个单元 u n i t unit unit进行自底向上的排序。

*注意:长度不足unit的剩余子序列也需要进行排序!!!

void merge_sort(vector<int> array){
	int unit = 2;
	int len = array.size();
	while(unit<=len){
		vector<int> temp = array;
		int i = 0;
		while(i+unit<=len){
			sort(temp.begin()+i, temp.begin()+i+unit);
			i+=unit;
		}
		sort(temp.begin()+i, temp.end());
		merge_array.push_back(temp);
		unit += unit;
	}
	sort(array.begin(), array.end());
	merge_array.push_back(array);
    return;
}

PTA-1060 爱丁顿数

源码如下:

#include<iostream>
#include<vector>

using namespace std;

int main(){
    int N; cin>>N;
    vector<int> miles(N+2, 0);
    int E = 0;
    
    for(int i = 0; i < N; i++){
        int temp; cin>>temp;
        miles[temp<=N?temp:N+1]++;
    }
    
    int summ = N;
    for(int i = 0; i <= N; i++){
        summ -= miles[i];
        if(summ>=i){
            E = i;
        }
    }
    
    cout<<E;
}

是时间空间双 O ( n ) O(n) O(n)线性模拟解法

核心思路:由于一共骑车天数为 N N N,因此 E E E最大为 N N N。故以长度为 N + 2 N+2 N+2容器记录骑车里数为 i i i的天数。接着从 0 0 0遍历到 N N N,总天数 N N N减去等于当前天数的里数的天数即为大于当前里数的总天数,若其大于等于当前天数,则爱丁顿数更新为之。

基础算法补充(带板子)

埃式筛

一种时间复杂度为 O ( n l o g n l o g n ) O(nlog nlog n) O(nlognlogn)的快速筛选出 2 − N 2-N 2N中素数的筛法。

思路:通过遍历 2 − N 2-N 2N,不断维护更新遇到的素数到容器中,同时将容器中每一个素数的倍数筛除。

板子如下:( N N N is a given integer)

// i-indexed element in isnp specifies whether i+1 was not a prime number(true)
vector<bool> isnp(N+1, false);
vector<int> primes;

for(int i = 2; i <= N; i++){
	// i is a prime number
	if(!isnp[i]){
		primes.push_back(i);
		// Start Sieve
		for(int j = i+i; j <= N; j+= i){
			isnp[j] = 1;
		}
	}
}

欧拉筛(Euler Sieve)

应用: PTA-1059 C语言竞赛

素数筛中由于非素数存在着多种因数,从而造成了同一非素数会被各个素因数筛去,这就是素数筛中的大量重复计算。若只以最小素因数筛去非素数,则得到了线性时间复杂度 O ( n ) O(n) O(n)的筛法——欧拉筛

板子如下:( N N N is a given integer)

// i-indexed element in isnp specifies whether i+1 was not a prime number(true)
vector<bool> isnp(N+1, false);
vector<int> primes;

for(int i = 2; i <= N; i++){
	// i is a prime number
	if(!isnp[i]){
		primes.push_back(i);
	}
	// Start sieve with primes vector
	for(auto p:primes){
		if(p*i>N){
			break;
		}
		isnp[p*i]=1;
		if(i%p == 0){
			break;
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码小狗Codog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值