常见的动态规划问题

140 阅读2分钟

1 爬楼梯

题目:

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

解题思路:

这是一道最简单的动态规划的题目,我们可以这么假设,当n>2时,我们可以到达楼顶的方法数为f(n)=f(n-1)+f(n-2)。

代码实现

class Solution {
    public int climbStairs(int n) {
        if (n <= 2) {
            return n;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;

        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

2 使用最小花费爬楼梯

题目

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

解题思路

假设我们设定f(n)表示到达第n层所需的最小花费,从题目中我们可以推算出f(n)=min(f(n1)+cost[n1],f(n2)+cost[n2])f(n)=min(f(n-1)+cost[n-1],f(n-2)+cost[n-2]);由于可以从下标为 0 或下标为 1 的台阶开始爬楼梯,所以我们可以推断出f(0)=0;f(1)=0;

代码实现

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        // 爬到顶层的最下花费
        int[] dp = new int[cost.length + 1];
        dp[0] = 0;
        dp[1] = 0;
        for (int i = 2; i < cost.length + 1; i++) {
            dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
        }
        return dp[cost.length];
    }
}

3 整数拆分

题目

给定一个正整数 n ,将其拆分为 k 个正整数的和( k >= 2 ),并使这些整数的乘积最大化。返回你可以获得的最大乘积。

解题思路

假设我们设定f(n)表示为将正整数i拆分成至少两个正整数的和之后,这些正整数的最大乘积。

所以当i>=2时,假设对正整数i拆分出的第一个正整数是j(1<=j<i),则有以下两种方案:

  1. 将i拆分成j和i−j的和,且i−j不再拆分成多个正整数,此时的乘积是 j×(i−j);

  2. 将i拆分成j和i−j的和,且i−j继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。

代码实现

class Solution {
    public int integerBreak(int n) {
        // 当n=i时,可以获得的最大乘积
        int[] dp = new int[n + 1];
        for (int i = 2; i <= n; i++) {
            int curMax = 0;
            for (int j = 1; j < i; j++) {
                curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j]));
            }
            dp[i] = curMax;
        }
        return dp[n];
    }
}