给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则输出-1。
输出包括两行,第一行代表字符串str1,第二行代表str2。
输出一行,代表他们最长公共子序列。如果公共子序列的长度为空,则输出-1。
1A2C3D4B56 B1D23CA45B6A
123456
"123456"和“12C4B6”都是最长公共子序列,任意输出一个。
时间复杂度,空间复杂度
。(n,m分别表示两个字符串长度)
import java.util.Scanner;
public class Main {
public static String process(String str1, String str2) {
if (str1 == null || str1.length() == 0 || str2 == null || str2.length() == 0) {
return "";
}
char[] char1 = str1.toCharArray();
char[] char2 = str2.toCharArray();
int[][] dp = dp(char1, char2);
int m = str1.length() - 1;
int n = str2.length() - 1;
char[] res = new char[dp[m][n]];
int index = res.length - 1;
while (index >= 0) {
if (n > 0 && dp[m][n] == dp[m][n - 1]) {
n--;
} else if (m > 0 && dp[m][n] == dp[m - 1][n]) {
m--;
} else {
res[index--] = char1[m];
m--;
n--;
}
}
return String.valueOf(res);
}
public static int[][] dp(char[] str1, char[] str2) {
int[][] dp = new int[str1.length][str2.length];
dp[0][0] = str1[0] == str2[0] ? 1 : 0;
for (int i = 1; i < str1.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], str1[i] == str2[0] ? 1 : 0);
}
for (int i = 1; i < str2.length; i++) {
dp[0][i] = Math.max(dp[0][i - 1], str2[i] == str1[0] ? 1 : 0);
}
for (int i = 1; i < str1.length; i++) {
for (int j = 1; j < str2.length; j++) {
int max = Math.max(dp[i - 1][j], dp[i][j - 1]);
if (str1[i] == str2[j]) {
max = Math.max(dp[i - 1][j - 1] + 1, max);
}
dp[i][j] = max;
}
}
return dp;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str1 = sc.next();
String str2 = sc.next();
System.out.println(process(str1, str2));
}
}
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));
char[] str1 = br.readLine().toCharArray();
char[] str2 = br.readLine().toCharArray();
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[i - 1] == str2[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]);
}
}
}
// 求完最长公共子序列的长度再把最长公共子序列还原出来
int m = str1.length;
int n = str2.length;
if(dp[m][n] == 0){
System.out.println(-1);
}else{
char[] res = new char[dp[m][n]];
int index = res.length - 1;
while(index >= 0){
if(n > 0 && dp[m][n] == dp[m][n - 1]){
n--; // 不包括str2[n-1]也可以达到这个长度,n就往前指
}else if(m > 0 && dp[m][n] == dp[m - 1][n]){
m--; // 不包括str1[m-1]也可以达到这个长度,m就往前指
}else{
res[index--] = str1[m - 1]; // 不能不包括str1[m-1]了,追加该字符
m--;
n--;
}
}
System.out.println(String.valueOf(res));
}
}
} #include <bits/stdc++.h>
using namespace std;
int getlenght(const string &str1,const string &str2,vector<vector<int>> &dp){
dp[0][0]=str1[0]==str2[0] ? 1:0;
for(int i=1;i<str1.size();i++)
dp[i][0] = dp[i-1][0]==1 ? 1 : (str1[i]==str2[0]? 1:0);
for(int j=1;j<str2.size();j++)
dp[0][j] = dp[0][j-1]==1 ? 1 : (str2[j]==str1[0]? 1:0);
for(int i=1;i<str1.size();i++){
for(int j=1;j<str2.size();j++){
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
if(str1[i]==str2[j])
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
}
}
return dp[str1.size()-1][str2.size()-1];
}
int main(){
string str1,str2;
getline(cin,str1);
getline(cin,str2);
vector<vector<int>> dp(str1.size(),vector<int>(str2.size(),0));
int lenght=getlenght(str1,str2,dp);
string ans;
ans.resize(lenght);
int index = lenght-1,x=str1.size()-1,y=str2.size()-1;
while(index>=0){
if(y>=1&&dp[x][y]==dp[x][y-1])
y--;
else if(x>=1&&dp[x][y]==dp[x-1][y])
x--;
else{
ans[index--]=str1[x];
x--;
y--;
}
}
cout<<ans;
return 0;
} import java.util.*;
public class Main{
public static int count = -1;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
byte[] s1 = in.nextLine().getBytes();
byte[] s2 = in.nextLine().getBytes();
for(int i=0;i<s1.length;i++){
for(int j=0;j<s2.length;j++){
StringEquals(s1,i,s2,j);
}
}
System.out.println(count);
}
public static void StringEquals(byte[] s1, int i, byte[] s2, int j){
int sum = 0;
while(i<s1.length&&j<s2.length&&s1[i]==s2[j]){
sum++;
i++;
j++;
}
if(sum!=0){
count = Math.max(count,sum);
}
}
}笑死,在题目题目理解错的基础上(以为是连续子串),想着应该是过不了测试的(准备优化),结果过了,
请问这个测试用例是怎么设计的,这都能过?
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1,s2;
cin>>s1;
cin>>s2;
vector<vector<int>>dp(s1.size()+1,vector<int>(s2.size()+1));
for(int i=0;i<s1.size()+1;i++)
{
for(int j=0;j<s2.size()+1;j++)
{
if(i==0||j==0)
dp[i][j]=0;
else if(s1[i-1]==s2[j-1])
dp[i][j]=dp[i-1][j-1]+1;
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
cout<<dp[s1.size()][s2.size()]<<endl;
return 0;
} 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();
System.out.println(maxSubSequence(str1,str2).length() > 0 ? maxSubSequence(str1,str2):-1);
}
}
public static String maxSubSequence(String str1,String str2) {
int M = str1.length();
int N = str2.length();
//多添加一行一列便于初始化
int[][] dp = new int[M+1][N+1];//dp[i][j] 表示 str1[0~i-1] 与 str2[0~j-1] 的最长公共子序列的长度
int maxLen = 0;
String maxSubSequence = "";
for(int i = 1;i < M+1;i++){
for(int j = 1;j < N+1;j++){
if(str1.charAt(i-1) == str2.charAt(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]);
}
if(dp[i][j] > maxLen){
maxLen = dp[i][j];
maxSubSequence += str1.charAt(i-1);
}
}
}
return maxSubSequence;
}
}
// write your code here cpp
#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
static string fun(string& s1, string& s2) {
int size1 = s1.size(), size2 = s2.size();
string res;
for(int i = 0; i < size1; ++i){
for(int j = 0; j < size2; ++j){
if(s1[i] == s2[j]){
res += s1[i];
}
}
}
return res;
}
};
int main() {
string s1, s2;
while (cin >> s1 >> s2) {
cout << Solution::fun(s1, s2) << endl;
}
return 0;
} #include <bits/stdc++.h>
using namespace std;
int main(){
string s1, s2, t="";
cin>>s1>>s2;
int n=s1.length(), m=s2.length();
int dp[n+1][m+1];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(s1[i]==s2[j]){
t += s1[i];
dp[i+1][j+1] = dp[i][j] + 1;
}else{
dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]);
}
}
cout<<t<<endl;
return 0;
} public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
String str1 = scan.nextLine();
String str2 =scan.nextLine();
StringBuilder sb = new StringBuilder();
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)) {
sb .append(str1.charAt(i-1));
dp[i][j] = 1 + dp[i-1][j-1];
}else {
int v1 = Math.max(dp[i-1][j], dp[i][j-1]);
dp[i][j] = v1;
}
}
}
System.out.println(sb);
} 这是前一半,动态规划求最长公共子序列的长度:力扣-1143-最长公共子序列
扫了一遍他们的题解,大概是逆向遍历一遍去还原字符串
我们来看看怎么根据dp数组把这个串还原
这里其实两次遍历了dp数组,也就是说,时间复杂度是O(2M*N),空间复杂度是二维数组+res一维数组的长度
#include<iostream>
#include<vector>
using namespace std;
int main() {
string text1, text2;
cin >> text1 >> text2;
int m = text1.size(), n = text2.size();
// dp[i][0]和dp[0][j]都初始化为0
vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (text2[i - 1] == text1[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
//for (vector<int> nums : dp) {
// for (int num : nums) cout << num << " ";
// cout << endl;
//}
// 还原字串
if (!dp[n][m]) cout << -1;
else {
vector<char> res(dp[n][m]);
int index = dp[n][m] - 1;
while (index >= 0) {
if (m > 0 && dp[n][m] == dp[n][m - 1]) m--;
else if (n > 0 && dp[n][m] == dp[n - 1][m]) n--;
else {
res[index--] = text2[n - 1];
n--;
m--;
}
}
for (char ch : res) cout << ch;
}
return 0;
}
str1 = input()
str2 = input()
n, m = len(str1), len(str2)
dp = [[0] * n for _ in range(m)]
dp[0][0] = 0 if str1[0] != str2[0] else 1
for i in range(1, m):
dp[i][0] = 0 if str1[0] != str2[i] else 1
dp[i][0] = max(dp[i - 1][0], dp[i][0])
for i in range(1, n):
dp[0][i] = 0 if str1[i] != str2[0] else 1
dp[0][i] = max(dp[0][i - 1], dp[0][i])
for i in range(1, m):
for j in range(1, n):
if str2[i] == str1[j]:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1] + 1)
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
i, j = m - 1, n - 1
res = []
if dp[-1][-1] == 0:
print(-1)
exit()
while j >= 0 and i >= 0:
if i > 0 and dp[i][j] == dp[i - 1][j]:
i -= 1
elif j > 0 and dp[i][j] == dp[i][j - 1]:
j -= 1
else:
res.append(str1[j])
i -= 1
j -= 1
print("".join(res[::-1])) #include <iostream>
#include <vector>
#include <string>
using namespace std;
string LCS(string& s1, string& s2, vector<vector<int>>& dp)
{
int len1 = s1.size();
int len2 = s2.size();
int len = dp[len1][len2];
string ans = "";
while(len)
{
if(len1 >= 1 && dp[len1][len2] == dp[len1 - 1][len2])
len1--;
else if(len2 >= 1 && dp[len1][len2] == dp[len1][len2 - 1])
len2--;
else
{
ans = s1[--len1] + ans;
len2--;
len--;
}
}
return ans;
}
int main()
{
string s1, s2;
while(cin >> s1 >> s2)
{
int len1 = s1.size();
int len2 = s2.size();
vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(s1[i - 1] == s2[j - 1])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
string ans = LCS(s1, s2, dp);
if(ans.size())
cout << ans << endl;
else
cout << -1 << endl;
}
return 0;
} import java.io.*;
public class Main{
public static void main(String[] args)throws Exception{
try(BufferedReader bf = new BufferedReader(new InputStreamReader(System.in))){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str1 = br.readLine();
String str2 = br.readLine();
String result = lcse(str1, str2);
System.out.println(result.equals("") ? -1 : result);
}catch(IOException e){
e.printStackTrace();
}
}
public static int[][] getdp(char[] str1,char[] str2){
int[][] dp=new int[str1.length][str2.length];
dp[0][0]=str1[0]==str2[0]?1:0;
for(int i=1;i<str1.length;i++){
dp[i][0]=Math.max(dp[i-1][0],str1[i]==str2[0]?1:0);
}
for(int j=1;j<str2.length;j++){
dp[0][j]=Math.max(dp[0][j-1],str1[0]==str2[j]?1:0);
}
for(int i=1;i<str1.length;i++){
for(int j=1;j<str2.length;j++){
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
if(str1[i]==str2[j]){
dp[i][j]=Math.max(dp[i][j],dp[i-1][j-1]+1);
}
}
}
return dp;
}
public static String lcse(String str1,String str2){
if(str1==null||str2==null||str1.equals("")||str2.equals("")){
return "";
}
char[] chs1=str1.toCharArray();
char[] chs2=str2.toCharArray();
int[][] dp=getdp(chs1,chs2);
int m=chs1.length-1;
int n=chs2.length-1;
char[] res=new char[dp[m][n]];
int index=res.length-1;
while (index>=0){
if(n>0&&dp[m][n]==dp[m][n-1]){
n--;
}else if(m>0&&dp[m][n]==dp[m-1][n]){
m--;
}else{
res[index--]=chs1[m];
m--;
n--;
}
}
return String.valueOf(res);
}
}
#include<iostream>
using namespace std;
const int N = 5000+10;
int end_[N][N];
string lcs(string& a, string &b) {
int n = a.size(),m = b.size();
int len =end_[n][m];
string res(len,'0');
while(len) {
if(n>=1 && end_[n][m] == end_[n-1][m]) --n;
else if(m>=1 && end_[n][m] == end_[n][m-1]) --m;
else {
res[--len] = a[--n];
--m;
}
}
return res;
}
int main() {
string a,b;
cin>>a>>b;
for(int i=1;i<=a.size();++i) {
for(int j=1;j<=b.size();++j) {
end_[i][j] = max(end_[i][j-1],end_[i-1][j]);
if(a[i-1]==b[j-1]) end_[i][j] = max(end_[i][j] ,end_[i-1][j-1]+1);
}
}
cout << lcs(a,b) <<endl;
return 0;
} 答案卡在 80% ,但是我感觉我的没有错
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
char[] str1 = bf.readLine().toCharArray();
char[] str2 = bf.readLine().toCharArray();
int[][] dp = new int[str1.length+1][str2.length+1];
int[][] dr = new int[str1.length][str2.length];
int n = str1.length;
int m = str2.length;
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
if (str1[i-1]==str2[j-1]){
dp[i][j] = dp[i-1][j-1]+1;
dr[i-1][j-1] = 1;
}else {
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
dr[i-1][j-1] = dp[i-1][j]>=dp[i][j-1]?2:3;
}
}
}
StringBuilder sb = new StringBuilder();
for (int i=n-1, j=m-1;i>=0&&j>=0;){
if (dr[i][j]==1){
sb.append(Character.valueOf(str1[i]));
i--;
j--;
}else if (dr[i][j]==2){
i--;
}else if (dr[i][j]==3){
j--;
}
}
sb = sb.reverse();
System.out.print(sb);
}
}
C++ 思路清晰的代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5007;
int f[N][N];
int n, m;
string a, b;
void getString(int i, int j, int len) { // len表示最大公共子序列的长度
string s;
while (i >= 1 && j >= 1) { // 倒序还原
if (a[i - 1] == b[j - 1]) {
s += a[i - 1];
i--, j--;
} else {
if (f[i - 1][j] >= f[i][j - 1]) { // 说明是有f[i-1][j]转移过来的
i --;
} else j --;
}
}
reverse(s.begin(), s.end());
cout << s << endl;
}
int main() {
cin >> a >> b;
n = a.size(), m = b.size();
// "f[i][j]"表示所有A[1,...,i]与B[1,...,j]的公共子序列的集合,属性:最大值
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i - 1] == b[j - 1]) {
s
f[i][j] = f[i - 1][j - 1] + 1;
} else {
f[i][j] = max(f[i - 1][j], f[i][j - 1]); // 集合"f(i-1,j)"和"f(i,j-1)"有相交部分,但求最值可重复
}
}
}
int len = f[n][m]; // 最长公共子序列的长度
if (len == 0) cout << -1 << endl;
else getString(n, m, f[n][m]);
return 0;
}
import java.util.Scanner;
public class Main{
public int longestCommenSubSequence(String s1,String s2){
int len1 = s1.length(),len2 = s2.length();
int[][] dp = new int[len1+1][len2+1];
for(int i=1;i<=len1;++i){
for(int j=1;j<=len2;++j){
if(s1.charAt(i-1)==s2.charAt(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];
}
public static void main(String[] args){
Main c = new Main();
Scanner sc = new Scanner(System.in);
String s1 = sc.nextLine();
String s2 = sc.nextLine();
int res = c.longestCommenSubSequence(s1,s2);
System.out.println(res);
}
}