PAT乙级刷题总结

开始先说最重要心得体会:

写代码前,先在纸上写写画画,写下伪码,理清思路,别上来就敲代码,效率极低还易出现bug。


2019-12-12到2020-01-17,用C++刷完了PAT乙级95道题目,第682个加入满分行列。

题目链接:
PAT乙级真题

image

乙级真题排名

为每道题撰写了相应CSDN博客:
Zhang35的CSDN个人主页

代码上传到了Github:
PAT-Basic-Level.git

每5道题是一套,分值为15、20、20、20、25,相当于一次PAT乙级考试。题目大都不难,因为乙级不考察数据结构,感觉乙级一道题,基本等于算法分析中的一句伪代码……

其中也有部分比较麻烦的题目,有些测试点很难通过,多亏了柳神的代码可以参考。她代码风格简洁、规范,博客整理的井井有条,对STL库的运用更是十分纯熟。柳神博客:
柳婼 の blog
柳婼的CSDN个人主页

后来每做一道题,无论对错,都会再搜柳神的代码,看有无可优化的地方。下面可能是我唯一一道写的比柳神简单点的:
PAT乙级真题 1087 有多少不同的值 C++实现(求出计算公式,1行代码搞定)

比较难的或代表性的有:
原创 PAT乙级真题 1025 反转链表
PAT乙级真题 1034 有理数四则运算 C++实现(两个int相乘结果应用long long存储)
PAT乙级真题 1035 插入与归并
PAT乙级真题 1040 有几个PAT C++实现
PAT乙级真题 1045 快速排序 C++实现
PAT乙级真题 1050 螺旋矩阵 C++实现
PAT乙级真题 1070 结绳 C++实现(类似求哈夫曼树)
PAT乙级真题 1089 狼人杀-简单版 C++实现(假设+遍历暴力求解)

遇到神坑悬而未解的有:
PAT乙级真题 1030 完美数列 C++实现(测试点4超时神坑)
PAT乙级真题 1035 插入与归并 C++实现(求解答:测试点4浮点错误,但不知道为啥还是得了满分)

一开始基本坚持每天1道,并到后面越刷越快,最多的一天是2020-01-14,刷了9道。收获是熟悉了网上刷题常见套路及C++ STL库的用法。下面总结一些常用操作和技巧。

常用函数

isPrime()

#include <cmath>
bool isPrime(int n){
    //用pow(n, 0.5)会超时,sqrt效率大增
    for (int i=2; i<=sqrt(n); i++){
        if (n%i==0){
            return false;
        }
    }
    return true;
}

isNumber()

用sstream判断字符串是否为数字

#include<sstream>
bool isNumber(string s){
    istringstream sin(s);
    double test;
    return sin >> test && sin.eof();
}

swap()

C++标准命名空间中有交换函数:

std::swap(T a, T b);

可以直接用于各种类型。

常用STL库操作

用vector排序

sort(v.begin(), v.end(), cmp);

用set判断相容性

set常见用法有:

#include <set>
using namespace std;
//定义
set<int> myset;
//插入元素
myset.insert(20);
//查找元素
set<int>::iterator it=myset.find(20);
//检查不存在某值
if (myset.find(value)==myset.end()){...}
//删除元素
myset.erase (it);
//删除所有元素
myset.clear();
//判断set是否为空
if (myset.empty()){...}

set是红黑树结构,近似平衡,插入、删除、查找操作的时间复杂度都是 O(logn),并且能自动排序。

适合判断相容性问题:PAT乙级真题 1064 朋友数

用map判断唯一

可使用map<int, int>对出现的数字计数,读到某个值时直接:
mapp[v[i][j]]++;

对map使用[]索引值,若key不存在则会将该key添加,并调用value的默认值作为其值。int的默认值即0。所以可以使用map直接计数。

遍历map

遍历map语法如下:

  // show content:
  for (std::map<char,int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
    std::cout << it->first << " => " << it->second << '\n';

反向遍历

以map为例,反向遍历STL库容器:

for (map<int, int>::reverse_iterator rit = countMap.rbegin(); rit!=countMap.rend(); ++rit){
        cout << rit->first << " " << rit->second << endl;
}

类型map<int, int>::reverse_iterator可以换成auto(C++11特性)。

输入输出

用getline读带空格的一行字符串

读取一行带空格的字符串,需要用getline(cin, s);

cin >> s只能读到空格前一个单词。

用scanf读string

用scanf替代cin时,无法直接读入string类型,可以先读进一个临时字符数组里,再把字符串数组赋值给字符串即可,如:

        char temp[10];
        scanf("%s", temp);
        string str = temp;

打印定长数字

1、cout:

#include <iomanip>
cout << setw(5) << setfill('0') << i;

2、printf:

printf("%05d", i);

小数点后精确2位

1、cout:

#include <iomanip>
cout << fixed << setprecision(2) << i;

2、printf:

printf("%05d", i);

printf打印百分号%

用printf输出’%’,加转义字符’%'是不对的,正确做法是:

printf("%%");

字符串处理

使用cctype.h判断字符类型

使用c++中”cctype”(c中的“ctype.h”)能极大提高效率,包括对单个字符判断类型及大小写转换的函数:

isalnum() 如果参数是字母数字,即字母或数字,该函数返回true
isalpha() 如果参数是字母,该函数返回真
isblank() 如果参数是空格或水平制表符,该函数返回true
iscntrl() 如果参数是控制字符,该函数返回true
isdigit() 如果参数是数字(0~9),该函数返回true
isgraph() 如果参数是除空格之外的打印字符,该函数返回true
islower() 如果参数是小写字母,该函数返回true
isprint() 如果参数是打印字符(包括空格),该函数返回true
ispunct() 如果参数是标点符号,该函数返回true
isspace() 如果参数是标准空白字符,如空格、进纸、换行符、回车、水平制表符或者垂直制表符,该函数返回true
isupper() 如果参数是大写字母,该函数返回true
isxdigit() 如果参数是十六进制的数字,即0~9、a~f、A~F,该函数返回true
tolower() 如果参数是大写字符,则返回其小写,否则返回该参数
toupper() 如果参数是小写字母,则返回其大写,否则返回该参数

reverse()

倒置字符串,用法为:

#include <algorithm>
std::reverse(myvector.begin(),myvector.end());

提高效率

遍历一遍同时得到最大、最小值

用两组临时变量,记录最大、最小两组值,如果有新的最大/小产生,相应更新改组数据。

如: PAT乙级真题 1004 成绩排名 C++实现

cin、cout与scanf、printf

cincoutscanfprintf慢很多,但只需在main函数第一行加上:

std::ios::sync_with_stdio(false);

就能快很多。因为C++为了兼容C,保证程序在使用了std::printf和std::cout的时候不发生混乱,将输出流绑到了一起。这行代码的作用便是取消iostream与stdio的默认关联同步,取消同步后的iostream的性能倍增,能与stdio相差无几。只要注意不要再混用iosteam和stdio即可,否则可能会出现预料之外的错误。

还能进一步提升效率,还可以再加上:

std::cin.tie(0);

PAT乙级真题 1095中添加ios::sync_with_stdio(false);cin.tie(0);依然超时,改成scanfprintf后就AC了。

str = str + "a"与str += "a"效率差距很大

前者产生了新的对象,再把结果返回;后者只涉及到对象的引用,不产生新对象。

拼接字符串最好使用str += "a" ,效率较高。

pow(n, 0.5)换成sqrt(n)

开方用pow(n, 0.5)有时会超时,sqrt效率大增。

排序传参使用引用传参

柳神说:“排序传参建议用引用传参,这样更快,虽然有时候不用引用传参也能通过,但还是尽量用,养成好习惯”。
代码如下:

bool cmp(const Info &i1, const Info &i2){
    return i1.score==i2.score ? i1.s<i2.s : i1.score>i2.score;
}

用vector代替map

索引是数字的时候,可以用vector代替map,用空间换时间。毕竟限定时间宝贵,空间几乎无限。

用unordered_map代替map

map是用红黑树实现的,默认按key排序,使用unordered_map即不排序的map,能提高不少效率。

重要扩展知识

数值有效范围

char             -128 ~ +127        (1 Byte)    
short             -32767 ~ + 32768    (2 Bytes)   3*10^4
unsigned short     0 ~ 65536        (2 Bytes)    6*10^4
int             -2147483648 ~ +2147483647   (4 Bytes)    2*10^9
unsigned int         0 ~ 4294967295    (4 Bytes)       4*10^9
long == int
long long         -9223372036854775808 ~ +9223372036854775807    (8 Bytes)      9*10^18
double         1.7 * 10^308        (8 Bytes)

位运算符

运算符有4种:
&(按位与)、|(按位或)、^(按位异或)、~ (按位取反)。

可以用异或判断异号

        //a,b异号或者有一个0直接算。
        if ((int)(a^b)<0) { …… }

异或运算符是“相异”为1,“相同”为0:

  • 若x^y>0 则二者同号(符号位为0)
  • 若x^y<0 则二者异号(符号位为1)

如:
1 ^ 1 = 0 ^ 0 = 0
1 ^ 0 = 0 ^ 1 = 1
(这里的1和0是位,不是数值)

再例如,1 ^ -1 = -2。因为数据在内存中以补码表示(以8位为例):
1 = 00000001 --> 00000001(补码)
-1 = 10000001 --> 111111111(补码)
异或是在补码的基础上运算的,二者异或结果为11111110(补码)-->10000010 = -2。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 在C语言中,五种基本数据类型存储空间长度的排列顺序是: A)char B)char=int<=float C)ch...
    夏天再来阅读 3,323评论 0 2
  •     大家新年快乐!    最近一直有朋友问我“考研上机怎么准备?”、“马上找工作,想考PAT练练手”等...其...
    大美mixer阅读 6,333评论 11 27
  • 浅谈C++常用输入输出 在编写C++程序的时候,经常因为输入输出头疼,所以在这里做一个小结,记录一下常用的输入输出...
    MinoyJet阅读 3,744评论 0 6
  • cin.tie与sync_with_stdio加速输入输出 以前碰到cin TLE的时候总是傻乎乎地改成scanf...
    Brent姜阅读 3,972评论 1 3
  • 最近准备PAT,临近考试,打算把刷过的PAT都好好写一个题解。加深巩固一下 PAT 乙级1085 1085PAT单...
    SAC0719阅读 416评论 0 0