写在前面
接上篇【PAT刷题甲级】部分笔记1001-1064~(上)
这里是1065-1155,同样仅为本人刷的题部分笔记,不包括所有题,希望对刷题的同学有帮助~
上篇:【PAT刷题甲级】部分笔记1001-1064~(上)
1065:A+B和C(64进制)(大整数运算与比较)
cin和scanf还真有点不同,如果读取的数溢出,cin得到的是最大值,而scanf得到的是溢出后的值
struct bign { //大整数
int d[22];
int len;
bign(){
memset(d,0,sizeof(d));
len=0;
}
};
bign change(char str[]) { //字符串转为大整数
bign a;
if(str[0]!='-') {
a.len = strlen(str);
for(int i=0; i<a.len; i++) {
a.d[i]=str[a.len-i-1]-'0'; //逆序赋值
}
} else {
a.len = strlen(str)-1;
for(int i=0; i<a.len; i++) {
a.d[i]=str[a.len-i]-'0'; //逆序赋值
}
}
return a;
}
bign add(bign a,bign b) { //大整数相加
bign sum;
int carry=0; //进位
for(int i=0; i<a.len || i<b.len; i++) {
int temp = a.d[i] + b.d[i] + carry;
sum.d[sum.len++] = temp % 10; //个位留下做和
carry = temp / 10; //十位作为进位
}
if(carry!=0) { //最后一位进位不为0,直接加到最高位上
sum.d[sum.len++] = carry;
}
return sum;
}
bign sub(bign a,bign b) { //大整数相减
bign c;
for(int i=0; i<a.len || i<b.len; i++) {
if(a.d[i]<b.d[i]) {
a.d[i+1]--;
a.d[i] += 10;
}
c.d[c.len++] = a.d[i] - b.d[i];
}
while(c.len-1>=1 && c.d[c.len-1]==0) {
c.len--; //去除高位的0,保留至少一位
}
return c;
}
int compare(bign a,bign b) { //大整数的比较,a大,相等,a小分别返回1、0、-1
if(a.len>b.len) return 1;
else if(a.len<b.len) return -1;
else {
for(int i=a.len-1; i>=0; i--) { //从高位向低位比较
if(a.d[i] > b.d[i]) return 1;
else if(a.d[i] < b.d[i]) return -1;
}
return 0;
}
}
void print(bign a){
for(int i=a.len-1;i>=0;i--){
printf("%d",a.d[i]);
}
}
1066:AVL树的根(AVL)
AVL的相关模板记牢!
1067:用交换排序(贪心)
permutation n.置换;排列(方式);组合(方式)
看清题意,要求只能用0与其他数字交换!
输入N,给出0—N-1的乱序版,要求只能将数字0与其他数字交换来获得递增序列。
首先找到0所在位置,将0与其位置本来应该在的元素进行交换,这样可以通过0将一些元素交换至正确位置。
如果0回到位置0,但是还是有其他数字乱序,那么将0与之后的不在正确位置上的数字交换,再次进行以上操作,直至所有的数字都在正确位置上。
1069:数字的黑洞(数字处理)
第一次非递增排列,第二次非递减排列
1070:月饼(贪心)
1071:演讲模式(字符串处理)
输入一行字符串,以换行符做结束符。至少包含一个字母或数字组成的字符串。
输出使用最多的字符串(区分大小写)
lexicographically smallest 字典序最小
输入带空格的字符串,以换行符做结束符:
string s;
getline(cin,s);
1072:加油站(Dijkstra+DFS)
1073:科学记数法(数字处理)
输入科学记数法,输出普通记数法
科学记数法的长度不超过9999
指数的绝对值不会超过9999
1074:倒置链表
1075:PAT评分(结构体排序)
未提交该题得分状态为’-’。
注意:只有全部题目都未提交或者提交的都未通过编译,才不能参与排名
1076:微博转发(BFS)
求最多转发次数,粉丝可看到自己关注的人发的帖子并转发,不可转发自己的帖子
只计算符合间接追随者的级别数的人转发数,即有L次的转发限制
vector<vector> 二维数组:存放i的粉丝id
给出每个用户关注的人的id,和转发最多的层数,求一个id发了条微博最多会有多少个人转发
1077:Kuchiguse(最长公共后缀)
case sensitive 区分大小写
输出最长的共同后缀
(1) #include < algorithm > reverse(s.begin(),s.end());
(2) 字符串可直接等于其子串,eg: s=s.substr(2,1);
(3) getline之前使用cin要加getchar(); 或者cin.ignore();
或者使用scanf("%d\n",&n);
1079:供应链的完整销售(广义树)
理解题意,抽象为一棵树。
注意:不超过10^10应该用double型
层序遍历即可
1080:研究生录取(结构体排序)
1081:分数的加减
numerator/denominator 分子/分母
long int gcd(long int a,long int b) { //最大公倍数
if(b==0) return a;
else return gcd(b,a%b);
}
假设a,b的最大公倍数是d,则a,b的最小公约数是a/d*b
1083:列表成绩(简单排序)
1084:坏键(散列)
case insensitive 不区分大小写
capitalized 大写
1085:完美数列(双指针)
int res=0,len=0;
for(int i=0; i<n; i++) {
for(int j=i+res; j<n; j++) {
if(v[j]<=v[i]*p) {
len = j-i+1;
if(len>res) {
res = len;
} else
break;
}
}
}
1086:树的再次遍历(树的遍历)
先序遍历 非递归 用栈
(1)根据先序序列和中序序列输出后序序列:
vector<int> pre,in,post;
int n; //结点总数
void topost(int is,int ie,int ps,int pe) { //中序起始位置,中序结束位置,先序起始位置,先序结束位置
post[--n]=pre[ps]; //倒着存,应该是根右左的顺序
int i=0;
while(i<ie && in[i]!=pre[ps]) i++;
if(ie-i>0) topost(i+1,ie,i-is+1+ps,pe); //如果存在右子树,先存右节点
if(i-is>0) topost(is,i-1,ps+1,i-is+ps); //如果存在左子树,存左节点
}
(2)根据后序和中序输出先序 :
void pre(int root, int start, int end,int index) { //根据后序和中序输出先序
if(start > end) return ;
int i = start;
while(i < end && in[i] != post[root]) i++;
level[index]=post[root]; //用index保存每次的根结点
pre(root-(end-i)-1,start, i-1,2*index+1);
pre(root-1,i+1,end,2*index+2);
}
1087:条条大路通罗马(Dijkstra)
1088:分数的运算
parenthesis 括号
分数的加、减、乘、除
rational numbers 有理数
sum, difference, product and quotient 和、差、积、商
numerator 分子
denominator 分母
化简可以专门写一个函数来进行多次应用,两个long int型相乘可能会超出long long型,故在判断a、b异号时,不可用a*b < 0来判断,只能用flag标记两种异号情况来表示。
1089:插入排序或归并排序
1090:供应链中的最高价格(广义树)
与1079题相似
1091:急性脑卒中(三维数组的BFS)
pixel 像素
threshold 阈值
volume 容量,音量,体积
队列中保存的只是原元素的一个副本
1092:买或者不买(散列)
1093:数PAT的子串
最终结果对1000000007取模
柳神思路:计算PAT的个数,只要遍历字符串中的每个A,A前面的P和后面的T的乘积就是PAT的个数。
1094:最大后代(广义树的层序遍历)
1095:校园里的汽车(比较复杂的模拟,排序,重点是思路)
plate_number 车牌号
1096:连续因子(因数分解)
连乘思想,构造连乘,看其是否为n的因数,若是再判断是否比之前的长度长。
初始长度一定为0
#include <cmath>
maxx = (int) sqrt(1.0*n)+1
//注意i=2;i<=maxx;i++
1097:链表数据去重(链表)
deduplication 重复数据删除,数据去重
去除相同或绝对值相同的多余数字
将去除多余数字的链表和多余数字组成的链表均输出
1098:插入排序或者堆排序
(1)插入排序特点:每次将未排序的插入已排序序列中正确位置。
因此插入排序前面一部分有序,后面一部分乱序(与未排序前一致)
(2)堆排序特点:后面总是从小到大的,因此从后往前扫描遇到第一个比heap[1]小的元素,就与之交换,再向下调整。
1099:建立一棵二叉排序树(BST)
给出各个节点的孩子情况,输出该BST的层序遍历
1100:火星数字(进制转换)
地球语言和火星语言转换
1101:快速排序
作为主元,必须满足其左边的数都小于它,其右边的数都大于它
找有几个数可作为主元(哨兵)
给出一串序列,判断其中几个数可作为主元
1102:倒置一棵二叉树(二叉树的遍历)
输出倒置二叉树的层序遍历和中序遍历
先找根节点,没有父节点的就是根节点
1103:整数因子(DFS+剪枝)
n,k,p 整数,因子个数,指数
要求n=n[1]p+……+n[k]p
可先将从0开始到n的ip存入vector中,直到ip>n,这样之后再用直接加即可
DFS注意剪枝,只有psum+v[index]<=n才能继续DFS
nowk == k是大前提,若nowk==k,但是psum!=n时需要剪枝。
1104:计算顺序子序列之和(数学问题,注意精度)
double %lf
long double %Lf
long double和double的比较:
二者均为浮点数类型,区别如下:
(1) double类型为C++原始类型,所有编译器均支持,而long double是C99规范增加的新类型,只有支持C99的编译器才支持long double;
(2) 占用大小不同,double占8个字节,long double根据编译器实现不同,有占用8,10,12字节和16字节四种;
在long double用8字节实现时,long double 和double没有其它区别。对于其它实现方式,还有以下三项区别:
① 运算速度不同,long double占用字节多,运算速度会慢一些;
② 精度不同,long double可以表示更大的精度;
③ 表示范围不同,long double可以表示更大范围的浮点数。
1106:供应链的最低价(广义树)
同1079、1090相似
1107:社会集群(并查集)
1108:寻找平均数
break 终止整个循环,在多层循环中, 一个break语句只向外跳一层
continue 只终止本次循环,跳过剩下语句直接进行下一次循环
#include <stdio.h>
sscanf(str,"%d",&n); //将字符串str中%d的内容赋值给n
sprintf(str,"%d",n); //将n以“%d”形式写入字符串str中
1110:完全二叉树(CBT)
判断是不是完全二叉树
1111:线上地图(两次Dijkstra+DFS)
记牢Dijkstra+DFS模板
one-way 单向
1112:阻塞的键盘(字符串处理)
判断坏键,按1次可能出现k次,那么坏键的判断只有一次,不可能出现先不是坏键后来又是坏键的情况,也不可能出现先是坏键后来又不是坏键的情况。
只有出现cnt%k的时候可能是坏键,要保证该字符每次出现都会出现cnt%k才能保证是坏键。
字符一共256个,可以开标记数组标记每个键的好坏情况。已经确定s是好的。
将坏键都存放在set中。
给一段结果字符串,输出原来的字符串
字母可能重复k次(除了s)
确定坏键并输出,不能直接用map的原因是需要按照坏键发现的顺序输出,而map会自动排序
1113:整数集合划分(简单数学问题)
1114:家庭财产(并查集)
注意用两个结构体,一个用来接收数据,一个用来存放结果,
让每个家庭的最小id做根节点
1115:BST中数结点(层序遍历)
分别统计最底2层的结点数
1116:Come on! Let’s C (简单模拟)
根据排位榜输出要求查询ID所获奖项,已查询的输出Checked
1117:Eddington数字
骑手骑行有E天都超过E公里,求最大的E
#include<algorithm>//因为用了sort()函数
#include<functional>//因为用了greater<int>()
sort(a,a+len,greater<int>());//内置类型的由大到小排序
1118:森林中的鸟(并查集)
1120:朋友数(map)
1121:Damn Single(单身狗)(散列+vector)
记住要考虑那些原本就不在配对列表中的人。
若直接初始化int couple={-1}
只能初始化第一个为-1
全部初始化为-1可用fill:fill(couple,couple+100000,-1);
1125:连接绳子(贪心)
be rounded to the nearest integer that is no greater than the maximum length 向下取整
floor() 向下取整
ceil() 向上取整
round() 四舍五入
强制转换,直接截取
1127:树中的Zigzagging
先根据中序、后序建树
node* create(int ps,int pe,int is,int ie) { //后序、中序确定一棵二叉树
if(ps>pe) return NULL;
node* root=new node;
root->data = post[pe];
int k;
for(k=is; k<=ie; k++) {
if(in[k]==post[pe]) {
break;
}
}
int numleft=k-is; //左子树个数
//返回左子树的根结点地址,赋值给root的左指针
root->left=create(ps,ps+numleft-1,is,k-1);
//返回右子树的根结点地址,赋值给root的右指针
root->right=create(ps+numleft,pe-1,k+1,ie);
return root; //返回根节点地址
}
再层序遍历,用v[31]保存每层结点的数值,再按照Z字形输出即可。
1129:推荐系统(结构体排序)
需要用到结构体内部’<'重载
node(int a, int b):id(a), cnt(b) {} //方便插入和删除node
struct node {
int id,cnt;
node(int a, int b):id(a), cnt(b) {} //方便插入和删除node
bool operator < (const node &a) const { //结构体内部"<"重载
if(cnt != a.cnt) return cnt > a.cnt;
else return id < a.id;
}
};
1130:表达式(二叉树的中序遍历)
注意加括号问题:
只有右子树不为空且不是根节点时需要加括号。
1132:整数切分(简单模拟)
1133:按要求排序(链表)
vector的合并:
res.insert(res.end(),res2.begin(),res2.end()); //合并vector数组
res.insert(res.end(),res3.begin(),res3.end());
1134:点的覆盖(简单模拟)
注意使用map代替三重循环,以免超时
incident to 易发生于
1135:它是红黑树吗
红黑树的性质:
(1)结点是红色或者黑色
(2)根结点总是黑色的
(3)叶结点总是黑色的(红黑树的叶子节点不是没有子节点的节点,而是为null的结点)
(4)每个红色结点的两个子结点都是黑色的
(5)从任意结点到每个叶结点的所有路径都包含相同数量的黑色结点
1136:延迟的回文数(大整数相加+判断是否为回文数)
1137:最终成绩(排序)
1138:后序遍历
根据先序和中序输出后序的第一个数字。
void topost(int ps,int pe,int is,int ie) {
if(ps>pe) return;
int k;
for(k=is; k<=ie; k++) {
if(in[k]==pre[ps])
break;
}
int numleft=k-is;
post[--n]=pre[ps];
topost(ps+numleft+1,pe,k+1,ie);
topost(ps+1,ps+numleft,is,k-1);
}
1140:看并说序列(字符串处理)
后一个数一描述前一个数的,将前一个数分为不同的统计规格数并在下一个数输出
1141:学院的PAT排名
分数相同,根据人数递增排序,人数相同,按学院名字典序排序
1143:最低的共同祖先(LCA)
BST树,对其先序遍历,从a开始,若a在u,v之间,或者a=u或者a=v则a就是u和v的最低共同祖先。
1144:丢失的数字(map)
使用map!
然后while(++j){
if(m[j]==0) break;
}
cout << j;
1147:堆
判断是否为堆(包括大根堆、小根堆)
int minn = 1, maxn = 1;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 2; i <= n; i++) {
if (a[i] > a[i / 2]) maxn = 0;
if (a[i] < a[i / 2]) minn = 0;
}
if (maxn == 1) printf("Max Heap\n");
else if (minn == 1) printf("Min Heap\n");
else printf("Not Heap\n");
1148:狼人杀简单版本(思路!!)
in ascending order 以递增顺序
1149:危险货物打包(map+散列)
flag等到全部判断完后在讨论=0或者=1的问题
1151:二叉树中的共同祖先(LCA)
这是普通二叉树,不是BST
1152:谷歌招聘(素数)
记住i<=l-k
1153:解码PAT注册卡(结构体排序)
(1)unordered_map比map快
vector<node> v;
unordered_map<string,int> m;
//可直接将map内容插入vector中:
for(auto it:m) v.push_back({it->first,it->second});
(2)如何让map根据value排序:
typedef pair<string,int> npair;
bool cmp2(const npair &a,const npair &b) {
if(a.second!=b.second) return a.second > b.second;
else return a.first < b.first;
}
map<string,int> site;
vector<npair> vsite(site.begin(),site.end()); //让map根据value排序
sort(vsite.begin(),vsite.end(),cmp2);
for(auto it=vsite.begin(); it!=vsite.end(); it++) {
printf("%s %d\n",it->first.c_str(),it->second);
}
1155:堆的路径(DFS)
输出根到每个叶子节点的路径
满足i<=n但是2i>n && 2i+1>n的heap[i] 一定是叶结点