PAT常用模板梳理

PAT常用模板梳理

1.DFS+Dijkstra

(description): 最短路径问题,如果约束条件不复杂的话直接写个Dijkstra就可以了。如果约束条件比较复杂的话那么可以先利用Dijkstra把所有搜索到的可疑路径先用图的结构存储起来,然后再采用dfs进行搜索。

void Dijkstra(int n){//利用Dijkstra把所有满足cost最小的路径采用pre[N]的邻接链表结构进行存储
    int newP = st;
    fill(dis,dis+n,inf);
    fill(mark,mark+n,false);
    dis[newP] = 0;
    mark[newP] = true;
    int T=n;
    while(T--){
        for(int i=0;i<Vec[newP].size();i++){
            int tmp_v = Vec[newP][i].v;
            int tmp_c = Vec[newP][i].c;
            if(mark[tmp_v])continue;
            if(dis[newP]+tmp_c<dis[tmp_v]){
                dis[tmp_v] = dis[newP]+tmp_c;
                pre[tmp_v].clear();
                pre[tmp_v].push_back(newP);
            }
            else if(dis[newP]+tmp_c==dis[tmp_v]){//处理多条结果相同的路径
                pre[tmp_v].push_back(newP);
            }
        }
        int minn = inf;
        for(int i=0;i<n;i++){
            if(!mark[i]&&dis[i]<minn){
                newP = i;minn = dis[i];
            }
        }
        mark[newP]=true;
    }
}
void dfs(int x){//利用dfs对邻接链表pre进行搜索,以此判断每一条路径是否满足条件
    tmp.push_back(x);
    if(x==target){
        judge and calculate
    }
    for(int i=0;i<pre[x].size();i++)dfs(pre[x]);
    tmp.pop_back();
}

2.并查集

description:并查集一般用于处理集合的相关问题。

fill(Tree,Tree+n,-1);
int findRoot(int x){//查找根结点
    if(Tree[x]==-1)
        return x;
    else
        return Tree[x]=findRoot(Tree[x]);
}
void Union(int x,int y){//合并两个结点所在的集合
    int rootA = findRoot(x);
    int rootB = findRoot(y);
    if(rootA!=rootB)
        Tree[rootA]=rootB;
}

同时能用并查集解决的方法一般也可以采用dfs进行解决,以判断一个图中联通域的个数为例。

void dfs(int x){
    if(!vis[x])
        vis[x]=true;
    for(int i=0;i<Vec[x].size();i++)
        dfs(Vec[x][i]);
}
int main(){
    int cnt=0;
    for(int i=0;i<n-1;i++){
        if(!vis[i]){
            dfs(i);
            cnt++;
        }
    }
}

3.树的创建

对于:
①前序+中序->后序/层序 以及 后序+中序->前序/层序 均不需要进行建树
②对于BST,CBT以及AVL Tree的相关操作需要进行建树。

前序+中序->后序

int Pre[N],In[N];
vector<int> Post;
int build(int sp,int ep,int si,int ei){
    if(sp>ep)return;
    int i=si;
    while(i<=ei&&In[i]!=Pre[sp])i++;
    int len = i-si;
    build(sp+1,sp+len,si,i);
    build(sp+len+1,ep,i+1,ei);
    Post.push_back(Pre[sp]);
    return sp;
}

后序+中序->层序

//PAT 1020
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int N = 30+5;
int Post[N],In[N],n;
vector<int>Vec;
map<int,int>Ma;
bool cmp(int a,int b){return Ma[a]<Ma[b];}
void build(int ist,int ied,int pst,int ped,int idx){
    if(ist>ied)return;
    int i=ist;
    while(i<=ied&&In[i]!=Post[ped])i++;
    int len = i-ist;
    Vec.push_back(Post[ped]);Ma[Post[ped]]=idx;
    build(ist,i-1,pst,pst+len-1,2*idx+1);
    build(i+1,ied,pst+len,ped-1,2*idx+2);
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>Post[i];
    for(int i=0;i<n;i++)cin>>In[i];
    build(0,n-1,0,n-1,0);
    sort(Vec.begin(),Vec.end(),cmp);
    for(int i=0;i<n;i++){
        cout<<Vec[i];
        if(i!=n-1)cout<<" ";
    }
    return 0;
}
/*
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
*/

BST的构建

Vec[root] = data;
void Insert(int root,int x){
    if(Vec[root]<x){
        if(Vec[root][0]==-1)
            Vec[root][0]=x;
        else
            Insert(Vec[root][0],x);
    }
    else{
        if(Vec[root][1]==-1)
            Vec[root][1]=x;
        else
            Insert(Vec[root][1],x);
    }
}

AVL树的构建

struct Node{
    Node *l,*r;
    int data;
};
Node* leftRotate(Node*tree){
    Node* tmp = tree->r;
    tree->r = tmp->l;
    tmp->l = tree;
    return tmp;
}
Node* rightRotate(Node*tree){
    Node* tmp = tree->l;
    tree->l = tmp->r;
    tmp->r = tree;
    return tmp;
}
Node* leftRightRotate(Node*tree){
    tree->l = leftRotate(tree->l);
    return rightRotate(tree);
}
Node* rightLeftRotate(Node*tree){
    tree->r = rightRotate(tree->r);
    return leftRotate(tree);
}
int getHeight(Node*tree){
    if(tree==NULL)
        return 0;
    else
        return max(getHeight(tree->l,tree->r))+1;
}
void Insert(Node*tree,int x){
    if(tree==NULL){
        tree = new Node;
        tree->data = x;
    }
    else if(tree->data<x){
        Insert(tree->l,x);
        int lh = getHeight(tree->l);
        int rh = getHeight(tree->r);
        if(lh-rh>1){
            if(x<tree->l->data){
                tree = rightRotate(tree);
            }
            else{
                tree = leftRightRotate(tree);
            }
        }
    }
    else{
        Insert(tree->r,x);
        int lh = getHeight(tree->l);
        int rh = getHeight(tree->r);
        if(rh-lh>1){
            if(x>tree->l->data){
                tree = leftRotate(tree);
            }
            else{
                tree = rightLeftRotate(tree);
            }
        }
    }
}

判断某一棵树是否是完全二叉树
判定方法:进行分level order travelsal,当出现一个结点存在空子树的时候,其后续访问的结点的子树必须均为空。

已知前序和后续,判断二叉树是否唯一,如果唯一则输出中序遍历的结果。如果不唯一则输出任意一颗满足条件的二叉树的中序遍历结果。

#include <iostream>
#include <vector>
using namespace std;
const int N = 30+5;
int Pre[N],Post[N],n;
vector<int> In;
bool flag=true;
void build(int prst,int pred,int post,int poed){
    if(prst==pred){//达到了继续细分的终止条件
        In.push_back(Pre[prst]);
        return;
    }
    if(Pre[prst]==Post[poed]){
        int i=prst;
        while(i<=pred&&Pre[i]!=Post[poed-1])i++;
        if(i-prst==1)//此时整段待划分的区域可以完全位于左子树也可以完全位于右子树
            flag = false;
        build(prst+1,i-1,post,post+i-prst-1-1);//左子树
        In.push_back(Pre[prst]);
        build(i,pred,post+i-prst-1,poed-1);//右子树
    }
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)cin>>Pre[i];
    for(int i=0;i<n;i++)cin>>Post[i];
    build(0,n-1,0,n-1);
    if(flag) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    for(int i=0;i<In.size();i++){
        cout<<In[i];
        if(i!=In.size()-1)cout<<" ";
        else cout<<endl;
    }
    return 0;
}

利用给定的sequence构造满足完全二叉树的BST

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
vector<int>Vec,res;
void getLevelOrder(int st,int ed,int idx){
    if(st>ed)return;
    int n = ed - st + 1;//注意这里的n为当前子树的结点个数,n不能声明为全局变量。
    int l = log2(n+1);
    int leaf = n - (pow(2,l)-1);
    int rootIdx = st+(pow(2,l-1)-1)+min((int)pow(2,l-1),leaf);
    res[idx] = Vec[rootIdx];
    getLevelOrder(st,rootIdx-1,2*idx+1);
    getLevelOrder(rootIdx+1,ed,2*idx+2);
}
int main()
{
    int n;
    cin>>n;
    Vec.resize(n);res.reserve(n);
    for(int i=0;i<n;i++) cin>>Vec[i];
    sort(Vec.begin(),Vec.end());
    getLevelOrder(0,n-1,0);
    for(int i=0;i<n;i++){
        cout<<res[i];
        if(i!=n-1) cout<<" ";
    }
    return 0;
}

补充

但涉及到大数运算的问题的时候要学会时候python来解决,节约时间。
以下面的大数起泡排序为例:

n = eval(input())
li=list(map(int,input().split()))
for i in range(n):
	for j in range(n-i-1):
		if li[j]>li[j+1]:
			tmp = li[j]
			li[j] = li[j+1]
			li[j+1] = tmp
for i in range(n):
	print(li[i],end="")
	if i!=n-1:
		print(" ",end="")

错误总结:

读题:
① 一定要把题目中的字眼都读出来,对于每一道题不要看到一半就开始动手,最好先把实例自己先用纸推演一遍,确保自己的思路无误后方才动手。
② 遇到不懂的单词不要慌张,尽量用所给的样例去推测。
③ 感觉每天道题总会有一些情况没有考虑到
④ 不要急着动手,动手前先想清楚应该采用什么样的数据类型进行存储,采用这个数据类型有没有存在什么漏洞。
编码:
① 在嵌套使用for循环的时候,记住不要重复使用循环变量,尤其是在写Dijkstra算法的时候。
② Dijkstra初始化话dis数组的时候最好初始化为最大值,免得后面比较判断的时候忘记考虑dis[i]=-1的情况了。
③ 在复制粘贴的时候一定要仔细检查好相关的变量是否已经修改过来。
④ 采用INT_MAX必须导入头文件
⑤ memset函数暂时不要使用,[来自柳神笔记:memset只能赋值0,-1和最大值,因为memset函数是按位赋值的,如果想要赋一个特定值,则采用fill函数,将arr[100]赋值为全-1的调用如下fill(arr,arr+100,-1),头文件为]
⑥ atoi是用来转换char c[100]的字符串,而stoi是用来转换string类型的.
⑦ 头文件中的max_element()函数可以返回数组中最大元素的地址,样例代码如下所示:
int A[5]={1,3,5,7,9};
int* p = max_element(A,A+5);
int idx = p-A;
⑧ String输入一行,空行作为结束,示例代码
string str;
while(getline(cin,str)&&str!=””){
//
}
⑨ 如果超时了,同时采用了map或者set,且当题目对于数据结构里面元素的顺序没有要求的时候,可以采用unordered_map和unoredered_set,对应的头文件为<unordered_map>和<unoredered_set>
⑩ 以后所有的define全都改成const,define只在编译的阶段进行替换,不像const在运行时还有进行类型的检查,因此最好采用const。[1013]
⑪ 同一份代码,多次提交,超时的用例可能就会通过。[1013]【这种情况在考试的时候是比较危险的】
⑫ 不满四位的整数进行补0处理printf(“%04d”,a)
⑬ Printf(“%.2f”),保留两位小数,是自带四舍五入功能的
⑭ 当编写bfs的时候,取出队首元素的时候记得顺便把它弹出来
⑮ 对于浮点型的相等比较,需要通过abs(a-b)<1e-7来实现,abs()的浮点型函数需要自己重新定义。
⑯ 构建二叉搜索树的时候,记得要给左右子树赋值
T->lchild = Insert(T->lchild,x);
T->rchild = Insert(T->rchild,x);
⑰ 在写结构体排序的时候,如果在operator<中定义>=号的话会出现段错误,改为>即可,所以说不能出现相等的情况?
⑱ Pow函数在Cmath函数的头文件里面
⑲ 字符串转大小写transform(str.begin().str.end(),str.begin(),::tolower/::toupper),单个字符转小写tolower©
⑳ 字符串按照空格记进行分割
#include
stringstream ss(str);
while(ss>>tmpstr){
cout<<tmpstr<<endl;
}
按照逗号进行分割
#include
stringstream ss(str);
while(getline(ss,tmpstr,’,’)){
cout<<tmpstr<<endl;
}
21.可以直接用数组的下标作为索引的话,就不要用map了,以免超时。
22.对于规模超过 的数据输入输出最好统一采用scanf()和printf()避免超时。

生词表:

Chronologically 同时地
Decimal system 十进制系统
Radix 基数
scattered cities 分散的城市
Vertex/vertices 顶点
even number 偶数
streets intersections 街道交叉口
family hierarchy 家庭层级
pedigree tree 谱系数
for the sake of 为了…
every seniority level 每个资历层级
traversal 遍历
acyclic 非周期性的
gang 团伙,帮派
liars 说谎者
descendants 后人
N distinct integers N个不同的整数
are partitioned into 被划分为
Quadratic probing 二次探测
with positive increments only 只考虑正的增量
Maximal Clique 最大团
subtle 微妙
in the first place 首先
analogously 类似的
having a crush on 迷恋上
Recommendation System 推荐系统
at the time 当时
parentheses 括号
the precedences of the operators 运算符的优先级
be rounded to [The result must be rounded to the nearest integer that is no greater than the maximum length.这句话有点意思] 四舍五入到
dangling with more than one companion. 牵挂布置一个伴侣
property 财产
Formation 编队
Spiral Matrix 螺旋矩阵
synonyms 同义词
lexicographically 字典顺序
quota 名额
Deduplication 去冗余
inventory 库存
bakery 面包店
lottery 抽奖
collaborate with 与…合作
gamblers 赌徒
chopping 切断
case sensitive 区分大小写
capital letter 大写字母
abbreviation 缩写
notorious 臭名昭著
particles 粒子/助词
exaggerated 夸张地
numerator 分子
denominator 分母


2019.9.8

最后说一些题外话,

经过了一个多月的刷题之后,大概刷了131到左右,刷题的代码都放在了here
在这里插入图片描述

终于踏上了9月8号的PAT考场,最后成绩也还算可以接受,虽然有个样例超时没过有点可惜,但95对于我而言已经不错了。所以算是兑现了自己1个月的准备吧。
在这里插入图片描述


2019.9.16

拿着PAT证书心想着要是进了浙大复试就不用忙着准备机试了,可以安心的梳理项目和专业课,去实验室找老师啦。但是,最后都没有收到面试的短信通知,在得知自己排名的前一位收到了之后有些心灰意冷,要是第六学期的排名没有下降那么就可以参加zju的复试了,要是提前一点联系导师会不会就有新的契机,哪有那么多要是呢…其实心里难免会有一些遗憾,但是呢至少这个选择是无悔的,谁知道呢,这未必是一件坏事,而且我比较看重导师,那么去zju能争取到心仪方向的导师吗,也未必。

所以呢,一阶段有一阶段该完成的事,面临机遇时可能会有遗憾,但是内心无悔,清晰地认识到自己的每一个决定那就足够了。而且去现在这个学校的导师组心理还是比较开心的,毕竟至少学校的平台可以,方向是自己喜欢的,而且导师的人品和学术能力都很nice,就业和实习的情况也挺乐观的!塞翁失马,祸兮福所倚。过程重要还是结果重要呢?

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值