[力扣] 动态规划(DP)问题分类汇总(二)

3.区间DP

3.1 回文序列

回文区间DP模板:

for (int i = 0; i < n; i ++) {
     
            dp[i][i] = true;
            res ++;
        }
        for (int i = n - 1; i >= 0; i --) {
     
            for (int j = i + 1; j < n; j ++) {
     
                // 判断s[i] == s[j],dp[i][j]是由dp[i + 1][j - 1]
                // 转移过来的
            }
        }
题目一:回文子串(647. 回文子串)

题解:对于字符串的DP,一般要用二维数组求解。引入两个指针dp[i][j],这个状态是字符串区间dp[i + 1][j - 1]转移而来的,结果是有s[i] == s[j]是否成立来确定。
代码如下:

class Solution {
     
    public int countSubstrings(String s) {
     
        if (null == s || 0 == s.length()) {
     
            return 0;
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        // 统计数量
        int res = 0;
        for (int i = 0; i < n; i ++) {
     
            dp[i][i] = true;
            res ++;
        }
        for (int i = n - 1; i >= 0; i --) {
     
            for (int j = i + 1; j < n; j ++) {
     
                // j - i == 1指相邻两个字符相等就直接判为true
                if (s.charAt(i) == s.charAt(j) && ((j - i == 1) || (dp[i + 1][j - 1]))) {
     
                    dp[i][j] = true;
                    res ++;
                }
            }
        }
        return res;
    }
}
题目二:最长回文子串(516. 最长回文子序列)

题解:创建boolean的dp二维数组,判断dp[i][j]是否为回文字符串。并记录最长长度和起始位置。

class Solution {
     
    public String longestPalindrome(String s) {
     
        if (null == s || 0 == s.length()) {
     
            return "";
        }
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        for (int i = 0; i < n ; i ++) {
     
            dp[i][i] = true;
        }
        int len = 0, maxLen = 1, index = 0;
        for (int i = n - 1; i >= 0; i --) {
     
            for (int j = i + 1; j < n ; j ++) {
     
                if(s.charAt(i) == s.charAt(j) && ((j - i == 1) || dp[i + 1][j - 1])) {
     
                    dp[i][j] = true;
                    len = j - i + 1;
                }
                // 保存最长回文长度和起始位置
                if (dp[i][j] && len > maxLen) {
     
                    maxLen = len;
                    index = i;
                }
            }
        }
        return s.substring(index, index + maxLen);
    }
}

4.博弈型DP

4.1 Nim游戏

题目一:292. Nim 游戏(292. Nim 游戏)

题解:dpp[i]表示石头数量为i时自己的输赢情况。dp[i]的结果要看dp[i - 1],dp[i - 2],dp[i - 3]中有false的即自己这次可以赢。否则就是输了。状态转移方程:
dp[i] = !dp[i - 1] || !dp[i - 2] || !dp[i - 3];
代码如下:

class Solution {
     
    public boolean canWinNim(int n) {
     
    	// 第一种方法
        // if (1 == n || 2 == n || 3 == n) {
     
        //     return true;
        // }
        // boolean[] dp = new boolean[n + 1];
        // dp[1] = true;
        // dp[2] = true;
        // dp[3] = true;
        // for (int i = 4; i <= n; i ++) {
     
        //     dp[i] = !dp[i - 1] || !dp[i - 2] || !dp[i - 3];
        // }
        // return dp[n];

		// 第二种方法
        // if (1 == n || 2 == n || 3 == n) {
     
        //     return true;
        // }
        // if (n % 4 != 0) {
     
        //     return true;
        // }
        // boolean dp_1 = true, dp_2 = true, dp_3 = true, dp = false;
        // for (int i = 4; i <= n; i ++) {
     
        //     dp = !dp_1 || !dp_2 || !dp_3;
        //     dp_1 = dp_2;
        //     dp_2 = dp_3;
        //     dp_3 = dp;
        // }
        // return dp;
        // 第三种方法:数学规律
        return n % 4 != 0;
    }
}

你可能感兴趣的:(leetCode)