1、单字符串/数组
模板
一般dp[i]表示以i结尾的子序列,,最终结果为dp[n-1]。
53. 最大子序和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 0);
for (int i=0; i<n; i++) {
dp[i] = nums[i];
}
int ans = nums[0];
for (int i=1; i<n; i++) {
dp[i] = max(0, dp[i-1]) + nums[i];
ans = max(ans, dp[i]);
}
return ans;
}
};
152. 乘积最大子数组
class Solution {
public:
int maxProduct(vector<int>& nums) {
int n = nums.size();
vector<int> maxDp(n);
vector<int> minDp(n);
for (int i=0; i<n; i++) {
maxDp[i] = nums[i];
minDp[i] = nums[i];
}
for (int i=1; i<n; i++) {
maxDp[i] = max(maxDp[i], max(maxDp[i-1] * nums[i], minDp[i-1] * nums[i]));
minDp[i] = min(minDp[i], min(maxDp[i-1] * nums[i], minDp[i-1] * nums[i]));
}
int ans = INT_MIN;
for (int i=0; i<n; i++) {
ans = max(ans, maxDp[i]);
}
return ans;
}
};
368. 最大整除子集
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<vector<int>> dp(n); // 以nums[i]结尾的子串最大整除数组
for (int i=0; i<n; i++) {
for (int j=0; j<i; j++) {
if (nums[i] % nums[j] == 0) {
if (dp[i].size() < dp[j].size()) {
dp[i] = dp[j];
}
}
}
dp[i].push_back(nums[i]);
}
vector<int> ans;
for (int i=0; i<n; i++) {
if (dp[i].size() > ans.size()) {
ans = dp[i];
}
}
return ans;
}
};
300. 最长递增子序列
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
dp[0] = 1;
for (int i=1; i<n; i++) {
for (int j=0; j<i; j++) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
int ans = 1;
for (int i=0; i<n; i++) {
ans = max(ans, dp[i]);
}
return ans;
}
};
354. 俄罗斯套娃信封问题
二维的最长递增子序列:对0维度从小到大排序,第1为从大到小排序。然后求解第1维度的最长递增子序列。
class Solution {
public:
static bool cmp(const vector<int> &a, const vector<int> &b) {
if (a[0]!=b[0]) {
return a[0]<b[0];
} else {
return a[1]>b[1];
}
}
int maxEnvelopes(vector<vector<int>>& v) {
sort(v.begin(), v.end(), cmp);
int n=v.size();
vector<int> dp(n, 1);
for (int i=1; i<n; i++) {
for (int j=0; j<i; j++) {
if (v[i][1] > v[j][1]) {
dp[i] = max(dp[i], dp[j]+1);
}
}
}
int ans=0;
for (int i=0; i<n; i++) {
ans = max(ans, dp[i]);
}
return ans;
}
};
2、双字符串/数组
模板
一般使用dp[i][j]代表s1[0...i-1], s2[0...j-1]的取值,最终结果为dp[m][n]。
5. 最长回文子串
子串要求连续,子序列不要求连续。
class Solution {
public:
string longestPalindrome(string s) {
if (s.size() == 0) {
return 0;
}
int maxLength = 1;
int left = 0;
int n = s.size();
vector<vector<int>> dp(n, vector<int>(n));
for (int i=0; i<n; i++) {
dp[i][i] = 1;
for (int j=0; j<i; j++) {
dp[j][i] = s[j] == s[i] && (i-j<2 || dp[j+1][i-1]);
if (dp[j][i]) {
if (i-j+1 > maxLength) {
maxLength = i-j+1;
left = j;
}
}
}
}
return s.substr(left, maxLength);
}
};
516. 最长回文子序列
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n=s.size();
if (n==0) {
return 0;
}
vector<vector<int>> dp(n, vector<int>(n, 0));
for(int i=0; i<n; i++) {
dp[i][i]=1;
}
for(int i=n-2; i>=0; i--) {
for (int j=i+1; j<n; j++) {
if (s[i]==s[j]) {
dp[i][j] = dp[i+1][j-1]+2;
} else {
dp[i][j] = max(dp[i][j-1], dp[i+1][j]);
}
}
}
return dp[0][n-1];
}
};
72. 编辑距离
class Solution {
public:
int minDistance(string s1, string s2) {
int m=s1.size();
int n=s2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1));
dp[0][0]=0;
for (int i=1; i<=m; i++) {
dp[i][0]=i;
}
for (int j=1; j<=n; j++) {
dp[0][j]=j;
}
for (int i=1; i<=m; i++) {
for (int j=1; j<=n; j++) {
if (s1[i-1]==s2[j-1]) {
dp[i][j]=dp[i-1][j-1];
} else {
dp[i][j]=min(dp[i-1][j], min(dp[i-1][j-1], dp[i][j-1]))+1;
}
}
}
return dp[m][n];
}
};
1143. 最长公共子序列
class Solution {
public:
int longestCommonSubsequence(string s1, string s2) {
int m=s1.size();
int n=s2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for (int i=1; i<=m; i++) {
for (int j=1; j<=n; j++) {
if (s1[i-1]==s2[j-1]) {
dp[i][j]=dp[i-1][j-1]+1;
} else {
dp[i][j]=max(dp[i][j-1], dp[i-1][j]);
}
}
}
return dp[m][n];
}
};
583. 两个字符串的删除操作
长度和减去最长公共子序列。
class Solution {
public:
int minDistance(string s1, string s2) {
return s1.size() + s2.size() - 2 * maxCommonSubString(s1, s2);
}
int maxCommonSubString(string s1, string s2) {
int m=s1.size();
int n=s2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
dp[0][0]=0;
for(int i=1; i<=m; i++) {
for(int j=1; j<=n; j++) {
if (s1[i-1]==s2[j-1]) {
dp[i][j]=dp[i-1][j-1]+1;
} else {
dp[i][j]=max(dp[i][j-1], dp[i-1][j]);
}
}
}
return dp[m][n];
}
};
712. 两个字符串的最小ASCII删除和
class Solution {
public:
int minimumDeleteSum(string s1, string s2) {
int m=s1.size();
int n=s2.size();
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
dp[0][0]=0;
for (int i=1; i<=m; i++) {
dp[i][0]=dp[i-1][0]+s1[i-1];
}
for (int j=1; j<=n; j++) {
dp[0][j]=dp[0][j-1]+s2[j-1];
}
for (int i=1; i<=m; i++) {
for (int j=1; j<=n; j++) {
if (s1[i-1]==s2[j-1]) {
dp[i][j]=dp[i-1][j-1];
} else {
dp[i][j]=min(dp[i-1][j]+s1[i-1], dp[i][j-1]+s2[j-1]);
}
}
}
return dp[m][n];
}
};