算法原理:
(1) 将两个字符串分别以行和列组成矩阵。
(2) 计算每个节点行列字符是否相同,如相同则为 1。
(3) 通过找出值为 1 的最长对角线即可得到最长公共子串。
人 民 共 和 时 代
中 0, 0, 0, 0, 0, 0
华 0, 0, 0, 0, 0, 0
人 1, 0, 0, 0, 0, 0
民 0, 1, 0, 0, 0, 0
共 0, 0, 1, 0, 0, 0
和 0, 0, 0, 1, 0, 0
国 0, 0, 0, 0, 0, 0
为进一步提升该算法,我们可以将字符相同节点(1)的值加上左上角(d[i-1, j-1])的值,这样即可获得最大公用子串的长度。如此一来只需以行号和最大值为条件即可截取最大子串。
人 民 共 和 时 代
中 0, 0, 0, 0, 0, 0
华 0, 0, 0, 0, 0, 0
人 1, 0, 0, 0, 0, 0
民 0, 2, 0, 0, 0, 0
共 0, 0, 3, 0, 0, 0
和 0, 0, 0, 4, 0, 0
国 0, 0, 0, 0, 0, 0
算法实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LCS
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("请输入目标字符串A:");
string s = Console.ReadLine();
Console.WriteLine("请输入目标字符串B:");
string t = Console.ReadLine();
string strReturn = LCS(t, s);
if (string.IsNullOrEmpty(strReturn))
{
Console.WriteLine("您输入的两个字符串没有找到最长的公共字符串.");
}
else
{
Console.WriteLine("CLS算法为您找到的正常的公共字符串是:" + strReturn);
}
}
catch (Exception ex)
{
Console.WriteLine("error:"+ex.Message);
}
}
/// <summary>
/// 最大公共字符串
/// LCS算法
/// </summary>
/// <param name="str1">字符串A</param>
/// <param name="str2">字符串B</param>
/// <returns></returns>
private static string LCS(string str1, string str2)
{
if (str1 == str2)
return str1;
else if (String.IsNullOrWhiteSpace(str1) || String.IsNullOrWhiteSpace(str2))
return null;
var d = new int[str1.Length, str2.Length];
var index = 0;
var length = 0;
for (int i = 0; i < str1.Length; i++)
{
for (int j = 0; j < str2.Length; j++)
{
//左上角
var n = i - 1 >= 0 && j - 1 >= 0 ? d[i - 1, j - 1] : 0;
//当前节点值等于“左上角的值+1”:“0”
d[i, j] = str1[i] == str2[j] ? n + 1 : 0;
//如果是最大值,记录该值和行号
if (d[i, j] > length)
{
length = d[i, j];
index = i;
}
}
}
return str1.Substring(index - length + 1, length);
}
}
}