题目描述
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
输入描述:
输入两个字符串
输出描述:
返回重复出现的字符
示例1
输入
abcdefghijklmnop
abcsafjklmnopqrstuvw
输出
jklmnop
while True:
try:
str1=input()
str2=input()
n = 0
s = ''
if len(str1)>len(str2):
str1,str2 = str2, str1
for i in range(len(str1)+1):
if str1[i-n:i] in str2:
s = str1[i-n:i]
n +=1
print(s)
except:
break
最长公共子串,长度
while True:
try:
str1=input()
str2=input()
n = 0
s = ''
if len(str1)>len(str2):
str1,str2 = str2, str1
for i in range(len(str1)+1):
if str1[i-n:i] in str2:
s = str1[i-n:i]
n +=1
print(n)
except:
break
def getCommonStr(str1,str2):
n=len(str1)
for i in range(n):#每次递减长度
start=0
end=n-i
while(end<=n):
if str1[start:end] in str2:
return len(str1[start:end])
else:
start+=1
end+=1
return 0
while True:
try:
a = str(input())
b = str(input())
if len(a)>len(b):
a,b=b,a
print(getCommonStr(a,b))
except:
break
java
最长公共子串
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
while(in.hasNext()){
String str1=in.nextLine();
String str2=in.nextLine();
if (str1.length()<str2.length()){
System.out.println(getCommonStr(str1,str2));
}
else
System.out.println(getCommonStr(str2,str1));
}
}
public static String getCommonStr(String sstr,String lstr){
if(sstr==null || lstr==null) return "";
if(sstr.equals(" ") || lsstr.equals(" ")) return " ";
for(int i=0;i<sstr.length();i++){//每次字符串递减的长度
for(int start=0,end=sstr.length()-i;end<=sstr.length();start++,end++){//start,end头尾指针,不断后移,直到end为最后一个index+1
String temp=sstr.substring(start,end);
if (lstr.contains(temp)){
return temp;
}
}
}
return " ";
}
}
每次子串长度递减,从0-len-1
在该长度时,定义首位指针,进行移动判断改子串是否被长串包含
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
while(in.hasNext()){
String str1=in.nextLine();
String str2=in.nextLine();
if (str1.length()<str2.length()){
System.out.println(getCommonStr(str1,str2));
}
else
System.out.println(getCommonStr(str2,str1));
}
}
public static int getCommonStr(String sstr,String lstr){
for(int i=0;i<sstr.length();i++){//每次字符串递减的长度,遍历短的字符串
for(int start=0,end=sstr.length()-i;end<=sstr.length();start++,end++){//start,end头尾指针,不断后移,直到end为最后一个index+1
String temp=sstr.substring(start,end);
if (lstr.contains(temp)){
return temp.length();
}
}
}
return 0;
}
}
动态规划
// 动态规划 复杂度o(n1*n2)
// memo[i][j]存放第一个str1以第i-1个字符为结尾的子串(必须用到) 和str2以第j-1个字符作为结尾的子串(必须用到)
// 的最大公共连续子串长度
// 输出时按照先遍历二维数组的长边 再遍历二维数组的短边 查找最大长度 以及对应的 结尾下标
import java.io.*;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s1 = br.readLine();
char[] str1 = s1.toCharArray();
char[] str2 = br.readLine().toCharArray();
br.close();
int n1 = str1.length, n2 = str2.length;
int max = -1, index = 0;
int[][] memo = new int[n1+1][n2+1];
for(int i = 1; i <= n1; i++)
for(int j = 1; j <= n2; j++)
if(str1[i-1] == str2[j-1])
memo[i][j] = memo[i-1][j-1] +1;
if(n1 <= n2){
for(int j = 1; j <= n2; j++)
for(int i = 1; i <= n1; i++)
if(memo[i][j] > max){
max = memo[i][j];
index = i;
}
}else{
for(int i = 1; i <= n1; i++)
for(int j = 1; j <= n2; j++)
if(memo[i][j] > max){
max = memo[i][j];
index = i;
}
}
System.out.println(s1.substring(index-max,index));
}
}
思路:dp[i][j]表示str1[0…i]与str2[0…j]的最长公共子串的长度
如果 str1 的长度为 N,str2 的长度为 M,生成大小为 N*M 的 数组 dp , dp[i][j]表示 str1[0…i] 与 str2[0…j] 的
最长公共子串的长度。
计算dp[i][j] 的方法如下:
矩阵 dp 的第一列 dp[0…m-1][0].对于 某个位置(i,0)如果str1[i]==str2[0],则dp[i][0]=1,否则dp[i][0]=0
矩阵 dp 的第一行 dp[0][0…n-1].对于 某个位置(0,j)如果str1[0]==str2[j],则dp[0][j]=1,否则dp[0][j]=0
其他位置从左到右从上到下计算,dp[i][j]的值只有两种情况:
1). str1[i]==str2[j],dp[i][j]=dp[i-1][j-1]+1;
2). tr1[i]!=str2[j]则dp[i][j]=0;
str1=”abc”,str2=”caba”的 dp 矩阵如下:
a b c
1
c 0 0 1
a 1 0 0
b 0 2 0
a 1 0 0
短字串sstr为行str1,长字串lstr为列str2
重要
public static int getCommonStr(String sstr,String lstr){
int len1=sstr.length();
int len2=lstr.length();
int[][] dp=new int[len1][len2];
int max=0;
//第一列赋值,判断sstr中第一个字符是否在lstr中出现
for(int i=0;i<len1;i++){
if (sstr.charAt(i)==lstr.charAt(0)){
dp[i][0]=1;
}
else
dp[i][0]=0;
}
//第一行赋值,判断llstr中第一个字符是否在sstr中出现
for(int j=0;j<len2;j++){
if (lstr.charAt(j)==sstr.charAt(0)){
dp[0][j]=1;
}
else
dp[0][j]=0;
}
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(sstr.charAt(i)==lstr.charAt(j)){
dp[i][j]=dp[i-1][j-1]+1;
}
else
dp[i][j]=0;//区别最长子序列
if(dp[i][j]>max)
max=dp[i][j];
}
}
return max;
}
}
或者在字符串前各加一个空字符,初始化dp[len1+1][len2+1]
import java.util.Scanner;
public class Main {
public static void commenSub(String s1,String s2){
s1=" "+s1;//相当于初始化a[0]=0;a[1]~a[m-1]=s1;
s2=" "+s2;
char a[]=s1.toCharArray();
char b[]=s2.toCharArray();
int m=a.length;
int n=b.length;
int c[][]=new int[m][n];
int max=0;
//没有初始化
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
if(a[i]==b[j]){//相等
c[i][j]=c[i-1][j-1]+1;
}else{//不等
c[i][j]=0;
}
if(max<c[i][j]){max=c[i][j];}//记录最长字串
}
}
System.out.println(max);
}
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String s1=sc.next();
String s2=sc.next();
commenSub(s1,s2);
}
}
}
或者在字符串前各加一个空字符,初始化dp[len1+1][len2+1]
dp[len1+1][len2+1]的方法:dp[i][j]表示str1的前i个字符串与str2的前j个字符串,此时字符索引为i-1,j-1;最后一个为dp[len1][len2]表示str1的所有len1个字符串与str2的所有len2个字符串
public static int getCommonStrLength(String str1, String str2){
int len1 = str1.length();
int len2 = str2.length();
int[][] dp = new int[len1+1][len2+1];
for(int i=0;i<=len1;i++){
for(int j=0;j<=len2;j++){
dp[i][j] = 0; ?
}
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(str1.charAt(i-1) == str2.charAt(j-1)){?为什么判断前一个
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = 0; //区别在这儿
}
}
}
int max = 0;
for(int i=0;i<=len1;i++){
for(int j=0;j<=len2;j++){
if(max < dp[i][j])
max = dp[i][j];
}
}
return max;
}
}
最长公共序列
最长公共子序列是:
dp[i][j] – 表示子串str1[0…i]和子串str[0…j]的最长公共子序列
当str1[i] == str2[j]时,dp[i][j] = dp[i-1][j-1] + 1;
否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
最优解为dp[len1-1][len2-1];
或者dp[len+1][len+2]的方法
public static int getCommonStr(String sstr,String lstr){
int len1=sstr.length();
int len2=lstr.length();
int[][] dp=new int[len1][len2];
int max=0;
//第一列赋值,判断sstr中第一个字符是否在lstr中出现
for(int i=0;i<len1;i++){
if (sstr.charAt(i)==lstr.charAt(0)){
dp[i][0]=1;
}
else
dp[i][0]=0;
}
//第一行赋值,判断llstr中第一个字符是否在sstr中出现
for(int j=0;j<len2;j++){
if (lstr.charAt(j)==sstr.charAt(0)){
dp[0][j]=1;
}
else
dp[0][j]=0;
}
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(sstr.charAt(i)==lstr.charAt(j)){
dp[i][j]=dp[i-1][j-1]+1;
}
else
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);//区别
}
}
return dp[len1-1][len2-1];
}
}
public static int getCommonStrLength(String str1, String str2){
int len1 = str1.length();
int len2 = str2.length();
int[][] dp = new int[len1+1][len2+1];
for(int i=0;i<=len1;i++){
for(int j=0;j<=len2;j++){
dp[i][j] = 0;//全部初始化为0
}
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(str1.charAt(i-1) == str2.charAt(j-1)){//表示str1前i个与str2前j个,此时字符串索引为i-1,j-1
dp[i][j] = dp[i-1][j-1] + 1;
}else{
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[len1][len2];
}
}