动态规划

32. Longest Valid Parentheses

LeetCode专题

我们设置dp[i]为第i位上以")"结尾的最大括号个数,则有三种情况:

  1. 若结尾为"(",则dp[i]=0
  2. 若结尾为")",且前一位为"(",则dp[i]=dp[i-2]+2
  3. 若结尾为")",但前一位也为")",此时我们只需挖空连续的已匹配括号,判断前一位是否为"(",例如()(())即,此时需要判断s[i-dp[i-1]-1] == '(' ,若成立则dp[i]=dp[i-1]+2+dp[i-dp[i-1]-2],否则dp[i]=0
class Solution {
public:
    int longestValidParentheses(string s) {
        // 16.51---16.56
        int n=s.size();
       // cout<<n<<endl;
        if(n==0)
            return 0;
        int dp[n];
        memset(dp,0,sizeof(dp));
        if(s[1]==')'&&s[0]=='(')
            dp[1]=2;
        for(int i=2;i<n;i++){
         //   cout<<i<<endl;
            if(s[i]=='(')
                dp[i]=0;
            if(s[i]==')'&&s[i-1]=='(')
                dp[i]=dp[i-2]+2;
            else if(s[i]==')'&&s[i-1]==')'){
                if(i-dp[i-1]-1>=0&&s[i-dp[i-1]-1]=='(')
                    dp[i]=i-dp[i-1]-1-1>=0?dp[i-1]+2+dp[i-dp[i-1]-1-1]:dp[i-1]+2;
                else
                    dp[i]=0;
            }
                
        }
        //cout<<"hello";
        sort(dp,dp+n);
        //cout<<dp[n-1];
        return dp[n-1];
    }
};

213. House Robber II

LeetCode专题

相对于上一题198. House Robber,此题的改版只是变成了环路的情形,环路只需要考虑max{偷第1家到第n-1家,偷第二家到第n家}即可.
通用的状态转移公式为: dp[i]=max(dp[i-1],dp[i-2]+nums[i])

class Solution {
public:
    int rob(vector<int>& nums) {
        int dp[1000];
        int dp2[1000];
        if(nums.size()==0)
            return 0;
        if(nums.size()==1)
            return nums[0];
        if(nums.size()==2)
            return max(nums[0],nums[1]);
        dp[0]=nums[0];
        dp[1]=max(nums[0],nums[1]);
        //环路,即为第1家和最后一家只能偷一个
        // 从第1家偷到第n-1家
        for(int i=2;i<nums.size()-1;i++){
            dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
        }
        // 从第2家偷到第n家
        dp2[0]=nums[1];
        dp2[1]=max(nums[2],nums[1]);
        for(int i=2;i<nums.size()-1;i++){
            dp2[i]=max(dp2[i-1],dp2[i-2]+nums[i+1]);
        }
        return max(dp[nums.size()-2],dp2[nums.size()-2]);
        
    }
};

718. Maximum Length of Repeated Subarray

LeetCode专题

首先得区分最长公共子序列LCS和最长公共子串,通常,substr都指的是连续的字符串,而公共子序列则可以不用连续。
因而对这两种题型解法不同:
子序列
/* dp状态转移方程:
* dp[i][j]表示str1长度为i,str2长度为j时的最长公共子序列的值
* str1[i]=str2[j],dp[i][j] = dp[i-1][i-1] + 1
* str1[i]!=str2[j], dp[i][j] = max{dp[i-1][j],dp[i][j-1]}
* 初始化二维dp数组均为0
* /
子串
/
dp状态转移方程:
* dp[i][j]表示str1长度为i,str2长度为j时的最长公共子串的值
* str1[i]=str2[j],dp[i][j] = dp[i-1][i-1] + 1
* 只有连续等于才行,初始化均为0
* */
最长公共子序列

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int len1=A.size();
        int len2=B.size();
        int dp[len1+1][len2+1];
        memset(dp,0,sizeof(dp));
        for(int i=0;i<=len1;i++){
            for(int j=0;j<=len2;j++){
                if(i==0||j==0)
                    dp[i][j]=0;
                else if(A[i-1]==B[j-1])
                    dp[i][j]=dp[i-1][j-1]+1;
                else 
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[len1][len2];
    }
};

最长公共子串

class Solution {
public:
    int findLength(vector<int>& A, vector<int>& B) {
        int len1=A.size();
        int len2=B.size();
        int dp[len1+1][len2+1];
        memset(dp,0,sizeof(dp));
        int max=-1;
        for(int i=0;i<len2;i++)
            if(A[0]==B[i])
                dp[0][i]=1;
        for(int i=0;i<len1;i++)
            if(A[i]==B[0])
                dp[i][0]=1;        
        for(int i=1;i<len1;i++){
            for(int j=1;j<len2;j++){                     
                if(A[i]==B[j])
                    dp[i][j]=dp[i-1][j-1]+1;
                max=max>dp[i][j]?max:dp[i][j];
            }
        }
        return max;
    }
};

相关文章: