查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!
数据范围:字符串长度
进阶:时间复杂度:,空间复杂度:
输入两个字符串
返回重复出现的字符
abcdefghijklmnop abcsafjklmnopqrstuvw
jklmnop
//Longest common substring 最长公共子串.子串是连续的。 //和之前的LCS(Longest common subsequence---最长公共子序列)不太一样,子序列不一定是连续的。 //不连续时,在求出dp矩阵后逆向求lcs时,返回路径既可以按↖方向走,也可以按←或↑走。 //连续时,逆向求lcs时只能按↖走。不过看题解中,有人直接在求dp时,就限制只能按↘方向动态求dp。学习了~ . #include<iostream> #include<vector> #include<string> using namespace std; string LCCS(const string& str1, const string& str2) { string ret; int sz1 = str1.size(), sz2 = str2.size(); vector<vector<int> > dp(sz1 + 1, vector<int>(sz2 + 1, 0)); for (int i = 1; i <= sz1; ++i) { for (int j = 1; j <= sz2; ++j) { if (str1[i - 1] == str2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; if (dp[i][j] > ret.size()) ret = str1.substr(i - dp[i][j], dp[i][j]); } } } return ret; } int main() { string str1, str2; while (cin >> str1 >> str2) { if (str1.size() > str2.size()) swap(str1, str2); cout << LCCS(str1, str2) << endl; } return 0; }
import java.util.ArrayList; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s1 = sc.nextLine(); String s2 = sc.nextLine(); if (s1.length()<s2.length()) { System.out.println(func(s1, s2)); } else { System.out.println(func(s2, s1)); } } } private static String func(String s1, String s2) { ArrayList<String> list = new ArrayList<>(); for(int i=0;i < s1.length()+1; i++) { for(int j=i+1; j<s1.length()+1;j++) { String subStr = s1.substring(i ,j); if (s2.contains(subStr) && subStr.length()>1) { list.add(subStr); } } } int maxLen = 0; int index = 0; // 找出第一个长度最大的子串索引 for(int i=0;i<list.size();i++) { int len = list.get(i).length(); if(maxLen < len) { maxLen = len; index = i; } } return list.get(index); } }dfs做法:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s1 = sc.nextLine(); String s2 = sc.nextLine(); if (s1.length()<s2.length()) { System.out.println(func(s1, s2)); } else { System.out.println(func(s2, s1)); } } } private static String func(String s1, String s2) { // 记录长度 int[][] dp = new int[s1.length()+1][s2.length()+1]; int maxLen = 0, startIdx = 0; for(int i=0;i<s1.length();i++) { for(int j=0;j<s2.length();j++) { if (s1.charAt(i) == s2.charAt(j)) { dp[i+1][j+1] = dp[i][j] + 1; if(dp[i+1][j+1] > maxLen) { maxLen = dp[i+1][j+1]; startIdx = i - maxLen; } } } } return s1.substring(startIdx + 1, startIdx+maxLen+1); } }
#include <string.h> int main(){ char str1[1000],str2[1000]; int count[1000]; //记录以串1各字符为首字母,后跟最大公共子串长度 while (~scanf("%s %s",str1,str2)) { int max=0; char temp[1000]; memset(count, 0, sizeof(count)); if (strlen(str1)>strlen(str2)) { strcpy(temp, str1); strcpy(str1, str2); strcpy(str2, temp); } for (int i=0; i<strlen(str1); i++) { //依次遍历串1中每个字符作为可能出现公共子串的首字母 for (int j=0; j<strlen(str2); j++) { //遍历找到与串1首字母相同的串2首字母 if (str1[i]==str2[j]) { int step; //公共子串遍历步长 int dist1=(int)strlen(str1)-i,dist2=(int)strlen(str2)-j; for (step=1; step<dist1<dist2?dist1:dist2; step++) if (str1[i+step]!=str2[j+step]) break; count[i]=count[i]>step?count[i]:step; //步长数组更新 if (i>0 && count[i]>count[max]) { max=i; //位置更新 } } } } for (int i=max; i<max+count[max]; i++) { printf("%c",str1[i]); } printf("\n"); } return 0; }
while True: try: a,b = input(),input() temp = "" count = 0 #比较字符串长度,将短字符串赋给a if len(a) > len(b): temp = a a = b b = temp #双循环遍历字符串a for i in range(len(a)): for j in range(i,len(a)): #查找b中公共子字符串 if a[i:j+1] not in b: break else: #筛选出最长的公共子串 if count < j-i+1: count = j-i+1 temp = a[i:j+1] print(temp) except: break
#include <iostream> #include <vector> #include <string> #include <sstream> #include <map> #include <set> #include <list> #include <deque> #include <algorithm> #include <cctype> #include <iomanip> #include<cstdlib> #include <functional> #include <bitset> using namespace std; void FindCommonSubString() { string str1, str2; while (cin >> str1 >> str2) { if (str1.size() > str2.size()) { string temp = str2; str2 = str1; str1 = temp; } int sz1 = str1.size(); int sz2 = str2.size(); vector<vector<int>> dp(sz1, vector<int>(sz2, 0)); for (int i = 0; i < sz1; ++i) { dp[i][0] = (str1[i] == str2[0] ? 1 : 0); } for (int i = 0; i < sz2; ++i) { dp[0][i] = (str2[i] == str1[0] ? 1 : 0); } for (int i = 1; i < sz1; ++i) { for (int j = 1; j < sz2; ++j) { if (str1[i] == str2[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; } } } int longest = 0; int start1 = 0; int start2 = 0; for (int i = 0; i < sz1; ++i) { for (int j = 0; j < sz2; ++j) { if (dp[i][j]>longest) { longest = dp[i][j]; start1 = i - longest + 1; start2 = j - longest + 1; } } } cout << str1.substr(start1, longest) << endl; } } int main() { FindCommonSubString(); return 0; }
import java.util.*; public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); String str1 = sc.nextLine(); String str2 = sc.nextLine(); System.out.println(longSubString(str1,str2)); } public static String longSubString(String str1,String str2){ String longStr = str1.length() > str2.length() ? str1 : str2; String shortStr = str1.length() < str2.length() ? str1 : str2; int shortLen = shortStr.length(); int longLen = longStr.length(); int maxLen = 0, start = 0; for(int i = 0; i < shortLen; i++){ //双指针逐渐靠近 for(int j = i, k = shortLen; k > j; k--){ String subStr = shortStr.substring(j,k); if(longStr.contains(subStr) && maxLen < subStr.length()){ //此时找到一个公共子串 //把这个公共子串的长度设置为当前最大的长度 maxLen = subStr.length(); //把这个公共子串的起始位置设置为切割子串的起始位置 start = j; //退出当前循环,进入下一个循环 } } } return shortStr.substring(start,start+maxLen); } }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s1 = sc.nextLine(); String s2 = sc.nextLine(); String longStr = s1.length() > s2.length()? s1 : s2; String shortStr = s1.length() < s2.length()? s1 : s2; String maxSubStr = shortStr.substring(0,1); int maxSubLen = 1; for (int i = 1; i <= shortStr.length(); i++) { //每次截取长度为i的字符串 abcde 5 for (int j = 0; j < shortStr.length()-i+1; j++) { String str = shortStr.substring(j,j+i);//长度为i的字符串 if (longStr.contains(str) && str.length() > maxSubLen) {//该串是否在长串里 maxSubStr = str; maxSubLen = str.length(); } } } System.out.println(maxSubStr); } } }
import java.io.*; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str = ""; while ((str = br.readLine()) != null) { String str1 = br.readLine(); System.out.println(method(str, str1)); } br.close(); } private static String method(String s1, String s2) { String shortStr = s1.length() < s2.length() ? s1 : s2; String longStr = s1.length() < s2.length() ? s2 : s1; for (int i = 0; i < shortStr.length(); i++) { for (int j = 0, k = shortStr.length() - i; k <= shortStr.length(); j++, k++) { if (longStr.contains(shortStr.substring(j, k))) { return shortStr.substring(j, k); } } } return null; } }
while True: try: a,b,res=input(),input(),'' short,long = (a,b) if len(a)<len(b) else (b,a) for i in range(len(short)): for j in range(len(short)): if short[i:j+1] in long and j+1 -i >len(res): res = short[i:j+1] print(res) except: break
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str1; while((str1 = br.readLine()) != null) { str1 = str1.trim(); String str2 = br.readLine().trim(); // 保证str2比str1长 if(str2.length() < str1.length()){ String temp = str1; str1 = str2; str2 = temp; } System.out.println(longestSubStr(str1, str2)); } } private static String longestSubStr(String str1, String str2) { int maxLen = 0, start = 0; // 动态规划求解,dp[i][j]表示str1[:i-1]和str2[:j-1]的最长公共子串长度 int[][] dp = new int[str1.length() + 1][str2.length() + 1]; for(int i = 1; i <= str1.length(); i++){ for(int j = 1; j <= str2.length(); j++){ if(str1.charAt(i - 1) == str2.charAt(j - 1)){ dp[i][j] = dp[i - 1][j - 1] + 1; if(dp[i][j] > maxLen){ maxLen = dp[i][j]; // 更新最大长度 start = i - maxLen; // 推算子串的起始位置 } } } } return str1.substring(start, start + maxLen); } }本题数据量比较小,用穷举法也可以AC
while True: try: s1 = input().strip() s2 = input().strip() l1, l2 = len(s1), len(s2) if l1 < l2: s1, s2 = s2, s1 l1, l2 = l2, l1 max_len = 0 res = "" for i in range(l2): for j in range(i + 1, l2 + 1): if s2[i:j] in s1 and j - i > max_len: max_len = j - i res = s2[i:j] print(res) except: break
import java.util.*; public class Main{ public static void main(String[] args){ Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ String[] strings = new String[2]; strings[0] = scanner.next(); strings[1] = scanner.next(); if (strings[0].length() > strings[1].length()){ String temp = strings[0]; strings[0] = strings[1]; strings[1] = temp; } System.out.println(findLongestCommonSubStr(strings)); } } public static String findLongestCommonSubStr(String[] strings){ int max = strings[0].length(); while (max >= 1){ for (int i = 0; i <= strings[0].length()-max; i++){ for (int j = 0; j <= strings[1].length()-max; j++){ if (strings[0].substring(i,i+max).equals(strings[1].substring(j,j+max))){ return strings[0].substring(i,i+max); } } } max -= 1; } return null; } }
#include <iostream> #include <string> using namespace std; int main() { string str1,str2; while(cin>>str1>>str2) { //保证str1是比较短的一个串 if(str1.size()>str2.size()) swap(str1,str2); int start = 0;//最长公共字符串的开始位置 int max = 0;//最长公共字串的长度 //用短串中的字符去挨个匹配长串中的字符,如果匹配的上,则继续短串和长串往后比,同时len++ //直到短串中的字符和长串中的字符不一样时,则,记录下最大长度 for(int i = 0;i<str1.size();i++) { for(int j = 0;j<str2.size();j++) { if(str1[i] == str2[j]) { int tmpi = i; int tmpj = j; int len = 0; while(str1[tmpi++] == str2[tmpj++]) len++; if(max < len) { start = i; max = len; } } } } cout<<str1.substr(start,max)<<endl; } return 0; }
public class Main{ public static void main(String[] args) { java.util.Scanner scanner = new java.util.Scanner(System.in); while (scanner.hasNext()) { char[] inputCharA = scanner.next().toCharArray(); char[] inputCharB = scanner.next().toCharArray(); String result; if (inputCharA.length > inputCharB.length) { result = find(inputCharB, inputCharA); } else { result = find(inputCharA, inputCharB); } System.out.println(result); } } public static String find(char[] inputCharA, char[] inputCharB) { int targetStartIndex = -1; int targetSubStrLength = -1; for (int i = 0; i < inputCharA.length; i++) { char charA = inputCharA[i]; for (int j = 0; j < inputCharB.length; j++) { char charB = inputCharB[j]; if (charA == charB) { int counter = 1; int tmpA = i + 1; for (int h = j + 1; h < inputCharB.length; h++) { if (tmpA < inputCharA.length) { if (inputCharB[h] == inputCharA[tmpA]) { counter++; tmpA++; } else { break; } } else { break; } if (counter > targetSubStrLength) { targetSubStrLength = counter; targetStartIndex = j; } } } } } StringBuilder stringBuffer = new StringBuilder(); for (int i = 0; i < targetSubStrLength; i++) { stringBuffer.append(inputCharB[i + targetStartIndex]); } return stringBuffer.toString(); } }
def longest_public_str(str1,str2): if len(str1)>len(str2): long_str=str1 short_str=str2 else: long_str=str2 short_str=str1 # l 初始化 l=[] for k in range(len(short_str)): if short_str[k] in long_str: l.append(short_str[k]) break # l=['a'] # 最长子串长度至少为2 for i in range(len(short_str)): s='' s+=short_str[i] for j in range(i+1,len(short_str)): s+=short_str[j] if s in long_str and len(s)>len(l[0]): l.pop() l.append(s) return l[0] while True: try: str1=input() str2=input() print(longest_public_str(str1,str2)) except: break
#include <iostream> #include <string> using namespace std; //str1 < str2 string FindPublicStr(string str1, string str2) { int len1 = str1.length(), len2 = str2.length(); //从大到小遍历子串长度 for(int l=len1; l>0; --l) { for(int i=0; i<len1-l+1; ++i) { int pos = str2.find(str1.substr(i, l)); if(pos != -1) return str1.substr(i, l); } } } int main() { string str1, str2; while(cin >> str1 >> str2) { if(str1.length() < str2.length()) cout << FindPublicStr(str1, str2) << endl; else cout << FindPublicStr(str2, str1) << endl; } }
while True: try: a = raw_input() b = raw_input() if len(a)>len(b): a,b = b,a ma = len(a) mb = len(b) ans = "" j = 1 for i in range(ma): while j<=ma and a[i:j] in b: j += 1 if (j-1-i)>len(ans): ans = a[i:j-1] if i == j: j += 1 print ans except: raise
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()) { String str1 = sc.next(); String str2 = sc.next(); if(str2.length() < str1.length()) { String temp = str2; str2 = str1; str1 = temp; } int cnt = 0;//存储最长公共子串长度 String need = "";//存储最长公共子串 int first = Math.max(str1.length(),str2.length());//存储最长公共字符串出现位置 for(int i=0; i<str1.length(); i++) { for(int j=i+1; j<str1.length(); j++) { String substr = str1.substring(i, j+1); if(str2.contains(substr)) { if(substr.length() > cnt) { cnt = substr.length(); need = substr; } } } } System.out.println(need); } } }