DP字符串

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];
    }
};

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值