区间型动态规划总结

区间型动态规划,都是dp[i][j]由小的区间先计算,然后计算大的区间得到,模板就是:

for(int len = 2; len <= n; len++) {
            for(int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;

很多题都可以用这个模板写;

Longest Palindromic Subsequence 思路:区间型动态规划,f[i][j] 表示s[i] ~ s[j]之间最大的palindromic subsequence,递推公式是:设dp[i][j]表示第i到第j个字符间的最长回文序列的长度(i<=j)

状态初始条件:dp[i][i]=1 (i=0:n-1)

dp[i][j]=dp[i+1][j-1] + 2 if(str[i]==str[j]) 

dp[i][j]=max(dp[i+1][j],dp[i][j-1])  if (str[i]!=str[j])

class Solution {
    public int longestPalindromeSubseq(String s) {
        if(s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        int[][] dp = new int[n][n];
        int maxlen = 0;
        for(int i = 0; i < n; i++) {
            dp[i][i] = 1;
            maxlen = 1;
        }
        
        char[] ss = s.toCharArray();
        for(int len = 2; len <= n; len++) {
            for(int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;
                if(ss[i] == ss[j]) {
                    dp[i][j] = dp[i + 1][j - 1] + 2;
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
                }
                maxlen = Math.max(maxlen, dp[i][j]);
            }
        }
        return maxlen;
    }
}

Longest Palindromic Substring

dp[i][j] 表示的物理意义是:string s里面i到j之间的string是否是palindrome. 那么很自然的会推导出递推关系:

if s(i) != s(j) 直接 dp[i][j] = false;

if s(i) == s(j)  : 

      if( j-i<=2) dp[i][j] = true; // aba, 这个是容易犯错的点。 j-i = 2的情况一定要考虑进去;

      else dp[i][j] = dp[i+1][j-1]  代表i,j指针向中间移动;

因为计算dp[i][j] 需要用到下一层的dp[i+1][j-1],所以for循环的时候,要从下开始算,也就是从后面开始计算;

class Solution {
    public String longestPalindrome(String s) {
        if(s == null || s.length() == 0) {
            return s;
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        String maxstr = "";
        int maxlen = 1;
        for(int i = 0; i < n; i++) {
            dp[i][i] = true;
            maxstr = s.substring(i, i + 1);
        }
        
        char[] ss = s.toCharArray();
        for(int len = 2; len <= n; len++) {
            for(int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;
                if(ss[i] != ss[j]) {
                    dp[i][j] = false;
                } else {
                    if(j - i == 1) {
                        dp[i][j] = true;
                    }
                    if(j - i >= 2 && dp[i + 1][j - 1]) {
                        dp[i][j] = true;
                    }
                    if(dp[i][j]) {
                        if(j - i + 1 > maxlen) {
                            maxlen = j - i + 1;
                            maxstr = s.substring(i, j + 1);
                        }
                    }
                }
            }
        }
        return maxstr;
    }
}

Palindromic Substrings 

思路:区间型动态规划 dp[i][j] = true if s[i] == s[j] and ( j - i <= 2 || dp[i+1][j - 1])

区间型,从小到大,计算,初值len = 1, len >= 2; 

class Solution {
    public int countSubstrings(String s) {
        if(s == null || s.length() == 0) {
            return 0;
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        int pcount = 0;
        for(int i = 0; i < n; i++) {
            dp[i][i] = true;
            pcount++;
        }
        
        char[] ss = s.toCharArray();
        for(int len = 2; len <= n; len++) {
            for(int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;
                if(ss[i] != ss[j]) {
                    dp[i][j] = false;
                } else {
                    if(j - i == 1) {
                        dp[i][j] = true;
                        pcount++;
                    }
                    if(j - i >= 2 && dp[i + 1][j - 1]) {
                        dp[i][j] = true;
                        pcount++;
                    }
                }
            }
        }
        return pcount;
    }
}

Burst Balloons 思路:f[i][j]代表:i个气球和j个气球不能被扎破的情况下,中间扎破能够得到的最大值。
记住首尾先要加入一个1,然后区间型动态规划,一定是先计算小区间然后计算大区间,所以for循环用len来写,然后枚举起点,最后得到整个区间的最大值;

class Solution {
    public int maxCoins(int[] nums) {
        if(nums == null || nums.length == 0) {
            return 0;
        }
        int n = nums.length;
        int[] A = new int[n + 2];
        // 最左边和最右边放值1;
        A[0] = 1; A[A.length - 1] = 1;
        n += 2;
        for(int i = 1; i < n - 1; i++) {
            A[i] = nums[i - 1];
        }
        
        int[][] dp = new int[n][n];
        //最短的balloon之间是不能扎破的,所以为0;
        for(int i = 0; i < n - 1; i++) {
            dp[i][i + 1] = 0;
        }
        
        // [1] A[0]....A[n - 2] [1]
        // 枚举length,区间型动态规划,都是从length从小到大计算的;
        for(int len = 2; len <= n; len++) {
            for(int i = 0; i + len - 1 < n; i++) {
                int j = i + len - 1;
                for(int k = i + 1; k < j; k++) {
                    dp[i][j] = Math.max(dp[i][j], 
                                        dp[i][k] + dp[k][j] + A[i] * A[k] * A[j]);    
                }
            }
        }
        
        return dp[0][n - 1];
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值