补充:需要掌握的算法

01背包、多重背包、完全背包

使用一维数组的版本:
01背包:

int main() {
    int n,m;
    while(cin>>n>>m) {
        vector weight(n+1,0);//物品的重量
        vector value(n+1,0);//物品的价值
        vector dp(m+1,0);//一维数组,存放用n个产品装容量为i的背包的解
        for(int i=0;i>weight[i+1]>>value[i+1];//输入

        for(int i=1;i<=n;i++)
            //这里是逆序
            //用j>=weight[i]作为判断条件,省略了一个if语句
            for(int j=m;j>=weight[i];j--) {
                    dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);

        cout<

多重背包:
多重背包是指在01背包的基础上,物品的个数有限制可以是0-n个。解决这类问题的思路是将其转化成01背包,具体的方法就是n个添加同样属性的物品就可以了。

完全背包:
只需要将上面的逆序改为顺序

for(int i=1;i<=n;i++)
        //这里变成了顺序
        //这里设j从weight[i]开始,省略了一个if语句
        for(int j=weight[i];j<=m;j++)
                dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);

O(nlogn)的排序

快排(单向扫描版)

int partition(int a[], int l, int r) {
    int x = a[l];//选择a[l]作为选定元素
    int i = l;
    int j = l+1;
    for (; j <= r; j++)
        if (a[j] < x) //如果a[j]小于x,就将它交换到前面去
            swap(&a[++i], &a[j]);
    swap(&a[l], &a[i]);//最终将a[l]交换到正确的位置上
    return i;
}

void quick(int a[],int l,int r) {
    if (l>=r) return;//如果子区间为0或1个元素,就可以结束递归调用

    int i = partition(a,l,r);
    quick(a,l,i-1);
    quick(a,i+1,r);
}

归并排序

int b[maxN]; //辅助数组

void partition(int a[],int l,int r) {
    int i,j,k;
    int m = (l+r)/2;
    //将排好序了的两个子数组:a[1~m]和a[m+1~r]放入辅助数组b中
    for (i=l;i<=r;i++) b[i]=a[i];

    //i和j分别指向两个子数组的开头
    i=l;
    j=m+1;
    k=l;
    while(i<=m && j<=r) {
        if (b[i]=r) return;

        int m = (l+r)/2;
        merge(a,l,m);
        merge(a,m+1,r);
        partition(a,l,r);
    }

堆排序

堆本质上是完全二叉树,用数组(vector)表示。首先定义一个数组,用来表示堆。

int N=0;
vector heap(100005,0);

上浮和插入操作:

void Up(int k) {
    while(k>1 && heap[k/2]

下沉和删除操作:

void Down(int k) {
    int j;
    while(2*k<=N) {//如果没到达树底
        j=2*k;
        if(jheap[j]) 
	        j++;//找到子节点中较大的那个
        
        if(heap[k]>heap[j]) 
	        break;//如果父节点比子节点都大,退出
        swap(heap[k],heap[j]);
        k=j;
    }
}

int deleteMax() {
    swap(heap[N],heap[1]);
    N--;
    Down(1);
    return heap[N+1];
}

堆排序:

void PQsort(int a[],int l,int r) {
    int k;
    for (k=l;k<=r;k++) insert(a[k]);
    for (k=r;k>=l;k--) a[k]=deleteMax();
}

迪杰斯特拉算法

int main() {
    int n,m,s,t;//分别是节点数、边的条数、起点、终点
    while(cin>>n>>m>>s>>t) {
        vector> edge(n+1,vector(n+1,0));//邻接矩阵
        vector dis(n+1,0);//从起点出发的最短路径
        vector book(n+1,0);//某结点已经被访问过

        for(int i=1;i<=n;i++)//初始化邻接矩阵
            for(int j=1;j<=n;j++)
                if(i!=j) edge[i][j]=INT_MAX;

        int u,v,length;
        for(int i=0;i>u>>v>>length;
            if(length dis[index]+edge[index][i]) 
                    dis[i] = dis[index]+edge[index][i];
            }
        }
        
        cout<

并查集

#include  
using namespace std;  

int  pre[1050];     //保存节点的直接父节点

//查找x的根节点 
int find(int a){  
    if(pre[a]!=a)  
        pre[a]=find(pre[a]);//路径压缩,本结点更新为根结点的子结点  
    return pre[a];  
} 
//连接两个连通块
void join(int x,int y) {  
    int fx=Find(x),fy=Find(y);  
    if(fx!=fy) pre[fy]=fx;  
}   

int main() {  
    int N,M,a,b,i,j,ans=0;  
    while(scanf("%d%d",&N,&M) && N) {
        //初始化pre数组
        for(i=1;i<=N;i++) pre[i]=i;  
        //根据连通情况,构建pre数组
        for(i=1;i<=M;i++) {  
            scanf("%d%d",&a,&b);  
            join(a,b);
        }  

    for(i=1;i<=N;i++) 
        if(pre[i]==i) ans++; //计算连通子图的个数ans

    cout<

拓扑排序

若用邻接表表示图的信息,则有:

int in[100001]={0};//记录每个节点的入度
vector > edge[100001]; //邻接表

int main() {
	int n,m;//节点数和顺序关系的数量
	
    while(cin>>n>>m) {
        int from,to;
        int i,k;
        int index;
        int cnt=0;
        
        for(i=1;i<=m;i++) {//初始化每个节点的入度
            cin>>from>>to;
            edge[from].push_back(to);
            in[to]++;
        }

        for(k=1;k<=n;k++) 
        {
            index=0;//当前这轮确定了的节点编号

            bool valid = false;
            for(i=1;i<=n;i++) {
                if(in[i]==0) {//若某个未确定节点的入度为0
                    index=i;
                    cnt++;
                    in[i]--;
                    valid = true;
                    break;
                }
            }
            if(!valid) {//如果在未确定的节点中,找不到入度为0的
                cout<<"Wrong"<

KMP算法

本质上,是利用匹配子串的最长公共前后缀的信息来提高效率。

void makeNext(string P,vector &next) 
{
    int q,k;
    int m = P.size();
    next[0] = 0;
    for (q = 1, k = 0;q < m;q++) 
    {
        while(k > 0 && P[q] != P[k])
            k = next[k-1];
        if (P[q] == P[k])
            k++;
        next[q] = k;
    }
}

int kmp(string T,string P,vector &next) {
    int n=T.size();
    int m=P.size();
    int i=0,q=0;
    int ans=0;
    for (;i < n;i++) {
        while(q > 0 && P[q] != T[i]) 
            //如果失配了,退回q-(q-next[q-1]) = next[q-1]位
            q = next[q-1]; 
        if (P[q] == T[i]) //如果当前字符匹配成功,q后移一位
            q++;
        if (q == m) //如果已经成功匹配一次
            ans++;
    }
    return ans;
}

int main() {
    int N;
    string mo,str;
    cin>>N;  
    while(N--) {  
        cin>>mo>>str;
        vector next(mo.size(),0);
        makeNext(mo,next);//构建部分匹配表
        cout<

你可能感兴趣的:(leetcode)