1032 Sharing
1052 Linked List Sorting
1074 Reversing Linked List
1097 Deduplication on a Linked List
模板:注意链表为空时输出的处理方式,题目没有明说,就试试两种,一种不输出,另一种输出-1
struct Node{
int add,key,next;
XXX 其他性质
}node[1000005];
//确定在链表上的节点,清除无效结点
vector v;
while(head!=-1){
v.push_back(node[head]);
head=node[head].next;
}
//输出结果格式:add key next,且最后一个结点next为-1,特殊处理
void print(const vector& v){
int n=v.size();
//if(n==0) cout<<-1<0){
for(int i=0;i
1100 Mars Numbers
最大公约数:gcd(a,b)=gcd(b,a%b);
最小公倍数:d=gcd(a,b),a/d*b(避免相乘后溢出)
1081 Rational Sum
1088 Rational Arithmetic
注意:保证分母为正数,否则分子分母都取相反数
模板:约分在计算完成后进行,简化计算的方法—分子为0,那分母取1
//针对输入为a/b形式的,其中b>0,但可以是未约分的形式
void print(int a,int b){
if(a==0){
cout<<0;
return;
}
int t=gcd(abs(a),b);
a/=t;b/=t;
if(b==1)
printf("%d",a/b);
else if(abs(a)>b)
printf("%d %d/%d",a/b,abs(a)%b,b);
else printf("%d/%d",a,b);
}
模板:注意特殊情况1
bool isPrime(int n){
if(n<=1) return false;
int x=(int)sqrt(1.0*n);
for(int i=2;i<=x;i++)
if(n%i==0) return false;
return true;
}
素数表:用素数筛法优化,注意此时上界为maxn,不是sqrN
const int maxn=1000001;
int p[maxn],prime[maxn],pNum=0;
void Find_Prime(){
for(int i=2;i
1059 Prime Factors
一个正整数n的质因子:质因子全部<=sqrt(n)或者是一个>sqrt(n)(有可能是n本身)
模板:在素数表的基础上,枚举素因子
struct factor{
int x,cnt;
}fac[10];
//枚举1~sqrt(n)范围内的所有质因子
for(int i=0;i
这个问题等价于求正整数n的因子个数。
1023 Have Fun with Numbers
1024 Palindromic Number
1065 A+B and C (64bit)
整数的高位对应数组的高位,整数的低位对应数组的低位
struct bign{
int d[1000];
int len;
bign(){
fill(d,d+1000,0);
len=0;
}
};
bign change(char str[]){//将整数转化为bign
bign a;
a.len=strlen(str);
for(int i=0;i
int compare(const bign& a,const bign& b){
if(a.len>b.len) return 1;
else if(a.len=0;i--) //从高位开始比较
if(a.d[i]>b.d[i]) return 1;
else if(a.d[i]
bign add(const bign& a,const bign& b){
bign c;
int carry=0;//carry表示进位
for(int i=0;i=1&&c.d[c.len-1]==0) //去除高位的0,且至少保留一位
c.len--;
return c;
}
1089 Insert or Merge
1098 Insertion or Heap Sort
void insertSort(){
for(int i=1;i0&&A[j-1]>tmp){
A[j]=A[j-1];
j--;
}
A[j]=tmp;
}
}
注意非递归写法中边界条件为step/2 取出堆顶元素,将最后元素放至堆顶,并调整,循环至堆中只有一个元素为止。 1091 Acute Stroke 1068 Find More Coins 注意:DFS选择路径时,一般选择路径1后,会做一个复原处理,eg: tmp.pop_back(),即恢复到不选路径1的状态!多个结点的情况看树的先根遍历部分。 1021 Deepest Root 问题:树的层序遍历及变形问题,要求区别每一层 Note:DFS等于于树的先根遍历,BFS等价于树的层序遍历。用DFS、BFS解决的问题有时候可以转为对树的直观求解。 1020 Tree Traversals 1053 Path of Equal Weight 如果题目不涉及数据域,那就简化成vector< int > child[maxn],实际上也是邻接矩阵的表达式。 先根遍历的应用例子:一般会有题目的条件筛选路径,直接将选择指标写在参数表里,注意回溯到上一层中要将前面加入的子结点pop_back()。注意下面这种写法,其实舍去了对最开始的第一个节点的处理,如果起始节点一定确定,图可以考虑用这个方法或者每次对起始节点做处理。 1043 Is It a Binary Search Tree BST的性质:BST的中序遍历是有序的。 1034 Head of a Gang 注意:为什么路径压缩后查询两个点是否在同一棵树上,仍然要使用findroot(),而不是father[]直接记录唯一的根结点? 1066 Root of AVL Tree LL:左孩子结点平衡因子是1,Right Rotation 堆是一棵完全二叉树,可以用数组存储 1034 Head of a Gang 1003 Emergency 1040 Longest Symmetric String 边界为:dp[i][i]=1,dp[i][i+1]=(s[i]==s[i+1])?1:0 1068 Find More Coins 令dp[i][v]表示前i件物品恰好装入容量为v的背包中获得的最大价值 注意此处dp[i][v]中的v其实是v=V向w[i]变化,而且dp[i-1]只影响dp[i],为节省空间,可以用滚动数组 1057 Stack 1021 Deepest Rootconst int maxn = 1e5;
int A[maxn];
//将数组A[l1,r1]和A[l2,r2]合并成一个有序数组
void merge(int A[], int l1, int r1, int l2, int r2){
int i=l1, j=l2, temp[maxn], index=0;
while(i<=r1 && j<=r2){
if(A[i]<=A[j]) temp[index++]=A[i++];
else temp[index++]=A[j++];
}
while(i<=r1) temp[index++]=A[i++];
while(j<=r2) temp[index++]=A[j++];
for (int i = 0; i < index; ++i)
{
A[l1+i] = temp[i];
}
}
// left=0, right=n-1
void mergeSort(int A[], int left, int right){
if(left
堆排序
//倒着遍历数组,最后能够实现递增排序
void heapSort(){
createHeap();
for(int i=n;i>1;i--){
swap(heap[i],heap[1]);
downAdjust(1,i-1);
}
}
搜索
DFS
问题:给定一个序列,枚举这个序列的所有子列(可以不连续)。变形为:选择一个序列中满足要求的不连续子序列。 类比二叉树,每个结点选不选是2个分支。
模板:注意DFS()可以判断是否需要剪枝,一般先进行最优条件的判断再剪枝,否则可能会失去边界情况的分,比如最后一个数要被考虑的情况,此时sum这些数据记录的暂时是上一个index的情况。vector
BFS
1079 Total Sales of Supply Chain
1090 Highest Price in Supply Chain
1094 The Largest Generation
1106 Lowest Price in Supply Chain
模板:void BFS(int s){
queue
树
二叉树的遍历
1064 Complete Binary Search Tree
1086 Tree Traversals Again
1119 Pre- and Post-order Traversals
问题:根据先/后序遍历和中序遍历重建树
问题变形:根据中序遍历的对应的入栈出栈序列输出后序遍历结果。(题目暗示)
所有的入栈元素顺序构成的序列为树的先序遍历序列;所有的出栈元素顺序构成的序列为中序遍历序列。node* CreateTree(int preL,int preR,int inL,int inR){
if(preL>preR) return NULL;
node* root=new node;
root->data=pre[preL];
root->lchild=root->rchild=NULL;
int k;
for(k=inL;k<=inR;k++)
if(pre[preL]==ins[k]) break;//尽量避免用in,可能会和头文件重定义
int n=k-inL;
root->lchild=CreateTree(preL+1,preL+n,inL,k-1);
root->rchild=CreateTree(preL+n+1,preR,k+1,inR);
return root;
}
多个结点
模板:一般用静态表示,即child记录数组下标struct node{
typename data;
vector
模板:先根遍历的边界情况由for循环已经删去了//先根遍历
void preorder(int root){
ans.push_back(node[root].data);
for(int i=0;i
void DFS(int index,int sum){
if(sum>s) return;
if(sum==s){
if(T[index].child.size()!=0) return;
ans.push_back(tmp);
return;
}
for(int i=0;i
BST
1064 Complete Binary Search Tree
1099 Build A Binary Search Tree
1110 Complete Binary Tree
1115 Counting Nodes in a BST
void insert(node*& root,int x){
if(root==NULL){
root=new node;
root->data=x;
root->lchild=root->rchild=NULL;
return;
}
if(x==root->data) return; //查找成功,节点已存在,不插入
else if(x
node* findMax(node* root){
while(root->rchild!=NULL)
root=root->rchild;
return root;
}
node* findMin(node* root){
while(root->lchild!=NULL)
root=root->lchild;
return root;
}
void delete(node*& root,int x){
if(root==NULL) return;
if(root->data==x){//找到欲删除结点
if(root->lchild!=NULL&&root->rchild!=NULL){
node* pre=findMax(root->lchild);
root->data=pre->data;
delete(root->lchild,pre->data); //在左子树中删除pre
}
else{
if(root->lchild==NULL) root=root->rchild;
if(root->rchild==NULL) root=root->lchild;
}
}
else if(x
并查集
1114 Family Property
1118 Birds in Forest
常用于计算连通分量个数。
问题:给定结点和边,最少添加几条边使结点间都连通。例:建公路连通城市。
因为每次合并可能使得一棵树的根结点a的father变成b,此时这棵树的根结点更新成了b,但是所有原来以a为根结点的结点对应仍为a。//初始化,每个结点都是单独的集合,根节点可以用来存储集合个数。
for(int i=1;i<=n;i++)
par[i]=i;
//查找根节点
int find(int x){
while(far[x]!=x)
x=par[x];
return x;
}
//合并
void Union(int a,int b){
int pa=find(a);
int pb=find(b);
if(pa!=pb)
par[pa]=pb;
}
int find(int x){
int a=x;
while(par[x]!=x)
x=par[x];
//x存放根节点,将路径中经过的点的par改成x
while(par[a]!=a){
int tmp=a;
a=par[a];
par[tmp]=x;
}
return x;
}
int find(int x){
if(x==par[x]) return x;
else{
int v=find(par[x]);
par[x]=v;
retuen v;
}
}
//用于计算分量个数
for(int i=1;i<=n;i++)
isRoot[par[i]]=true;
for(int i=1;i<=n;i++)
ans+=isRoot[i];
//用于求每个集合中元素个数
for(int i=1;i<=n;i++)
isRoot[par[i]]++;
AVL树
1123 Is It a Complete AVL Tree
注意初始化新结点时,不要忘记对height初始化为1struct node{
int v,height;
node *lchild,*rchild;
};
//根结点的高度为1,空结点的高度为0
int getHeight(node* root){
if(root==NULL) return 0;
else return root->height;
}
int getBalance(node* root){
return getHeight(root->lchild)-getHeight(root->rchild);
}
void updateHeight(node* root){
root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
}
//Left Rotation
void L(node*& root){
node* temp=root->rchild;
root->rchild=temp->lchild;
temp->lchild=root;
updateHeight(root); //更新结点高度
updateHeight(temp);
root=temp;
}
//Right Rotation
void R(node*& root){//和RL左右都相反
node* temp=root->lchild;
root->lchild=temp->rchild;
temp->rchild=root;
updateHeight(root); //更新结点高度
updateHeight(temp);
root=temp;
}
LR:左孩子结点平衡因子是-1,先对左孩子结点做Left Rotation转化成LL型
RR:右孩子结点平衡因子是-1,Left Rotation
RL:右孩子结点平衡因子是1,先对右孩子结点做Right Rotation转化为RR型void insert(node*& root,int x){
if(root==NULL){
root=newNode(x);
return;
}
if(x
node* Create(int data[],int n){
node* root=NULL;
for(int i=0;i
堆
//对heap[low,high]进行向下调整
void downAdjust(int low,int high){
int i=low,j=i*2;
while(j<=high){
if(j+1<=high&&heap[j+1]>heap[j])
j++;
if(heap[j]>heap[i]){
swap(heap[j],heap[i]);
i=j;
j=i*2;
}
else break;
}
}
//完全二叉树叶子节点个数为n/2+1,[1,n/2]都是非叶子节点
void CreateHeap(){
for(int i=n/2;i>=1;i--)
downAdjust(i,n);
}
//将最后元素覆盖堆顶,并调整
void deleteHeap(){
heap[1]=heap[n--];
downAdjust(1,n);
}
//将添加元素放在最后并向上调整
void upadjust(int low,int high){
int i=high,j=i/2;
while(j>=low){
if(heap[j]
图
vector
图的遍历
1076 Forwards on Weibo
1107 Social Clusters
1114 Family Property
void DFS(int u,int depth){
vis[u]=true;
//如果需要对u做一些操作,可以在这进行
for(u的所有邻接点v)
if(vis[v]==false)
DFS(v,depth+1);
}
void BFS(int u){
queue
最短路
1030 Travel Plan
1072 Gas Station
1087 All Roads Lead to Rome
1111 Online Map
问题变形:某两个城市间的最短路,并且要求路线上累计的权值最大,统计最短路的条数,输出路线。动态规划
最长回文子串
令dp[i][j]表示s[i]至s[j]是否为回文子串
for(int i=0;i
01背包问题
有n件物品,每件物品的重量为w[i],价值为c[i]。现有一个容量为V的背包,问如何选取物品放入背包中,使得背包内的物品总价值最大,其中每件物品都只有一件。
for(int i=1;i<=n;i++)
for(int v=w[i];v<=V;v++)
dp[i][v]=max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]);
for(int i=1;i<=n;i++)
for(int v=V;v>=w[i];v--)
dp[v]=max(dp[v],dp[v-w[i]]+c[i]);
拓展
分块思想
问题:在线查询一个序列第K大的数。
hash数组table[N]表示整数x的存在个数,其中N为元素范围+1,将元素分为M= ceil (sqrt(N))组,每块元素不超过S=floor(sqrt(N))个,统计数组block[M]表示每组元素的个数。
//插入元素n
block[n/S]++; table[n]++;
//删除元素
block[n/S]--; table[n]--;
先利用block[]找到第K大元素所在块数,再利用table[]在块内找到这个元素
block[i]: 对应元素值[ i*S,(i+1)*S-1 ]树状数组
题目
1026 Table Tennis
1034 Head of a Gang
1057 Stack
1064 Complete Binary Search Tree
1068 Find More Coins
1087 All Roads Lead to Rome
1091 Acute Stroke
1095 Cars on Campus
1119 Pre- and Post-order Traversals