动态规划相关题目详解

一、LeetCode746:使用最小花费爬楼梯

数组的每个索引做为一个阶梯,第i个阶梯对应着一个非负数的体力花费值cost[i](索引从0开始)

每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯

您需要找到达到楼层顶部的最低花费。在开始时,你可以选择从索引为0或1的元素作为初始阶梯

示例1:

输入: cost = [10, 15, 20]
输出: 15
解释: 最低花费是从cost[1]开始,然后走两步即可到阶梯顶,一共花费15

示例2:

输入: cost = [1, 100, 1, 1, 1, 100, 1, 1, 100, 1]
输出: 6
解释: 最低花费方式是从cost[0]开始,逐个经过那些1,跳过cost[3],一共花费6

题解:

    public int minCostClimbingStairs(int[] cost) {
        int[] dp = new int[cost.length];
        dp[0] = cost[0];
        dp[1] = cost[1];
        for (int i = 2; i < dp.length; ++i) {
            dp[i] = Math.min(dp[i - 2], dp[i - 1]) + cost[i];
        }
        return Math.min(dp[dp.length - 1], dp[dp.length - 2]);
    }

二、LeetCode72:编辑距离

给定两个单词word1和word2,计算出将word1转换成word2所使用的最少操作数

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

示例1:

输入: word1 = "horse", word2 = "ros"
输出: 3

解释: 
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

示例2:

输入: word1 = "intention", word2 = "execution"
输出: 5

解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

解析:

dp[i][j]代表word1到i位置转换成word2到j位置需要最少步数

所以

当 word1[i] == word2[j],dp[i][j] = dp[i-1][j-1];

当 word1[i] != word2[j],dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1

其中,dp[i-1][j-1]表示替换操作,dp[i-1][j]表示删除操作,dp[i][j-1]表示插入操作

针对第一行,第一列要单独考虑,下图所示:

在这里插入图片描述

第一行,是word1为空变成word2最少步数,就是插入操作

第一列,是word2为空,需要的最少步数,就是删除操作

转自:https://leetcode-cn.com/problems/edit-distance/solution/zi-di-xiang-shang-he-zi-ding-xiang-xia-by-powcai-3/

题解:

    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 1; i < dp.length; ++i)
            dp[i][0] = i;
        for (int j = 1; j < dp[0].length; ++j)
            dp[0][j] = j;
        for (int i = 1; i < dp.length; ++i) {
            for (int j = 1; j < dp[0].length; ++j) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1))
                    dp[i][j] = dp[i - 1][j - 1];
                else
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i - 1][j]), dp[i][j - 1]) + 1;
            }
        }
        return dp[word1.length()][word2.length()];
    }

三、LeetCode300:最长上升子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4 
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4

题解:

    public int lengthOfLIS(int[] nums) {
        int length = nums.length;
        if (length == 0) return 0;
        int[] dp = new int[length];
        int result = 0;
        Arrays.fill(dp, 1);
        for (int i = 0; i < length; ++i) {
            for (int j = 0; j < i; ++j) {
                if (nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
            }
            result = Math.max(result, dp[i]);
        }
        return result;
    }

四、LeetCode91:解码方法

一条包含字母A-Z的消息通过以下方式进行了编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26

给定一个只包含数字的非空字符串,请计算解码方法的总数

示例1:

输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)

示例2:

输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 

解析:

在这里插入图片描述

转自:https://leetcode-cn.com/problems/decode-ways/solution/c-wo-ren-wei-hen-jian-dan-zhi-guan-de-jie-fa-by-pr/

题解:

    public int numDecodings(String s) {
        char[] chars = s.toCharArray();
        if (chars[0] == '0') return 0;
        int[] dp = new int[s.length()];
        dp[0] = 1;
        for (int i = 1; i < dp.length; ++i) {
            if (chars[i] == '0') {
                if (chars[i - 1] == '1' || chars[i - 1] == '2') dp[i] = (i >= 2 ? dp[i - 2] : 1);
                else return 0;
            } else if (chars[i - 1] == '1' || (chars[i - 1] == '2' && chars[i] >= '1' && chars[i] <= '6')) {
                dp[i] = dp[i - 1] + (i >= 2 ? dp[i - 2] : 1);
            } else {
                dp[i] = dp[i - 1];
            }
        }
        return dp[s.length() - 1];
    }

五、LeetCode32:最长有效括号

给定一个只包含()的字符串,找出最长的包含有效括号的子串的长度

示例1:

输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"

示例2:

输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

解析:

dp[i]表示以下标为i的字符结尾的最长有效子字符串的长度

  • s[i]=')'s[i-1]='(',也就是字符串如...() d p [ i ] = d p [ i 2 ] + 2 dp[i]=dp[i−2]+2

  • s[i]=')'s[i-1]=')',也就是字符串如...)),如果s[i-dp[i-1]-1]='(',那么 d p [ i ] = d p [ i 1 ] + d p [ i d p [ i 1 ] 2 ] + 2 dp[i]=dp[i-1]+dp[i−dp[i-1]-2]+2 , 表示当前位置的最长有效括号长度等于上一位有效括号的长度加上自身匹配的上一位的有效括号的长度加上2

题解:

    public int longestValidParentheses(String s) {
        int result = 0;
        int[] dp = new int[s.length()];
        for (int i = 1; i < s.length(); ++i) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                    dp[i] = (i - 2 >= 0 ? dp[i - 2] : 0) + 2;
                } else if (i - dp[i - 1] - 1 >= 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    dp[i] = dp[i - 1] + (i - dp[i - 1] - 2 >= 0 ? dp[i - dp[i - 1] - 2] : 0) + 2;
                }
            }
            result = Math.max(result, dp[i]);
        }
        return result;
    }

六、LeetCode85:最大矩形

给定一个仅包含0和1的二维二进制矩阵,找出只包含1的最大矩形,并返回其面积

示例:

输入:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

解析:

https://leetcode-cn.com/problems/maximal-rectangle/solution/zui-da-ju-xing-by-leetcode/

题解:

    public int maximalRectangle(char[][] matrix) {
        if (matrix == null || matrix.length == 0) return 0;
        int maxArea = 0;
        int[][] dp = new int[matrix.length][matrix[0].length];
        for (int i = 0; i < matrix.length; ++i) {
            for (int j = 0; j < matrix[0].length; ++j) {
                if (matrix[i][j] == '1') {
                    dp[i][j] = (j == 0) ? 1 : dp[i][j - 1] + 1;
                    int width = dp[i][j];
                    for (int k = i; k >= 0; --k) {
                        width = Math.min(width, dp[k][j]);
                        maxArea= Math.max(maxArea, width * (i - k + 1));
                    }
                }
            }
        }
        return maxArea;
    }

七、LeetCode115:不同的子序列

给定一个字符串S和一个字符串T,计算在S的子序列中T出现的个数

一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,"ACE"是"ABCDE"的一个子序列,而"AEC"不是)

示例1:

输入: S = "rabbbit", T = "rabbit"
输出: 3
解释:
如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案
(上箭头符号 ^ 表示选取的字母)
rabbbit
^^^^ ^^
rabbbit
^^ ^^^^
rabbbit
^^^ ^^^

示例2:

输入: S = "babgbag", T = "bag"
输出: 5
解释:
如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案
(上箭头符号 ^ 表示选取的字母)
babgbag
^^ ^
babgbag
^^    ^
babgbag
^    ^^
babgbag
  ^  ^^
babgbag
    ^^^

解析:

dp[i][j]表示当字符串s走到j位置,字符串t走到i位置, 有多少次匹配

在这里插入图片描述

s[j]== t[i]时,dp[i][j] = dp[i-1][j-1] + dp[i][j-1] :有两种情况,匹配时最后一个字符为s[j](那么前j-1个字符只需要匹配T的前j-1个字符即可,即dp[i-1][j-1])或者不是最后一个字符(那么由s[j-1]前面出现过的t[i]作为最后一个字符了,即dp[i][j-1]),所以为两个之和

题解:

    public int numDistinct(String s, String t) {
        int[][] dp = new int[t.length() + 1][s.length() + 1];
        for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1;
        for (int i = 1; i < t.length() + 1; i++) {
            for (int j = 1; j < s.length() + 1; j++) {
                if (t.charAt(i - 1) == s.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
                else dp[i][j] = dp[i][j - 1];
            }
        }
        return dp[t.length()][s.length()];
    }
发布了177 篇原创文章 · 获赞 407 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_40378034/article/details/103444943
今日推荐