Hello,爱客们好,我是Tony
欢迎大家访问我的个人主页:Tony’s Blog,让我们一起站在巨人的肩膀之上!
最长公共子序列
编程题
给定两个字符串str1和str2,返回两个字符串的最长公共子序列
举例
str1=“1A2C3D4B56”,str2=“B1D23CA45BA”
"123456"或者“12C4B6”都是最长公共子序列,返回哪一个都行
思路
这道题可以用经典的动态规划来做,先把第一列和第一行算出来,再算整个二维向量
第一列 dp(i,0)=1,之后的dp(i+1…M-1,0)均为1,M为str1长度
第一列 dp(0,j)=1,之后的dp(0,j+1…N-1)均为1,N为str2长度
其余
if(str1[i]==str2[j]),dp(i,j)=max(dp(i,j),dp(i-1,j-1)+1)
if(str1[i]!=str2[j],dp(i,j)=max(dp(i-1),j),dp(i,j-1))
代码(动态规划)
// 最长公共子序列.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
string fun1(string str1, string str2)
{
int M = str1.size();
int N = str2.size();
vector<vector<int>>dp(M+ 1, vector<int>(N + 1));
int i, j;
int temp=0;
int i1, j1;
if (str1[0] == str2[0])
{
dp[0][0] = 1;
}
else
{
dp[0][0] = 0;
}
//第一列
for (i = 0; i < M; i++)
{
for (i1 = 0; i1 < i; i1++)
{
if (str1[i1] == str2[0])
{
temp = 1;
break;
}
}
if (temp == 1)
{
for (j1 = i; j1 < M; j1++)
{
dp[j1][0] = 1;
}
}
else
{
dp[i][0] = 0;
}
}
//第一行
temp = 0;
for (j = 0; j < N; j++)
{
for (i1 = 0; i1 < j; i1++)
{
if (str2[i1] == str1[0])
{
temp = 1;
break;
}
}
if (temp == 1)
{
for (j1 = j; j1 < N; j1++)
{
dp[0][j1] = 1;
}
}
else
{
dp[0][j] = 0;
}
}
for (i = 1; i < M; i++)
{
for (j = 1; j < N; 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);
}
}
}
cout << dp[M - 1][N - 1];
cout << endl;
/*int m = str1.size() - 1;
int n = str2.size() - 1;
vector<char>res;
res.resize(dp[m][n]+1);
int index=dp[M-1][N-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--] = str1[m];
m--;
n--;
}
}*/
int m = str1.size() - 1;
int n = str2.size() - 1;
vector<char>res;
res.resize(dp[m][n] + 1);
int index = dp[M - 1][N - 1];
while (index >0)
{
if (m>0&&n>0&&dp[m][n] > dp[m - 1][n] && dp[m][n] > dp[m][n - 1])
{
res.push_back(str1[m]);
m--;
n--;
index--;
}
else if(m>0 && dp[m][n] ==dp[m - 1][n])
{
m--;
}
else if (n>0 && dp[m][n] ==dp[m][n-1])
{
n--;
}
else
{
res.push_back(str1[m]);
m--;
n--;
index--;
}
}
string str;
for (vector<char>::iterator iter = res.end()-1; iter != res.begin(); iter--)
{
str += *iter;
}
return str;
}
int _tmain(int argc, _TCHAR* argv[])
{
int k;
string str1 = "1AAA2C3D4B567";
string str2 = "BaAA1D23CA45B6A7";
string res = fun1(str1, str2);
cout << res;
return 0;
}
最长公共子串
编程题
给定两个字符串str1和str2,返回两个字符串的最长公共子串
举例
str1=“1AB2345CD”,str2=“12345EF”,返回“2345”
思路
第一列 if(str1[i]==str2[0]) dp(i,0)=1 否则dp(i,0)=0
第一行 if(str1[0]==str2[j]) dp(0,j)=1否则dp(0,j)=0
其余
if(str1[i]==str2[j]) dp(i,j)=dp(i-1,j-1)+1
else
dp(i,j)=0
代码(动态规划)
// 最长公共子串.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
string fun(string str1, string str2)
{
int len1=str1.size();
int len2 = str2.size();
vector<vector<int>>dp(len1, vector<int>(len2));
int i, j;
if (str1[0] == str2[0])
{
dp[0][0] = 1;
}
else
{
dp[0][0] = 0;
}
for (i = 0; i < len1; i++)
{
if (str1[i] == str2[0])
{
dp[i][0] = 1;
}
else
{
dp[i][0] = 0;
}
}
for (j = 0; j < len2; j++)
{
if (str1[0] == str2[j])
{
dp[0][j] = 1;
}
else
{
dp[0][j] = 0;
}
}
for (i = 1; i < len1; i++)
{
for (j = 1; j < len2; j++)
{
if (str1[i] == str2[j])
{
dp[i][j] = dp[i - 1][j - 1] + 1;
}
else
{
dp[i][j] = 0;
}
}
}
int max = dp[0][0];
for (i = 0; i <dp.size(); i++)
{
for (j = 0; j <dp[0].size(); j++)
{
cout << dp[i][j] << " ";
if (max < dp[i][j])
{
max = dp[i][j];
}
}
cout << endl;
}
//打印子串
cout << "子串长度:"<<max<<endl;
int temp_i=0,temp_j=0;
for (i = 0; i < dp.size(); i++)
{
for (j = 0; j < dp[0].size(); j++)
{
if (dp[i][j] == max)
{
temp_i = i;
temp_j = j;
}
}
}
vector<char>temp;
string temp6="";
for (i = temp_i; i >0; i--)
{
temp.push_back(str1[i]);
}
for (vector<char>::iterator iter = temp.end()-1; iter != temp.begin(); --iter)
{
temp6 += *iter;
}
temp6 += temp[0];
return temp6;
}
int _tmain(int argc, _TCHAR* argv[])
{
string str1 = "abcde";
string str2 = "bebcd";
string res = fun(str1, str2);
cout << res;
return 0;
}
最长递增子序列
编程题
给定数组arr,返回arr最长递增子序列
举例
arr=[2,1,5,3,6,4,8,9,7],返回的最长递增子序列为[1,3,4,8,9]
思路
用动态归来来做,dp[i]表示以arr[i]这个数结尾的情况下,arr[0…i]中的最大递增子序列
dp[0]=1
dp[i]=max{dp[j]+1(0<=j<i,arr[j]<arr[i])}如果arr[0…i-1]中所有的数都不比arr[i]小,令dp[i]=1即可
代码(动态规划)
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int>fun1(vector<int>arr)
{
int i, j;
int maxnum;
vector<int>dp(arr.size() + 1);
vector<int>temp;
dp[0] = 1;
for (i = 1; i < arr.size(); i++)
{
for (j = 0; j < i; j++)
{
temp.push_back(1);
if (arr[j] < arr[i])
{
temp.push_back(dp[j]+1);
}
}
maxnum = *max_element(temp.begin(), temp.end());
dp[i] = maxnum;
temp.clear();
}
vector<int>restemp;
restemp.push_back(*max_element(dp.begin(), dp.end()));
restemp.push_back(max_element(dp.begin(), dp.end()) - dp.begin());
restemp.push_back(arr[max_element(dp.begin(), dp.end()) - dp.begin()]);
return restemp;
}
vector<int>fun2(vector<int>arr, vector<int>res)
{
int i, j, k;
int len = arr.size();
vector<int>temp2;
temp2.push_back(arr[res[1]]);
for (i = 0; i < res[0]; i++)
{
for (j = res[1] - 1; j >= 0; j--)
{
if (arr[j] < *min_element(temp2.begin(), temp2.end()))
{
temp2.push_back(arr[j]);
}
}
}
reverse(temp2.begin(), temp2.end());
return temp2;
}
int _tmain(int argc, _TCHAR* argv[])
{
int i, j;
int a1 = 91;
vector<int>arr = { 2,1,5, 3,6,4,8,9,10,12};
vector<int>res=fun1(arr);
for (i = 0; i < res.size(); i++)
{
cout << res[i]<<",";
}
cout << endl;
vector<int>res2=fun2(arr, res);
for (i = 0; i < res2.size(); i++)
{
cout << res2[i]<< ",";
}
return 0;
}
用动态规划好哈