一天一道算法题(5)---最长公共子串

  • 题目

给定两个字符串str1和str2,返回两个字符串的最长公共子串。例如:str1="1AB2345CD",str2="12345EF",公共子串是“2345”

  • 解析

最长公共子串和最长公共子序列的区别是,子串是连续的,子序列是不连续的。

首先还是要生成动态规划表。生成大小为M*N的矩阵dp。dp[i][j]的含义是,在必须把str1[i]和str2[j]当作公共子串最后一个字符的情况下,公共子串最长能有多长。比如,str1="A1234B",str2="CD1234",dp[3][4]的含义是在必须把str1[3]和str2[4]当作公共子串最后一个字符的情况下,公共子串能有多长。所以dp[3][4]=3。如果str1[i] != str2[j],那么dp[i][j]=0。具体求解过程如下:

1.矩阵dp第一列即dp[0..M-1][0]。如果str1[i]==str2[0],dp[i][0]=1,否则dp[i][0]=0。

2.矩阵dp第一行同上。

3.从左到右,从上到下可能有以下两种情况:

1)如果str1[i] != str2[j],那么dp[i][j]=0

2)如果str1[i] == str2[j],那么dp[i][j]=dp[i-1][j-1] + 1

计算dp矩阵的代码如下:

 1   public int[][] getdp(char[] str1, char[] str2) {
 2         int[][] dp = new int[str1.length][str2.length];
 3         for (int i = 0; i < str1.length; i++) {
 4             if (str1[i] == str2[0])
 5                 dp[i][0] = 1;
 6         }
 7         for (int j = 0; j < str2.length; j++) {
 8             if (str1[0] == str2[j])
 9                 dp[0][j] = 1;
10         }
11         for (int i = 1; i < str1.length; i++) {
12             for (int j = 1; j < str2.length; j++) {
13                 if (str1[i] == str2[j]) {
14                     dp[i][j] = dp[i-1][j-1] + 1;
15                 }
16             }
17         }
18         return dp;
19     }

从dp矩阵中得到最长公共子串是非常容易的。只需要找到dp矩阵中最大的那个数即可。代码如下。

 1   public String lcst1(String str1, String str2) {
 2         if (str1 == null || str2 == null || str1.equals("") || str2.equals("")) {
 3             return "";
 4         }
 5         char[] chs1 = str1.toCharArray();
 6         char[] chs2 = str2.toCharArray();
 7         int[][] dp = getdp(chs1, chs2);
 8         int end = 0;
 9         int max = 0;
10         for (int i = 0; i < chs1.length; i++) {
11             for (int j = 0; j < chs2.length; j++) {
12                 if (dp[i][j] > max) {
13                     end = i;
14                     max = dp[i][j];
15                 }
16             }
17         }
18         return str1.substring(end-max+1, end+1);
19     }

上面的算法需要大小为M*N的矩阵,但实际上是可以减小到O(1)的,如下图所示,每一条斜线在计算之前生成整型变量len,len表示左上方位置的值,初始时len=0.从斜线最左上的位置开始向右下方依次计算每个位置的值。

代码实现如下:

 1   public String lcst2(String str1, String str2) {
 2         if (str1 == null || str2 == null || str1.equals("") || str2.equals("")) {
 3             return "";
 4         }
 5         char[] chs1 = str1.toCharArray();
 6         char[] chs2 = str2.toCharArray();
 7         int row = 0; //斜线开始的行
 8         int col = chs2.length - 1; //斜线开始的列
 9         int max = 0;  //记录最大长度
10         int end = 0;  //最大长度更新时,记录子串的结尾位置
11         while (row < chs1.length) {
12             int i = row;
13             int j = col;
14             int len = 0;
15             //从(i, j)开始向右下方遍历
16             while (i < chs1.length && j < chs2.length) {
17                 if (chs1[i] != chs2[j]) {
18                     len = 0;
19                 } else {
20                     len++;
21                 }
22                 //记录最大值以及结束字符的位置
23                 if (len > max) {
24                     end = i;
25                     max = len;
26                 }
27                 i++;
28                 j++;
29             }
30             if (col > 0) { //斜线开始位置的列先向左移动
31                 col--;
32             } else { //列移动到最左位置后,行向下移动
33                 row++;
34             }
35         }
36         return str1.substring(end-max+1, end+1);
37     }
  • 参考资料

《程序员代码面试指南》  左程云

时间: 2024-10-25 06:10:13

一天一道算法题(5)---最长公共子串的相关文章

每周一道算法题011:最长公共子串

问题: 求以下几组单词的最长公共子串的长度1.fish和fosh2.fish和hish3.fish和vista 思路: 可以用表格法,横纵坐标分别是两个单词,如果字符相同,就用左上角的数字加1,最后取表格中的最大值. 解答: php: <?php // 找出两个单词的最长公共子串 function findLongestSubString($word1, $word2) { $len1 = strlen($word1); $len2 = strlen($word2); $cell = array

一天一道算法题---6.3---二分运用

感谢微信平台 : 一天一道算法题 -----  一天多一点进步----- 先来段 废话: 已经 3 4天没更了 主要还是自己 太懒了 .... 好 让我们 开始吧 题目链接: touch  me 是不是 有点长啊  最可恶的是 还有张 诱人的 馅饼  --- 话说 有个很好的美国系列校园青春 sex movie ---  American Pie  --- 美国派----- 题目大意: 有F+1个人来分N个圆形蛋糕 每个人得到的必是一整块蛋糕 (不是由几块拼在一起的)面积要相同 求每个人最多能得

一天一道算法题--6.18--思维题

感谢微信平台---一天一道算法题---每天多一点进步---- problem: 给你一天的Google搜索日志 你怎么设计算法找出是否有一个搜索词 它出现的频率占所有搜索的一半以上?如果肯定有一个搜索词栈大多数 你能这么提高你的算法找到它?再假设搜索日志就是内存中的一个数组 要求O(1)空间 O(n) 时间的算法 analyse: 这题来源于google面试 而且这题真的很有意思.......... 这个分析 也真的好长啊 我也基本懂了 还是 明天 继续码吧 今天 主要来开个头 不然怕又被拖着了

一天一道算法题---6.26---二分查找

感谢微信平台---一天一道算法题----每天多一点进步-- 好累啊  现在在用win7自带的输入法 打起来真麻烦 快点把这2天的搞完就重装了 还是直接来源于----〉 待字闺中 分析 给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复,请给出方法,找到这个Magic Index.更进一步,当A中允许有重复的元素,该怎么办呢? 没有重复元素的情况 一些同学在遇到这个题目的时候,往往会觉得比较简单.

一天一道算法题--6.25--无定义

感谢微信平台---一天一道算法题--每天多一点进步---- 其实今天我接下去补上的几题都来自---待字闺中 所以我就原封不动的将它的题目与分析搬过来了 原题 给定一个数组,我们可以找到两个不相交的.并且是连续的子数组A和B,A中的数字和为sum(A), B中的元素和为sum(B).找到这样的A和B,满足sum(A) - sum(B)的绝对值是最大的. 例如:[2, -1 -2, 1, -4, 2, 8]划分为A=[-1, -2, 1, -4], B=[2, 8], 最大的值为16 分析 如果没有

一天一道算法题---6.27---二分图

感谢微信平台---一天一道算法题---每天多一点进步--- Ah... last... 也很晚了 快2点半了 C罗也告别这届世界杯了  主要还是输给德国太多球了 美国也没赢 唉 还是来源于----> 待字闺中 原题 大家都知道facebook用户都是双向的好友,a是b的好友,那么b一定是a的好友,现在给定一个用户列表,其中有些用户是好友,有些不是,请判断,这些用户是否可以划分为两组,并且每组内的用户,互相都不是好友.如果能,请给出这个划分. 例子1: 用户:{1, 2, 3} 好友关系:1-2,

前端面试的一道算法题

(使用canvas解答) 下面说一个跟前端有点相关并且有点趣的一道算法题. 题目: 平面上有若干个不特定的形状,如下图所示.请写程序求出物体的个数,以及每个不同物体的面积. 分析 想要知道有多少个图形,想到的就是先获取图片中的每一个像素点然后判获取像素点的背景颜色(RGBA).想要获得图片中的每一个像素点,那就可以联想到使用h5的canvas.如下: 菜鸟教程中canvas的getimagedata方法http://www.runoob.com/tags/canvas-getimagedata.

一天一道算法题--6.19--二分搜索

感谢微信平台---一天一道算法题---每天多一点进步 这是昨天的 只贴下题目 == 再把今天的也是一样处理了   这2天 不想写 可能晚上会有改变吧.. problem: 给定一个最多包含40亿个随机排列的32位 二进制的无符号整数 找出不在文件中的数.显然 由于 2^32=4294967196大于4亿 所以缺少的数不止一个 现限制只能使用几个外部的临时文件和仅几百个字节的内存. ****************************** 过了明天 就没事了 =-= 一天一道算法题--6.19

一天一道算法题--6.13---计算几何

感谢微信平台---一天一道算法题---每天多一点进步 本来 想在世界杯之前 可以 开开心心地A了今天的算法题  .... 竟然是计算几何 我高数 那么渣....... 这题 先放着吧..... 哎.... 链接 还是一样先放出来 . touch me 平常这个点 再过会 就应该要碎觉了 今天 = 个揭幕战 累死我的节奏,,, 现在去做点什么呢........... 一天一道算法题--6.13---计算几何,布布扣,bubuko.com