Vintion's blog

~夜黑路滑,社会复杂~

最系列

| Comments

最系列

常见到最长子序列,最长公共子序列等,网上总结了也很多.但自己实现一次方才了解.发现收获很多的.

目录

最长公开子序列

这个最基础,动态规划;转移方程:

C[i,j] = 0; 初始

C[i,j] = C[i-1,j-1] + 1; Xi = Yi

C[i,j] = max(C[i-1,j], C[i,j-1]); Xi != Yi;

**代码

#include <stdio.h>
#include <string.h>

int LCS(char *str1, char *str2, int m, int n, int len[][100],int sub[][100])
{
        int i,j;
        for(i=0;i<m;i++)
            len[i][0] = 0;
        for(i=0;i<n;i++)
            len[0][i] = 0;
        for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        {
            if(str1[i-1]==str2[j-1])
            {
                len[i][j] = len[i-1][j-1] + 1;
                sub[i][j] = 0;
            }
            else if(len[i-1][j]>=len[i][j-1])
            {
                len[i][j] = len[i-1][j];
                sub[i][j] = 1;
            }
            else
            {
                len[i][j] = len[i][j-1];
                sub[i][j] = -1;
            }
        }
        return len[m][n];
}

void PrintSub(char *x,int i, int j, int b[][100])
{
    if(i==0||j==0)
        return;
    if(b[i][j] == 0)
    {
        PrintSub(x,i-1,j-1,b);
        printf("%c",x[i-1]);
    }
    else if(b[i][j]==1)
        PrintSub(x,i-1,j,b);
    else 
        PrintSub(x,i,j-1,b);
    return ;
}
int main()
{
    char str1[100],str2[100];
    int len1,len2;
    int subq[100][100],subq_len[100][100]; 
    while(~scanf("%s %s",str1,str2))
    {
        len1 = strlen(str1); 
        len2 = strlen(str2); 
        int len = LCS(str1,str2,len1,len2,subq_len,subq);
        printf("%d\n",len);
        PrintSub(str1,len1,len2,subq);
        printf("\n");
    }
    return 0;
}
最长公开子串

串和序列的区别在于连续与否,两者实现也差不多

**代码

#include <stdio.h>
#include <string.h>

int LCS(char *str1, char *str2, int m, int n, char *str3, int len[][100])
{
        int i,j;
        int max = -1;
        int x,y;
        int k;
        for(i=0;i<m;i++)
            len[i][0] = 0;
        for(i=0;i<n;i++)
            len[0][i] = 0;
        for(i=1;i<=m;i++)
        for(j=1;j<=n;j++)
        {
            if(str1[i-1]==str2[j-1])
                len[i][j] = len[i-1][j-1] + 1;
            else 
                len[i][j] = 0;
            if(len[i][j]>max)
            {
                max = len[i][j];
                x = i;
                y = j;
            }
        }
        k = max;
        str3[k] = '\0';
        while(k>=0)
            str3[--k] = str1[--x];
        return max;
}

int main()
{
    char str1[100],str2[100];
    char str3[100];
    int len1,len2;
    int subq_len[100][100]; 
    while(~scanf("%s %s",str1,str2))
    {
        len1 = strlen(str1); 
        len2 = strlen(str2); 
        int len = LCS(str1,str2,len1,len2,str3,subq_len);
        printf("%s\n",str3);
        printf("%d\n",len);
    }
    return 0;
}
最大子数组和

即一个数组中连续元素和的最大值,如1,2,-4,2 最大是3

**代码: 

#include <stdio.h>
#include <limits.h>

int main()
{
    int n, a[100];
    int i,sum,tmp;
    int maxsum ;
    while(~scanf("%d",&n))
    {
        maxsum = INT_MIN;
        sum = tmp = 0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            tmp += a[i];
            if(tmp<0)
                tmp = 0;
            else
                sum = tmp;
            if(sum>maxsum)
                maxsum = sum;
        }
        if(maxsum<=0)
        {
            maxsum = a[0];
            for(i=0;i<n;i++)
                if(a[i]>maxsum)
                    maxsum = a[i];
        }
        printf("%d\n",maxsum);
    }
    return 0;
}
最大子数组

序列可以为数组,也可以为特别的结构体,原理应该是一样的 **代码:

#include <stdio.h>
#include <string.h>
//return the length
int LongIncreaseSubsquence1(int *a, int n, int *b)
{
    int i,j;
    int lenght = 1;
    if(n<=0)return 0;
    if(n==1)return 1;
    b[0] = 1;
    for(i=1;i<n;i++)
    {
        b[i] = 1;
        for(j=0;j<i;j++)
        {
            if(a[j]<a[i]&&b[j]+1>b[i])
               b[i] = b[j] + 1;
        }
    }
    for(i=1;i<n;i++)
        lenght = (lenght>=b[i]?lenght:b[i]);
    return lenght;
}
int main()
{
    int a[100];
    int b[100];
    int n,i;
    while(~scanf("%d",&n))
    {
        for(i=0;i<n;i++)
            scanf("%d",&a[i]);
        int len = LongIncreaseSubsquence1(a,n,b);
        printf("%d\n",len);
    }
    return 0;
}

还有两种方法: – 1.基于最长公共子序列,先把原串排序,再求最长公共子序列 – 2.再查找b[n]的时候,用二分法,因为b[n]是递增的序列


最大各子矩阵
最长重复子串
最长回文子串
最大M子段
字符编码距离

两个字符串,从其中一个变为另外一个需要的操作次数就是编码距离,这个或者还有其它的名词称谓.

操作只有三种最基本的,即增删改,例如abc和bcd的距离就是,abc删除a,再后面添加d,操作就两步

这种有一个很简单的方法,基于最长公共子序列,首先求出最长公共子序列int len = GetLongestCommomSubsquence(str1,str2),然后得到两个字符串长度,len1,len2.则操作的距离是len1+len2-len*2

当这几个系列的操作都了解后,好多字符串的处理都是基于此的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

class Solution {
public:
    int minDistance(string word1, string word2) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int row = word1.length() + 1;
        int col = word2.length() + 1;
        
        vector<vector<int> > f(row, vector<int>(col));

        for (int i = 0; i < row; i++)
            f[i][0] = i;

        for (int i = 0; i < col; i++)
            f[0][i] = i; 
        for (int i = 1; i < row; i++)
            for (int j = 1; j < col; j++){
                if (word1[i-1] == word2[j-1])
                    f[i][j] = f[i-1][j-1];
                else
                    f[i][j] = f[i-1][j-1] + 1;
                f[i][j] = min(f[i][j], min(f[i-1][j]+1, f[i][j-1]+1));
            }

        return f[row-1][col-1];
    }
};lass Solution {
public:
    int minDistance(string word1, string word2) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int row = word1.length() + 1;
        int col = word2.length() + 1;
        
        vector<vector<int> > f(row, vector<int>(col));

        for (int i = 0; i < row; i++)
            f[i][0] = i;

        for (int i = 0; i < col; i++)
            f[0][i] = i;

        for (int i = 1; i < row; i++)
            for (int j = 1; j < col; j++){
                if (word1[i-1] == word2[j-1])
                    f[i][j] = f[i-1][j-1];
                else
                    f[i][j] = f[i-1][j-1] + 1;
                f[i][j] = min(f[i][j], min(f[i-1][j]+1, f[i][j-1]+1));
            }

        return f[row-1][col-1];
    }
};

待续

Comments