题目

给定两个字符串str1和str2, 长度分别稳M和N,返回两个字符串的最长公共子串

解法一

这是一道经典的动态规划题,可以用M*N的二维dp数组求解.dp[i][j]代表以str1[i]和str2[j]当做公共子串结尾的情况下,公共子串能有多长.然后分析可以发现dp[i][j]只与dp[i- 1][j - 1]有关:当str1[i] 和str2[j]相等的时候, dp[i][j] = dp[i - 1][j - 1] + 1;当它们不相等的时候,dp[i][j] = 0.获得dp数组之后要获得最长公共子串只需要找到数组中最大的值,其值代表最长子串的长度,其所在的索引代表了子串在原字符串中结束的位置.

代码

先获取dp数组,然后通过dp数组得到最长公共子串

//最长公共子串的dp数组
vector<vector<int> > getdp1(string str1, string str2) {
vector<vector<int> > dp(str1.length(), vector<int>(str2.length()));
if (str1.length() == 0 || str2.length() == 0)
return dp;
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < int(str1.length()); i ++)
dp[i][0] = str1[i] == str2[0] ? 1 : 0;
for (int j = 1; j < int(str2.length()); j ++)
dp[0][j] = str2[j] == str1[0] ? 1 : 0; for (int i = 1; i < int(str1.length()); i ++) {
for (int j = 1; j < int(str2.length()); j ++) {
if (str1[i] == str2[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = 0;
}
}
return dp;
} // 最长公共子串的解法一
string lcst1(string str1, string str2) {
string res = "";
if (int(str1.length()) == 0 || int(str2.length()) == 0)
return res;
vector<vector<int> > dp = getdp1(str1, str2);
int maxNum = 0;
int maxIndex;
for (int i = 0; i < int(dp.size()); i ++) { // 遍历dp矩阵找到最大值
for (int j = 0; j < int(dp[0].size()); j ++)
if (dp[i][j] > maxNum) {
maxNum = dp[i][j];
maxIndex = i;
}
} res = str1.substr(maxIndex - maxNum + 1, maxNum);
return res;
}

解法二

上面这种解法需要的时间复杂度和空间复杂度都是O(M* N).下面提供一种空间复杂度为O(1)的解法

代码

//最长公共子串解法二
string lcst2(string str1, string str2) {
string res = "";
if (int(str1.length()) == 0 || int(str2.length()) == 0)
return res; int maxNum = 0; //记录最大值
int maxindex = -1; //记录最大值的索引
int tmpNum; //记录当前值,如果大于最大值就更新
int i = int(str1.length()) - 1;
int j = int(str2.length()) - 1;
for (j; j >= 0; j --) { // 斜线先向左移动
tmpNum = 0;
for (int tmp = 0; tmp < int(str2.length()) - j; tmp ++){
if (str1[tmp] == str2[j + tmp]) {
tmpNum = tmpNum == 0 ? 1 : tmpNum + 1;
} else
tmpNum = 0;
if (tmpNum > maxNum) {
maxNum = tmpNum;
maxindex = j + tmp;
}
}
} bool triangleUpFlag = true; //maxindex 在通过斜线计算的时候属于上三角的flag
for (i; i > 0; i --) { //列移到最左边之后再向下移动
tmpNum = 0;
for (int tmp = 0; tmp < int(str1.length()) - i; tmp ++) {
if (str2[tmp] == str1[i + tmp])
tmpNum = tmpNum == 0 ? 1 : tmpNum + 1;
else
tmpNum == 0;
if (tmpNum > maxNum) {
maxNum = tmpNum;
triangleUpFlag = false;
maxindex = i + tmp;
}
}
} cout<<maxindex<<" "<<maxNum<<" "<<triangleUpFlag<<endl;
res = triangleUpFlag == true ? str2.substr(maxindex - maxNum + 1, maxNum) : str1.substr(maxindex - maxNum + 1, maxNum);
return res;
} int main()
{
string str1 = "1AB2345CD";
string str2 = "12345EF";
//string str1 = "abcde";
//string str2 = "bebcd";
cout<<lcst2(str1, str2)<<endl; //输出2345
return 0;
}

[DP]最长公共子串的更多相关文章

  1. poj1159 dp最长公共子串

    //Accepted 204 KB 891 ms //dp最长公共子串 //dp[i][j]=max(dp[i-1][j],dp[i][j-1]) //dp[i][j]=max(dp[i][j],dp ...

  2. DP:LCS(最长公共子串、最长公共子序列)

    1. 两者区别 约定:在本文中用 LCStr 表示最长公共子串(Longest Common Substring),LCSeq 表示最长公共子序列(Longest Common Subsequence ...

  3. [程序员代码面试指南]递归和动态规划-最长公共子串问题(DP,LCST)

    问题描述 如题. 例:输入两个字符串 str1="1AB234",str2="1234EF" ,应输出最长公共子串"234". 解题思路 状 ...

  4. 最长公共子串(DP)

    DP基础_最长公共子串 Description 两个序列的最长公共子串,这个子串要求在序列中是连续的.如:"bab"和"caba" (可以看出来最长公共子串是& ...

  5. 经典算法-最长公共子序列(LCS)与最长公共子串(DP)

    public static int lcs(String str1, String str2) { int len1 = str1.length(); int len2 = str2.length() ...

  6. HDU 1503 带回朔路径的最长公共子串

    http://acm.hdu.edu.cn/showproblem.php?pid=1503 这道题又WA了好几次 在裸最长公共子串基础上加了回溯功能,就是给三种状态各做一个 不同的标记.dp[n][ ...

  7. 动态规划(一)——最长公共子序列和最长公共子串

    注: 最长公共子序列采用动态规划解决,由于子问题重叠,故采用数组缓存结果,保存最佳取值方向.输出结果时,则自顶向下建立二叉树,自底向上输出,则这过程中没有分叉路,结果唯一. 最长公共子串采用参考串方式 ...

  8. 最长公共子串 NYOJ 36

    http://acm.nyist.net/JudgeOnline/problem.php?pid=36 最长公共子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 ...

  9. 算法设计 - LCS 最长公共子序列&&最长公共子串 &&LIS 最长递增子序列

    出处 http://segmentfault.com/blog/exploring/ 本章讲解:1. LCS(最长公共子序列)O(n^2)的时间复杂度,O(n^2)的空间复杂度:2. 与之类似但不同的 ...

随机推荐

  1. Unity经典游戏教程之:合金弹头

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  2. 1关于如何用Navicat连接到xampp安装的mysql

    打开xampp,打开config打开my.ini. 检索bind-address,后面的数字是你的IP地址 检索 port,后面的数字是端口号 打开Navicat新建连接,选中mysql 连接名随便起 ...

  3. Visual Studio Debug

    在watch窗口输入,$err,hr可以看到上一个错误代码和相关描述信息 Error Lookup可以将错误代码转换成为相应的文本描述 FormatMessage()

  4. 大数据学习之旅1——HDFS版本演化

    最近开始学习大数据,发现大数据有很多很多组件,我现在负责的是HDFS(Hadoop分布式储存系统)的学习,整理了一下HDFS的版本情况.因为HDFS是Hadoop的重要组成部分,所以有关HDFS的版本 ...

  5. Cocos Creator经典游戏制作之:信使(The Messenger)

    版权声明: 本文原创发布于博客园"优梦创客"的博客空间(网址:http://www.cnblogs.com/raymondking123/)以及微信公众号"优梦创客&qu ...

  6. 自己实现spring核心功能 三

    前言 前两篇已经基本实现了spring的核心功能,下面讲到的参数绑定是属于springMvc的范畴了.本篇主要将请求到servlet后怎么去做映射和处理.首先来看一看dispatherServlet的 ...

  7. AutoResetEvent控制线程用法

    本文主要来自一道面试题,由于之前对AutoResetEvent的用户很模糊(即使已经使用过了).面试题题目很简洁:两个线程交替打印0~100的奇偶数.你可以先动手试试,我主要是尝试在一个方法里面完成这 ...

  8. 盘一盘 NIO (三)—— Selector解析

    Selector是个啥? Selector是Java NIO核心组件中的选择器,用于检查一个或多个Channel(通道)的状态是否处于可读.可写.实现一个单独的线程可以管理多个channel,从而管理 ...

  9. C笔记_常用快捷键

    1.第一部分 Ctrl + up/down 以光标所在行为中心上下移动文本: Ctrl + left/right 左右跳过一个单词或符号: Ctrl + end 跳至文本末尾: Ctrl + dele ...

  10. Liunx学习总结(三)--用户和用户组管理

    用户和组的基本概念 用户和组是操作系统中一种身份认证资源. 每个用户都有用户名.用户的唯一编号 uid(user id).所属组及其默认的 shell,可能还有密码.家目录.附属组.注释信息等. 每个 ...