给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
数据范围: 
要求: 空间复杂度
,时间复杂度 )
要求: 空间复杂度
char* LCS(char* s1, char* s2 ) {
int dp[10000][10000], i, j, maxLen=0, maxS1_i=0;
char *res;
res = (char*)malloc((strlen(s1)<strlen(s2)?strlen(s1):strlen(s2))+1);
strcpy(res, "");
for(i=0; i<=strlen(s1); i++)
dp[i][0] = (s2[i]==s1[0] ? 1 : 0);
for(i=0; i<=strlen(s2); i++)
dp[0][i] = (s1[i]==s2[0] ? 1 : 0);
for(i=1; i<strlen(s1); i++) {
for(j=1; j<strlen(s2); j++) {
if(s1[i]==s2[j]) {
dp[i][j] = dp[i-1][j-1]+1;
if(maxLen<dp[i][j]) {
maxLen = dp[i][j];
maxS1_i = i;
}
}
else
dp[i][j] = 0;
}
}
strncpy(res, s1+maxS1_i-maxLen+1, maxLen);
res[maxLen] = 0;
return res;
} char* LCS(char* str1, char* str2 )
{
// write code here
//记录两个字符串长度
int len1=strlen(str1);
int len2=strlen(str2);
//dp用于存储动态规划的结果,即每个公共子串的长度
int dp[len1+1][len2+1];
//最长公共子串长度
int maxLen=0;
//最长公共子串在str1的结束下标
int endIndex=0;
//遍历str1和str2每个元素之间是否存在公共子串,若存在,记录长度
for(int i=0;i<=len1;i++)
{
for(int j=0;j<=len2;j++)
{
//第一行和第一列初始化为0,作为边界条件
if(i==0||j==0)
{
dp[i][j]=0;
}
else if(str1[i-1]==str2[j-1])//出现公共子串
{
//i-1和j-1才是公共子串最后一个元素
dp[i][j]=dp[i-1][j-1]+1;
//更新记录最大长度
if(maxLen<dp[i][j])
{
maxLen=dp[i][j];
endIndex=i-1;
}
}
else //没有子串
{
dp[i][j]=0;
}
}
}
//记录子串
char*res=malloc(maxLen+1);
if(maxLen==0)
{
return NULL;
}
else
{
strncpy(res,&str1[endIndex-maxLen+1],maxLen);
res[maxLen]='\0';
}
return res;
} /*
暴力,双层循环检索是否匹配,匹配则继续下一索引匹配,直到遇到不同字符串。
更新最大公共子串的长度与起始位置。
全部找完后,将最大公共子串复制到返回字符串中。
*/
char* LCS2(char* str1, char* str2 ) {
// write code here
char* res = (char*)malloc(sizeof(char)*5000);
memset(res, 0, sizeof(char)*5000);
int len1 = strlen(str1), len2 = strlen(str2);
int n = 0;
int maxStart = 0, maxN = 0;
for(int i=0; i<len1; i++){
for(int j=0; j<len2; j++){
//注意一定要判断索引是否有效,排查了很久才发现索引超出有效范围。
while(i+n < len1 && j+n < len2 && str1[i+n] == str2[j+n])n++; //此处每次都需要遍历,是动规优化的点
if(n>maxN){
maxN = n;
maxStart = i;
}
n=0;
}
}
memcpy(res, &str1[maxStart], sizeof(char)*maxN);
return res;
}
//动态规划:节省暴力的多次遍历。
//使用上一次的状态即dp[i-1][j-1]来更新当前位置的匹配长度
char* LCS(char* str1, char* str2 ) {
// write code here
int maxN = 0, maxEnd = 0; //此处为maxEnd,即匹配的最后一个字符位置
char* res = (char*)malloc(sizeof(char)*5000);
memset(res, 0, sizeof(char)*5000);
int len1 = strlen(str1), len2 = strlen(str2);
int dp[len1][len2];
memset(dp, 0, sizeof(int)*len1*len2);
for(int i=0; i<len1; i++){
for(int j=0; j<len2; j++){
if(str1[i] == str2[j]){ //匹配上
if(i==0 || j==0){ //如果是边沿,则置1
dp[i][j] = 1;
}else{ //如果不是边沿,则取左上角的dp,来更新最长匹配长度
dp[i][j] = dp[i-1][j-1] + 1;
}
}
if(maxN < dp[i][j]){ //更新最长字符串的信息
maxN = dp[i][j];
maxEnd = i;
}
}
}
//此处由于是maxEnd,因此需要通过maxEnd-maxN+1来获取匹配字符串的开头位置
memcpy(res, &str1[maxEnd-maxN+1], sizeof(char)*maxN);
return res;
}
//动态规划
char* LCS(char* str1, char* str2 ) {
int len1 = strlen(str1);
int len2 = strlen(str2);
int maxlen = 0, index;
int (*dp)[len2] = (int (*)[len2])calloc(len1 * len2, sizeof(int));
for(int i = 0; i < len1; i++) { //初始化
if(str2[0] == str1[i]) {
dp[i][0] = 1;
maxlen = 1;
index = i;
}
}
for(int i = 0; i < len2; i++) { //初始化
if(str1[0] == str2[i]) {
dp[0][i] = 1;
maxlen = 1;
index = 0;
}
}
for(int i = 1; i < len1; i++) {
for(int j = 1; j < len2; j++) {
if(str1[i] == str2[j]) {
dp[i][j] = dp[i-1][j-1] + 1; //状态转移表达式
if(dp[i][j] > maxlen) {
maxlen = dp[i][j];
index = i;
}
}
}
}
char *str = (char *)calloc(maxlen+1, sizeof(char));
memcpy(str, str1+(index - maxlen + 1), maxlen); //从str1上拷贝最长公共子串
return str;
}
import java.util.*; public class Solution { /** * longest common substring * @param str1 string字符串 the string * @param str2 string字符串 the string * @return string字符串 */ //状态记录,取缔二维数组,减少内存开销 int start = 0; int stepNum = 0; int currentStart = 0; int currentStepNum = 0; boolean cancleLeft = false; boolean cancleRight = false; int len2 = 0; public String LCS (String str1, String str2) { String breakJudge; if (str1.length() < str2.length()){ String temp = str1; str1 = str2; str2 = temp; } len2 = str2.length(); for (int i = 0;i < str1.length() && !cancleRight;i++){ for (int j = 0; j < str2.length() && i + j < str1.length();j++) doJudge(str1,str2,j + i,j); clear(); if (!cancleRight) cancleRight = breakJudge(str1.length(),i); } clear(); for (int i = 0;i < str2.length() && ! cancleLeft;i++){ for (int j = 0; i + j < str2.length();j++) doJudge(str1,str2,j,j + i); clear(); if (!cancleLeft) cancleLeft = breakJudge(str2.length(),i); } return stepNum == 0 ? "-1" : str1.substring(start,start + stepNum); } // 判断能否提前退出 public boolean breakJudge(int len,int i){ if (stepNum == len2 || (stepNum >= (len - i))){ return true; } return false; } public void clear(){ if (currentStepNum > stepNum){ stepNum = currentStepNum; start = currentStart; } currentStepNum = 0; currentStart = 0; } public void doJudge(String str1,String str2,int index1,int index2){ if ( str1.charAt(index1) == str2.charAt(index2)){ if (currentStepNum == 0)// 记录步长为0 currentStart = index1; //更新起点 currentStepNum ++;//步长加一 } else clear();//不等,对比当前步长与缓存步长,更新保存的步长与起点 } }