zoukankan      html  css  js  c++  java
  • 傻瓜笔记之动态规划(二)——最长公共子串

    示例字符串:

    X = "abcopms"    Y = "opmkabc" , 最长公共子串Z = "abc   opm"

    状态转移思路:由于记录的是最长的连续的子串,那么只需要在碰到相同的字符的时候做标记即可,不需要像最长子序列那样做状态转移的记录,即该问题的状态转换方程如下:

    Z = 1,  z[i,j] = 0                     i==0 or j == 0

      2,  z[i,j] = z[i-1,j-1]+1     x[i] == y[j]    解1

      3,  z[i,j] = 0                     x[i]!=y[j]

    解1:匹配到相同的字符的时候,就在两个字符串前面的基数上面增加1,意味着最长子串长度加一(到遍历的目前为止),这个是该方程唯一一个状态转移的过程。

    下面贴上全文代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace 最长子串
     8 {
     9     class Program
    10     {
    11         public static string s1 = "abcopms";
    12         public static string s2 = "opmkabc";
    13         public static int maxLength = 0;        // 记录最长的长度
    14         public static int [,] c = new int[s1.Length+1, s2.Length+1];
    15         static void Main(string[] args)
    16         {
    17             MaxLength();
    18             for (int i = 0; i < s1.Length + 1; ++i)
    19             {
    20                 for (int j = 0; j < s2.Length + 1; ++j)
    21                 {
    22                     Console.Write(c[i, j]);
    23                 }
    24                 Console.Write("
    ");
    25             }
    26             Console.WriteLine("这是所有子串");
    27             for(int i = 0;i<s1.Length+1;++i)
    28             {
    29                 for(int j = 0;j<s2.Length+1;++j)
    30                 {
    31                     if (c[i, j] == maxLength)
    32                     {
    33                         Translate(i, j);
    34                         Console.Write("
    ");
    35                     }
    36                 }
    37             }
    38             Console.ReadKey();
    39         }
    40 
    41         public static void Translate(int x,int y)
    42         {
    43             if (c[x, y] == 0) return;
    44             else
    45             {
    46                 Translate(x - 1, y - 1);
    47                 //Console.WriteLine("printf");
    48                 Console.Write(s1[x - 1]);
    49             }
    50         }
    51 
    52         public static int [,] MaxLength()
    53         {
    54             Console.WriteLine("这是状态矩阵");
    55             Console.WriteLine(s1);
    56             Console.WriteLine(s2);
    57             for(int i = 0;i<s1.Length+1;++i)
    58             {
    59                 for(int j=0;j<s2.Length+1;++j)
    60                 {
    61                     if (i == 0 || j == 0)
    62                         c[i, j] = 0;
    63                     else if (s1[i-1] == s2[j-1])
    64                     {
    65                         c[i, j] = c[i - 1, j - 1] + 1;
    66                         maxLength = Math.Max(maxLength, c[i, j]);
    67                     }
    68                     else
    69                     {
    70                         c[i, j] = 0;
    71                     }
    72                 }
    73             }
    74             return c;
    75         }
    76     }
    77 }

    完成状态转移的代码片段如下:

     1 public static int [,] MaxLength()
     2         {
     3             Console.WriteLine("这是状态矩阵");
     4             Console.WriteLine(s1);
     5             Console.WriteLine(s2);
     6             for(int i = 0;i<s1.Length+1;++i)
     7             {
     8                 for(int j=0;j<s2.Length+1;++j)
     9                 {
    10                     if (i == 0 || j == 0)
    11                         c[i, j] = 0;
    12                     else if (s1[i-1] == s2[j-1])
    13                     {
    14                         c[i, j] = c[i - 1, j - 1] + 1;
    15                         maxLength = Math.Max(maxLength, c[i, j]);
    16                     }
    17                     else
    18                     {
    19                         c[i, j] = 0;
    20                     }
    21                 }
    22             }
    23             return c;
    24         }

    该片段执行完毕之后返回一个二维数组,记录此次转移的过程

    完成状态转移数组遍历的代码如下:

     1 for(int i = 0;i<s1.Length+1;++i)
     2             {
     3                 for(int j = 0;j<s2.Length+1;++j)
     4                 {
     5                     if (c[i, j] == maxLength)
     6                     {
     7                         Translate(i, j);
     8                         Console.Write("
    ");
     9                     }
    10                 }
    11             }

    遍历转移数组的过程中,只有碰到最大值得时候才是最长子串的时候,但是往往最长的子串又不止一个,如果题目规定只有一个最长子串的话,那么只要记录在记录maxLength时同步记录下i,j,即可直接进行输出而不必遍历整个数组。

    完成子串输出的代码如下:

    1 public static void Translate(int x,int y)
    2         {
    3             if (c[x, y] == 0) return;
    4             else
    5             {
    6                 Translate(x - 1, y - 1);
    7                 Console.Write(s1[x - 1]);
    8             }
    9         }

    总结:没什么好说的,更最长子序列差不多一个模子,而且代码量显然比最长子序列少,因果过程就比它要简单的多。

  • 相关阅读:
    poj3372 Candy Distribution
    poj3270 Cow Sorting
    poj2888 Magic Bracelet
    poj2429 GCD & LCM Inverse
    poj1811 Prime Test
    poj2689 Prime Distance
    【思维】2017多校训练七 HDU6121 Build a tree
    【字符串+BFS】Problem 7. James Bond
    【dfs】codeforces Journey
    【思维+贪心】codeforces Game of the Rows
  • 原文地址:https://www.cnblogs.com/CHANGKTITI/p/11214290.html
Copyright © 2011-2022 走看看