动态规划合集

####最长有效括号

给定一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: “(()”
输出: 2
解释: 最长有效括号子串为 “()”
示例 2:
输入: “)()())”
输出: 4
解释: 最长有效括号子串为 “()()”

dp{i}表示0~i的有效括号子串的长度。
遇到’(‘直接跳过,因为之前没有与之匹配的括号。
遇到’)’,我们则开始进行讨论,j=i-1-dp[i-1] (我们需要跳过在这之前的已经匹配的有效子串) 例如: (()()) pos=6,j=1 dp[i-1]=4.
若j处的括号是’(’,那么状态转移方程为:dp{i}=dp{i-1}]+2;
我们还需要加j-1之前的有效子串。例如: () (()())

class Solution {
    public int longestValidParentheses(String s) {
        if(s.equals("")){
            return 0;
        }
        int ans=0;
        int len=s.length();
        int[] dp=new int[len];
        dp[0]=0;
        for(int i=1;i<len;++i){
            if(s.charAt(i)==')'){
                int j=i-1-dp[i-1];
                if(j>=0&&s.charAt(j)=='('){
                    dp[i]=dp[i-1]+2;
                    if(j-1>=0){
                        dp[i]+=dp[j-1];
                    }
                }
            }
            ans=Math.max(ans,dp[i]);
        }
        return ans;
    }
}

#####最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。
示例:
输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:
可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

O(logn)做法:利用lower_bound

class Solution {
    public int lengthOfLIS(int[] nums) {
        if(nums.length==0){
            return 0;
        }
        int total=0;
        int[] vec=new int[nums.length];
        vec[total++]=nums[0];
        for(int i=0;i<nums.length;++i){
            if(nums[i]>vec[total-1]){
                vec[total++]=nums[i];
            }else {
                vec[lower_bound(vec,total,nums[i])]=nums[i];
            }
        }
        return total;
    }
    public int lower_bound(int[] arr,int k,int target){
        int l=0;
        int r=k;
        while (l<r){
            int mid=l+(r-l)/2;
            if(arr[mid]>=target){
                r=mid;
            }else{
                l=mid+1;
            }
        }
        return l;
    }
}
10. 正则表达式匹配

给定一个字符串 (s) 和一个字符模式 §。实现支持 ‘.’ 和 ‘’ 的正则表达式匹配。
‘.’ 匹配任意单个字符。
'
’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = "a
"
输出: true
解释: ‘’ 代表可匹配零个或多个前面的元素, 即可以匹配 ‘a’ 。因此, 重复 ‘a’ 一次, 字符串可变为 “aa”。
示例 3:
输入:
s = “ab”
p = ".
"
输出: true
解释: "." 表示可匹配零个或多个(’’)任意字符(’.’)。
示例 4:
输入:
s = “aab”
p = “cab”
输出: true
解释: ‘c’ 可以不被重复, ‘a’ 可以被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p = “misisp*.”
输出: false

这道题我们需要分情况讨论,首先先注意一点 * 前一定是有字母的,例如 a* 就表示a可以为0个也可以为n个。
我们就要分清理讨论了。
首先dp{i,j}表示s串前i个与p串前j个字符的匹配情况。
如果si == pj的话,dp{i,j}=dp{i-1,j-1}
如果pj == '.'的话,dp{i,j}=dp{i-1,j-1},同上。
接下来就要讨论pj == '*'的情况了。

  • 1.s[i]!=p[j-1]&&p[j-1]!=’.’,即ab a* 这种情况,那么我就要舍弃a*这一部分,即a的个数为0,那么dp{i,j}=dp{i,j-2}.
  • 2.分类讨论(以下若有一项匹配成功那么说明s串匹配是true)
    • 当出现 bab,b.* 这种情况时,那么我们就要舍弃 .* 这种情况,那么dp{i,j}=dp{i,j-2},即舍弃这一部分。
    • 当出现aaa a* 这种情况,dp{i,j}=dp{i-1,j},这种就类似s串删除了一个a字符(这样子*就可以匹配多个a)
    • dp{i,j}=dp{i,j-1},例如 aabc a*bc 这种情况就像p串把 *变成了a,这样子就只匹配一个字符a.

至于初始化,dp[0][0]表示我们两个串还没开始匹配,那么肯定为true

class Solution {
    public boolean isMatch(String s, String p) {
        if(s==null||p==null){
            return false;
        }
        int n=s.length();
        int m=p.length();
        boolean[][] dp=new boolean[n+1][m+1];
        dp[0][0]=true;
        for(int i=1;i<m;++i){
            if(p.charAt(i)=='*'&&dp[0][i-1]){ 
                dp[0][i+1]=true;
            }
        }
        //这部分表示我们匹配串的多个开始位置 我们需要把他们都找出来。
        //因为不止dp[0][0]是开始的位置 例如c*a 我们是可以舍弃c*(使用0个c)从a开始的,
        //并不一定是从c开始,即dp[0][2]=true 具体的话自己思考一下就知道了
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if (s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='.'){
                    dp[i][j]=dp[i-1][j-1];
                }
                if(p.charAt(j-1)=='*'){
                    if(p.charAt(j-2)!=s.charAt(i-1)&&p.charAt(j-2)!='.'){
                        dp[i][j]=dp[i][j-2];
                    }else{
                        dp[i][j]=dp[i-1][j]||dp[i][j-1]||dp[i][j-2];
                    }
                }
            }
        }
        return dp[n][m];
    }
}
44. 通配符匹配

给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
'
’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = "
"
输出: true
解释: ‘’ 可以匹配任意字符串。
示例 3:
输入:
s = “cb”
p = “?a”
输出: false
解释: ‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。
示例 4:
输入:
s = “adceb”
p = “ab”
输出: true
解释: 第一个 '
’ 可以匹配空字符串, 第二个 '’ 可以匹配字符串 “dce”.
示例 5:
输入:
s = “acdcb”
p = "a
c?b"
输入: false

这道题比上一道更加直观,讨论的情况也少很多。
首先dp{i,j}表示s串前i个与p串前j个字符的匹配情况。
如果si==pj的话,dp{i,j}=dp{i-1,j-1}
如果pj=='.'的话,dp{i,j}=dp{i-1,j-1},同上。
接下来就要讨论pj=='*'的情况了。这一步是和上面一样的。
当pj=='*'的时候,其实很直观,*只有为空串或者匹配n个字符,而且多个字符是从s串第i个到第i+n-1个这个范围,
不可能是这个范围之外的串了,自己推一下就知道了。
匹配多个字符,就和上一题一样,dp{i,j}=dp{i-1,j},就是s串删除一个字符,只是上一题删除的重复的字符,
这一题删除的是不重复的多个字符。
接着是空串,即dp{i,j}=dp{i,j-1},即把*删掉,还有就是匹配一个字符,也是dp{i,j}=dp{i,j-1}.
那么转移方程就是dp{i,j}=dp{i-1,j}||dp{i,j-1}.其中一种成立即为true.
记得初始化化,即dp[0][0]不一定是开始的点,例如: ???? ?是可以为空串的。可以从dp[0][1]开始,
也可以从dp[0][2]开始,以此类推。 
class Solution {
    public boolean isMatch(String s, String p) {
        if(s==null||p==null){
            return false;
        }
        int n=s.length();
        int m=p.length();
        boolean[][] dp=new boolean[n+1][m+1];
        dp[0][0]=true;
        for(int i=1;i<=m;++i){
            if(p.charAt(i-1)=='*'&&dp[0][i-1]){
                dp[0][i]=true;
            }
        }
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(s.charAt(i-1)==p.charAt(j-1)||p.charAt(j-1)=='?'){
                    dp[i][j]=dp[i-1][j-1];
                }
                if(p.charAt(j-1)=='*'){
                    dp[i][j]=dp[i][j-1]||dp[i-1][j];
                }
            }
        }
        return dp[n][m];
    }
}
石子合并 —区间dp

传送门

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值