给定两个字符串,求出它们的最长公共字串git
var str1="abcdefg"; var str2="xyzabcd";
说明:好比在单词"abcdefg"和"abcdefg"它们的最长公共子序列是"abcd"。寻找最长子序列经常使用于遗传学中,用于使用核苷酸碱基的首字母对DNA的描述(这段话从网上抄的)。github
最长公共子串和最长公共子序列的区别。数组
最长公共子串和最长公共子序列的区别为:子串是串的一个连续的部分,子序列则是从不改变序列的顺序,而从序列中去掉任意的元素而得到新的序列;也就是说,子串中字符的位置必须是连续的,子序列则能够没必要连续。微信
这道题,想了很长时间,终于慢慢的把题目作出来了,接下来的内容可能会很难理解,也许我比较笨吧至少对我来讲想了很久。我会尽可能结合图文去展现解题的思路,也能够本身想一想,而后在看接下来的内容。优化
其实看到这个问题咱们直接能够用暴力的方式解决这个问题。给定两个字符串A和B,咱们能够经过从A的第一个字符开始与B对应的每个字符进行对比的方式找到最长的公共字串。若是此时没有找到匹的字母,则移动到A的第二个字符处,而后从B的第一个字符处进行对比,以此类推。因为下面的内容较多,爆力方法我这里就不写了。spa
咱们回顾一下动态规划的解题思路:code
从底部开始解决问题,将全部小问题解决掉,而后合并成一个总体的解决方案。rem
使用一个数组创建一张表,用于存放被分解成众多子问题的解。字符串
那基于这两点咱们首先要分解这个问题,怎么分解呢?源码
第一步: 最小的是每一个字符,因此要把分解成单个的字符去匹配每一个单个的字符。所以这里咱们能够获得下面这一张表:
匹配为1,不匹配为0,这个时候咱们就分解成为每一个字符的匹配状况,由此获得。
第二步: 每一个子问题有了,这个时候咱们要创建一个数组去存放每一个子问题的解。关键问题在于,咱们怎么样把每一个子问题的解存起来,而且能够获得咱们想要的结果。对表作一些处理,初始化一个二维数组:
var arr = new Array(str1.length + 1); for (var i = 0; i <= str1.length + 1; i++) { arr[i] = new Array(str2.length + 1); for (var j = 0; j <= str2.length + 1; j++) { arr[i][j] = 0; } }
获得以下的表:
图中咱们能够看到行和列都多加了一个而且都是0,这是为了判断上一个是否相等的操做,后面你就会明白它的意思了。
对初始化的二维数组坐些处理,获得以下图:
一开始看到这个图的时候你可能会很懵逼,若是你已经看明白了,那你就跳过我这段废话吧。咱们应该一直的告诉本身,新建的这个数组是存放每一个子问题的解,首先要明确的是找出最长字串,有哪些方式能够作到把字串从原来的字符串中截取,因此要知道起始位置和字串的长度。从图中能够看到的红字就是存放这个位置的最优解字串的长度,因此应该创建两个变量去存储其实位置的index 和最大长度 maxLen 。获得一下代码:
var maxLen = 0; var index = 0; for(var i = 0; i <= str1.length; i++){ for(var j = 0; j <= str2.length; j++){ if(i == 0 || j == 0){ arr[i][j] = 0 }else{ if (str1[i] == str2[j] && str1[i - 1] == str2[j - 1]) { arr[i][j] = arr[i - 1][j - 1] + 1; }else{ arr[i][j] = 0; } } if(arr[i][j] > maxLen){ maxLen = arr[i][j]; index = i; } } }
简单的解释一下,这里要明确连续的字串的位置,是二维数组对角线上的值,这点明确了不少问题就好理解了。
上面的代码把最主要的两个参数找到了,那接下来就是选择其中的一个字符串去截取字串:
var str = ""; if(maxLen == 0){ return ""; }else{ for(var k = index - maxLen; k < maxLen; k++){ str += str1[k]; } return str; }
下面贴上完整的代码,你也能够去个人github上查看源码;
function LCS(str1, str2){ var maxLen = 0; var index = 0; var arr = new Array(); for (var i = 0; i <= str1.length + 1; i++) { arr[i] = new Array(); for (var j = 0; j <= str2.length + 1; j++) { arr[i][j] = 0; } } for(var i = 0; i <= str1.length; i++){ for(var j = 0; j <= str2.length; j++){ if(i == 0 || j == 0){ arr[i][j] = 0 }else{ if (str1[i] == str2[j] && str1[i - 1] == str2[j - 1]) { arr[i][j] = arr[i - 1][j - 1] + 1; }else{ arr[i][j] = 0; } } if(arr[i][j] > maxLen){ maxLen = arr[i][j]; index = i; } } } var str = ""; if(maxLen == 0){ return ""; }else{ for(var k = index - maxLen; k < maxLen; k++){ str += str1[k]; } return str; } } var str1="abcdefg"; var str2="xyzabcd"; LCS(str1, str2) // abcd
到此为止咱们终于找到了最长公共字串。到这里咱们须要想一想能不能在优化了,虽然这样解决问题,可是引入了一个二维数组,在两个字符串都较大的状况下不是很划算,是否能够进一步优化?答案是能够的,须要改变一下策略,是否能够创建一个一维数组就能够解决问题了呢,这里晚了先写这么多把,以后我会在公众号中贴出暴力解法和动态规划的优化解法,欢迎持续关注个人公众号得到一手的信息。
欢迎关注微信公众帐号查看最新文章