zoukankan      html  css  js  c++  java
  • 算法复习周------“动态规划之‘最长公共子序列’”&&《计蒜课》---最长公共子串题解

    问题描述: 这个问题其实很容易理解。就是给你两个序列X={x1,x2,x3......xm} Y={y1,y2,y3......ym},要求找出X和Y的一个最长的公共子序列。

    例:Xi={A, B, C, B, D, A}    Yj={B, C, A, B, A}  求得 Z={B, C, B, A}

    问题详解: 那么问题来了,我们如何去求解出最终的过程呢?既然是复习周,那我就开门见山,直接用DP算法去解决这个问题。

    分析:该问题具有最优子结构的性质。

    这里我们使用上面的那个例子:我们此时倒着进行分析

    ①当我们知道了最长公共子序列为Z={B,C,B,A}的时候,我们知道当取Xi序列的最后一个值x6=A与Yi序列的最后一个值Y5=A,此时X6=Y5,则z4=X6=Y5,就得出来 Z1~Z3 为 X1~X5 与 Y1~Y4 的最长公共子序列。

    ②再往前走,X5=D而Y4=B我们知道  x5!=Y4  所以Z1~Z3是  X1~X5 与 Y1~Y3的子序列 或者是 X1~X4 与 Y1~Y4的子序列(这里这个例子是——Z{B,C,B}是A{A,B,C,B}与B{B,C,A,B}的公共子序列)

    也许文字不太好理解,但是我们由此可以归纳出一个递推公式:

    而C[i][j]中存的是序列X1~Xi与序列Y1~Yj的最长公共子序列长度。

    下面我们来看具体的寻找方法——>

      这里我们放一道例题:

    给定两个序列为X=<A, B, C, B, D, A, B>和 Y=<B, D, C, A, B, A>,求最长公共子序列?

    这个时候我们需要递归来填写出数组中的数字。

    ①我们来画出这个二维数组。

    ②因为0行0列并没有实际的意义,所以我们填上0。

    ③之后,我们开始递归写表。此时我们要知道,行数1~7代表X的各个数字,而列为Y的数字。当i=1是代表我拿出来X数列中的A,j=1代表我拿出来Y数列中的B。然后比较发现A!=B  所以我们判断max(C[0][1],C[1][0])--其实我们写算法的时候都默认从上面继承下来。发现都是0,所以C[1][1]=0。

    ④同样的情况一直到C[1][4]这个地方,此时我们发现X1=A,Y4=A。X1=Y4。所以我们调用C[i][j]=C[i-1][j-1]函数,从左上角继承下来。C[1][4]=C[0][3]=0+1=1。

     。。。。。最后填写完成后为:

    (其实算法思想很简单,就是当前两个数相同就左上角的值+1,不相同就比较左边和上面,找大的写上去

    此时我们就要进入下一步,就是根据这个表去找到最长公共子序列。

    而在上面的每一步填写表格的时候,我们需要加上一步——就是记录我当前的这个格子的值是从什么位置继承来的。(创建一个新的二维数组)  这里我们规定:

    ①当C[i][j]是从左上角+1得来的,我们在b[i][j]处填上1。

    ②当C[i][j]是从左侧继承来的,b[i][j]=3。

    ③当C[i][j]从上面继承来的,b[i][j]=2。

    我们这里得到b[i][j]

    之后我们从最右下角的位置开始,根据b中的表格得到:

    这个时候我们取箭头的末端所在行——第2、3、4、6行,对应X序列中的B,C,B,A。由此得到Z序列。

    算法代码:

      因为这道题目要考上机题,所以我在这里把代码思想也放到这里,不过代码很简单这里就不详细叙述了

    #include<iostream>
    #include<string.h>
    using namespace std;
    int C[15][15];
    int bb[15][15];
    char A[10];
    int LCS(char a[],char b[],int a_len,int b_len){
        for(int i =0;i<15;i++){
            C[0][i]=0;
            C[i][0]=0;
        }
        for(int h=1;h<=a_len;h++){
            for(int hh=1;hh<=b_len;hh++){
                if(a[h-1]==b[hh-1]) {
                C[h][hh]=C[h-1][hh-1]+1;
                bb[h][hh]=1;
            }
            else{
                if(C[h-1][hh]>=C[h][hh-1]) {
                    C[h][hh]=C[h-1][hh];
                    bb[h][hh]=2;
                    
                }
                if(C[h-1][hh]<C[h][hh-1]){
                    C[h][hh]=C[h][hh-1];
                    bb[h][hh]=3;
                }
            }
            }
        }
    }
    int LCScout(int a,int b){
        if(a==0||b==0) return 0;
        else{
            if(bb[a][b]==1) {
                LCScout(a-1,b-1);
                cout<<A[a-1];
            }
            if(bb[a][b]==2){
                LCScout(a-1,b);
            }
            if(bb[a][b]==3){
                LCScout(a,b-1);
            }
        }
    } 
    int main(){
        
        char B[10];
        cin>>A;
        cin>>B;
        int A_len = strlen(A);
        int B_len = strlen(B);
        LCS(A,B,A_len,B_len);
        LCScout(A_len,B_len);
    
    }

    上面的代码是我自己写着玩的一些寻找最长公共序列的方法,下面我在放上计蒜课上的——《最长共公子串》

    #include<iostream>
    #include<string.h>
    using namespace std;
    int lcs[2000][2000];
    int b[2000][2000];
    
    int LCS(char A[],char B[],int a_len,int b_len){
        int max=0;
        for(int i=0;i<=2000;i++){
            lcs[0][i]=0;
            lcs[i][0]=0;
        }
        for(int i=1;i<=a_len;i++){
            for(int h=1;h<=b_len;h++){
                if(A[i-1]==B[h-1]) {
                    lcs[i][h]=lcs[i-1][h-1]+1;
                    if(lcs[i][h]>max) max=lcs[i][h];
                    b[i][h]=1;
                }
                else{
                    if(lcs[i-1][h]>=lcs[i][h-1]){
                        lcs[i][h]=lcs[i-1][h];
                        b[i][h]=2;
                    }
                    else{
                        lcs[i][h]=lcs[i][h-1];
                        b[i][h]=3;
                    }
                }
            }
        } 
        return max;
    }
    int main(){
        char A[2001];
        char B[2001];
        cin>>A;
        cin>>B;
        int A_len = strlen(A);
        int B_len = strlen(B);
    
        cout<<LCS(A,B,A_len,B_len);
    }

     是不是很基础~相信大家算法考试应该问题不大~加油加油!

    ——————————————————————————————————————Made By Pinging

  • 相关阅读:
    ubuntu12.04 死机 卡屏 画面冻结解决方案
    Install Firefox 20 in Ubuntu 13.04, Ubuntu 12.10, Ubuntu 12.04, Linux Mint 14 and Linux Mint 13 by PPA
    ListView1.SelectedItems.Clear()
    android studio 下载地址
    jquery.slider.js jquery幻灯片测试
    jquery.hovermenu.js
    jquery.tab.js选项卡效果
    适配 placeholder,jquery版
    jquery.autoscroll.js jquery自动滚动效果
    将 Google Earth 地图集成到自己的窗体上的 简单控件
  • 原文地址:https://www.cnblogs.com/Pinging/p/7904324.html
Copyright © 2011-2022 走看看