对于长度为n的一个字符串A(仅包含数字,大小写英文字母),请设计一个高效算法,计算其中最长回文子串的长度
class Solution {
public:
// abcbc
int getLongestPalindrome(string A) {
int len = A.size();
vector> dp(len,vector(len,false));
int res = 0;
for(int i = len -1; i >= 0; i--) {
for(int j = i; j < len;j++) {
if(A[i] == A[j]) {
if(j-i <= 1) { //表示相邻的位置情况
dp[i][j] = true;
res = max(res,j-i+1);
}
else if(dp[i+1][j-1]) {
dp[i][j] = true;
res = max(res,j-i+1); //获取最大长度
}
}
}
}
return res;
}
};
给定两个字符串str1和str2,输出两个字符串的最长公共子串,保证str1和str2的最长公共子串存在且唯一
class Solution {
public:
string LCS(string str1, string str2) {
int len1 = str1.size();
int len2 = str2.size();
vector> dp(len1 + 1, vector(len2 + 1, 0));
int end = 0;
int maxLen = 0;
for (int i = 1; i < len1 + 1; i++) {
for (int j = 1; j < len2 + 1; j++) {
if (str1[i - 1] == str2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1; //公共子串需要保证连续的字符相等
} else {
dp[i][j] = 0;
}
if (maxLen < dp[i][j]) {
maxLen = dp[i][j];
end = i - 1; //记录位置信息
}
}
}
return str1.substr(end - maxLen + 1, maxLen);
}
};
需要注意的是,公共子串和子序列的不一样的地方,子串需要保证的是连续的字符都是需要相同,所以导致动态转移方程中 dp[i][j] = dp[i-1][j-1] + 1,而不是 需要和dp[i-1][j]、dp[i][j-1] 进行比较
给定两个字符串str1和str2,输出两个字符串的最长公共子串,返回最长公共子序列的长度数值
class Solution {
public:
int LCS(string s1, string s2) {
int len1 = s1.size();
int len2 = s2.size();
vector> dp(len1 + 1,vector(len2+1,0));
for(int i = 1; i < len1 + 1; i++) {
for(int j = 1; j < len2 + 1;j++) {
if(s1[i-1] == s2[j-1]) { //下标从0开始,所以是i-1,j-1
dp[i][j] = dp[i-1][j-1] + 1; //s1 == s2的时候,根据状态转移方程
}
else {
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);//取其中一个最大的数值
}
}
}
return dp[len1][len2];
}
};
特别需要注意的是dp[i][j] = dp[i-1][j-1] + 1的理解,对这个需要分析和理解递归的子逻辑
给定两个字符串 str1 和 str2 ,请你算出将 str1 转为 str2 的最少操作数
你可以对字符串进行3种操作:1.插入一个字 2.删除一个字符 3.修改一个字符
class Solution {
public:
int editDistance(string str1, string str2) {
int len1 = str1.size();
int len2 = str2.size();
vector> dp(len1+1,vector(len2+2,0));
//dp[i][j] 表示str1的前 i 个字符 和str2的前j个字符的编辑距离的操作数
//边界问题处理,str2 为空的时候 dp[i][0],表示str1字符串变成空字符串的操作
for(int i = 1; i < len1+1; i++) {
dp[i][0] = dp[i-1][0] + 1;
}
// 表示一个str1为空字符串,变成str2的操作数
for(int j = 1; j< len2 + 1; j++) {
dp[0][j] = dp[0][j-1] + 1; //表示前一个字符 直接 +1
}
for(int i = 1; i < len1 + 1; i++) {
for(int j = 1; j< len2 + 1; j++) {
if(str1[i-1] == str2[j-1]) { //当前字符一样,不需要任何操作
dp[i][j] = dp[i-1][j-1];
}
else { //当前字符不一样,需要delete or add or replace
// str1[i] != str2[j] 有下面操作
/*
dp[i-1][j-1] str1 or str2 替换操作 得到dp[i][j] -> dp[i-1][j-1] +1
dp[i-1][j] 表示str1删除i字符 + 1
dp[i][j-1] 表示str2 删除j字符 +1
*/
dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1])) + 1;
}
}
}
return dp[len1][len2];
}
};
输入一个长度为n的整型数组array,数组中的一个或连续多个整数组成一个子数组,子数组最小长度为1。求所有子数组的和的最大值
class Solution {
public:
int FindGreatestSumOfSubArray(vector array) {
if(array.empty()) return 0;
vector dp(array.size(),0);
dp[0] = array[0];
int result = dp[0];
for(int i = 1; i < array.size(); i++) {
dp[i] = max(dp[i-1] + array[i],array[i]);
if(dp[i] > result) result = dp[i];
}
return result;
}
};
给定数组arr,arr中所有的值都为正整数且不重复。每个值代表一种面值的货币,每种面值的货币可以使用任意张,再给定一个aim,代表要找的钱数,求组成aim的最少货币数。
如果无解,请返回-1.
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 最少货币数
* @param arr int整型vector the array
* @param aim int整型 the target
* @return int整型
*/
int minMoney(vector& arr, int aim) {
//dp数组记录货币数值为aim的数据需要最少的货币个数
vector dp(aim+1,aim+1);//数组初始化,每一个元素max
dp[0] = 0; //第一个元素为0
for(int i = 0; i < arr.size(); i++) {
int value = arr[i]; //取出其中一个货币
for(int j = value; j <= aim; j++) {
dp[j] = min(dp[j],dp[j - value] + 1); //dp[v1] dp[v2]最小数
}
}
if(dp[aim] == aim + 1) return -1;
return dp[aim];
}
};