PAT算法问题模板

PAT算法问题模板

  • 常用语法
    • 函数库ctype.h
    • 函数库algorithm
    • for语句,范围for
    • 分组
  • stl模板库
    • vector
      • ​​​​​​​定义
      • 使用
    • string
      • 定义
      • 使用
  • 常见算法
      • 1.前序和中序遍历建树
      • 2.AVL平衡二叉树
        • 节点模板
        • 构建二叉树必要的一些模块化函数:
        • 函数的具体实现
      • 3.并查集
        • 常用结构
        • 常用的算法操作
        • 算法实现
        • 并查集的应用
      • 4.堆的使用
        • 常用结构
        • 常用算法操作
        • 算法实现
        • 堆的应用
    • 归并排序
      • 算法实现
      • 归并排序的应用
    • Hash表
      • 1.平方探测法
        • 建表
        • 查询
    • 动态规划
      • LIS(最长不下降子序列)
        • 方法1
        • 方法2
    • 动态查询
      • 分块查询
        • 方法
      • 树状数组
        • 用的函数与数据结构
        • 函数的具体实现

常用语法

函数库ctype.h

  1. 大写变小写
    tolower(char c);返回c的小写

  2. 小写变大写
    toupper(char c);返回c的大写
    总结:一次只能用于一个字母

  3. 判断字符是否是字母
    isalpha(char c);返回bool

  4. 判断是否为数字
    isdigit(char c);返回bool

  5. 判断字符是否为字母和数字
    isalnum(char c);返回bool

  6. 判断字符是否为大写或者小写字母
    isupper(char c),islower(char c);返回bool

函数库algorithm

1.max_element(),min_element();
返回迭代器,默认是从小到大排序,max返回最后一个元素,min返回第一个元素。可以自己构造cmp函数,让它排序
2.reverse(iterator a,iterator b);将两个迭代器之间的元素翻转,b是所指元素的下一个位置。

for语句,范围for

  1. 除了一般的循环,还有遍历功能,如

    for(声明:序列),然后就会遍历了。

分组

1.对于一个序列,把它分组。

int temp = np,group;//temp为当前序列长度
    while(a.size()!=1)
    {
        if(temp%ng==0) group = temp/ng;//先计算可以分出多少组
        else group = temp/ng + 1;
        for(int i=0;i=temp) break;//元素遍历多了,自动跳出,最后一个组元素不够
                int front = a.front();
                if(m[k].w

stl模板库

vector

​​​​​​​定义

  1. vector< typename> v;
  2. vector< typename> v(n); 定义一个vector,包含n个元素,都默认初始化。
  3. vector< typename> v(n,1);定义一个长度为n的向量,里面的元素初始值为1。
  4. vector< typename>
  5. vector< typename> v1(v.begin(),v.end());定义了一个v1,里面的内容为v,其实也可以复制一部分。括号里面必须是地址或者迭代器。

使用

  1. v.resize(n),把vector设置为长度为n,并且初始化。

string

定义

  1. string s;

使用

  1. 常用函数to_string(),将常用格式转化成为string格式
  2. string可以加减和赋值以及比较。前加和后加操作灵活。
  3. stoi可以将string化为整数返回。
  4. string.rbegin(),string.rend();反向迭代器。
  5. string.substr(pos,len);pos是位置,len是长度。pos不是迭代器。不能用迭代器。
  6. string.erase(iterator);删除单个元素,string.erase(pos,len);从pos开始删除len长的子串string.erase(pos);从pos开始,后面全部删除。string.erase(it1,it2),删除两个迭代器之间的元素。

常见算法

1.前序和中序遍历建树

   void creat(node* &root,int prel,int prer,int inl,int inr)
        {
            if(prel>prer) return;
            int u = pre[prel];
            root = newnode(u);
            int k;
            for(int i=inl;i<=inr;i++)
            {
                if(u==in[i])//在中序序列中找到这个根节点
                {
                    k = i;
                    break;
                }
            }
            int numleft = k-il;
            creat(root->left,prel+1,prel+numleft,inl,inl+numleft-1);
            creat(root->right,prel+numleft+1,prer,inl+numleft+1,inr);
        }

2.AVL平衡二叉树

节点模板

平衡二叉树重要的是要记录高度,用来算平衡因子
struct node{
int val,height;
node* left,*right;
};

构建二叉树必要的一些模块化函数:

node* newnode(int v)//建立节点
int getheight(node* root)//得到节点高度
int getbalancefactor(node* root)//得到节点的平衡差值
void updateheight(node* root)//节点变动之后,更新节点参数
void L(node* &root)//左旋
void R(node* &root)//右旋
void insert(node* &root,int x)//插入节点

函数的具体实现

node* newnode(int v)
{
    node* now = new node;
    now->height = 1;
    now->val = v;
    now->left = NULL;
    now->right= NULL;

    return now;
}

int getheight(node* root)
{
    if(root==NULL) return 0;
    return root->height;
}

int getbalancefactor(node* root)
{
    //获得左右子树的高度差
    return getheight(root->left)-getheight(root->right);
}

void updateheight(node* root)
{
    root->height = max(getheight(root->left),getheight(root->right))+1;//要是和getheight互换,那么每次查询高度差都要计算,可能会超时。更新计算
}

void L(node* &root)
{
    node* temp = root->right;
    root->right = temp->left;
    temp->left = root;
    updateheight(root);
    updateheight(temp);
    root = temp;
}

void R(node* &root)
{
    node* temp = root->left;
    root->left = temp->right;
    temp->right= root;
    updateheight(root);
    updateheight(temp);
    root = temp;
}

void insert(node* &root,int x)
{
    if(root==NULL)
    {
        root = newnode(x);
        return;
    }

    if(x < root->val)
    {
        insert(root->left,x);
        updateheight(root);
        if(getbalancefactor(root)==2)
        {
            if(getbalancefactor(root->left)==1)
            {
                R(root);
            }else
            {
                L(root->left);
                R(root);
            }
        }
    }else{
        insert(root->right,x);
        updateheight(root);
        if(getbalancefactor(root)==-2)
        {
            if(getbalancefactor(root->right)==-1)
            {
                L(root);
            }else
            {
                R(root->right);
                L(root);
            }
        }
    }
}

3.并查集

常用结构

father[maxn];数组,指向父亲下标。开始的时候都指向自己。是一个集合的概念。

常用的算法操作

init();初始化father数组,每个的结点都指向自己
findfather(int x);找到x结点的根节点。最好把路径上的结点都更新指向根节点。
Union(int a,int b);若a,b不在同一个集合,合并他们。

算法实现

void init()
{
    for(int i=1;i

并查集的应用

常用于判断哪些是属于一个集合。

4.堆的使用

常用结构

数组heap[N+1]或者vector heap[N+1];
堆是一颗特殊的数,通常用层序的方法来存,所以从1到N来存,方便处理

常用算法操作

downadjust(int low,int high);将上方的点往底层调整
upadjust(int low,int high);将下方的点往顶层调整
creat();创建堆。
选向下调整复杂度为O(n) ,从n/2开始往1一个一个调整
选向上调整复杂度为O(nlogn),从2开始往n一个一个调整
heapsort();堆排序。若要从小到大排序,就建立大顶堆,大到小排序,就建立小顶堆。
deletetop();删除堆顶元素
insert(int x);添加元素

算法实现

void downjust(int low,int high)
{
    int i = low,j = i*2;
    while(j<=high)
    {
        //找出两个孩子结点中的最大值
        if(j+1<=high&&heap[j+1]>heap[j])
        {
            j = j+1;
        }
        //如果孩子结点中的最大值比欲调整的结点大
        if(heap[j]>heap[i])
        {
            swap(heap[i],heap[j]);
            i = j;
            j = j*2;
        }else
        {
            break;//若有一个不满足,那么证明后面的都已经调整好了
        }
    }
}
void upadjust(int low,int high)
{
	int i =high,j = i/2;
	while(j>=low)
	{
		//父亲权值小于欲调整的结点i的权值
		if(heap[j]0;i--)
    {
        downjust(i,N);//自底向上复杂度低
    }

}
void heapsort()
{
    for(int i=N;i>1;i--)
    {
        swap(heap[1],heap[i]);
        downjust(1,i-1);
    }
}
void deletetop()
{
    heap[1] = heap[n--];
    downadjust(1,n);
}
void insert(int x)
{
	heap[++n] = x;
	upadjust(1,n);
}

堆的应用

常用于排序题。排序的复杂度为O(nlogn)

归并排序

算法实现

void MergeSort(vector &v)
{
    bool flag = false;
    for(int step=2;step/2<=N;step*=2)
    {
        for(int i=0;i

归并排序的应用

题目中一般是一步一步的,但是用sort和真正的归并排序不一样,真正的是先左边再右边,而用hash是不管左右的,都是以2的幂次方分组的。

Hash表

1.平方探测法

建表

for(int i=0;i

查询

  for(int i=0;i<=tsize;i++)//这个最多要查询tsize+1次
    {
        int pos =(a+i*i)%tsize;//a为要查询的数字,pos是位置
        if(hashtable[pos]==a||hashtable[pos]==0)//无论是找到了数字,还是当前位置为空查找都结
        {                                       //束了
            break;
        }
    }
  • 注意:建立最多循环tsize次,查询最多tsize+1次。而且查询结束有两种情况,找到算一种。表中元素为空,代表这个元素
    没在hash表中。因为这个位置为空,平方探测法计算的下一个位置也一定为空。

动态规划

LIS(最长不下降子序列)

方法1

dp[i] 表示以A[i]结尾的最长不下降子序列长度。
状态转移方程
dp[i] = max{1,dp[j] + 1}
(j = 1,2…,i-1&&A[ j ] < A[ i ])

算法思想:对于每个元素,在元素 i 前面找标号小于它的元素,这些元素里面有最长子序列长度的,元素 i 接在他后面,若前面所有元素的标号都大于他,那么他自己单独作为最长不下降子序列,长度为1.

for(int i=1;i<=n;i++)
{
	dp[i] = 1;
	for(int j=1;j=A[j]&&(dp[j]+1>dp[i}){
			dp[i] = dp[j] +1;
		}
	}
	ans = max(ans,dp[i]);//最终的ans就是答案。
}

方法2

dp[i] 表示在子序列中下标为i的元素结尾的当前序列的最长不下降子序列长度。
状态转移方程
dp[i]++
for(int j=i+1;j dp[j] = max{dp[j],dp[j-1]};

算法思想:最开始的时候dp[]数组里面全部为0,当第一个元素来的时候,对应的下标数组元素+1,大于这个下标的元素可以选择接在原先的序列后面,或者这个新元素后面。所以取最大值。

动态查询

分块查询

方法

建立两个数组,一个存每个数出现的次数,一个存块内元素出现的次数

树状数组

用的函数与数据结构

c[maxn] c[i] 存的是小于i,范围为lowbit(i)范围数据的多少
lowbit(i) ((i)&(-i)) 可以用宏定义
update(int x,int num);更新元素x的相关数组,更新的增量为num
getsum(int x);得到小于等于x的元素个数;

函数的具体实现

int c[maxn];
#define lowbit(i) ((i)&(-i))
void update(int x,int num)
{
    for(int i = x;i
int getsum(int x)
{
    int sum = 0;
    for(int i=x;i>0;i-=lowbit(i))
        sum+=c[i];
    return sum;
}

你可能感兴趣的:(pat)