基本思想:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,再构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
使用条件:可分为多个相关子问题,子问题的解被重复使用。
基本步骤:
根据动态规划的题目,我分成了以下的做法:
这是非常经典的斐波那契数列类型的动态规划题。使用一个数组dp来表示前n个房屋中能偷窃的最高金额。因为不能连续偷两家,也就是说在选择第 i-1 家和第 i-2 家与第 i 家相比,选更大的那个。
class Solution {
public int rob(int[] nums) {
int n = nums.length;
if(n<=1) return nums[0];
int[] dp = new int[n];
dp[0] = nums[0];
dp[1] = Math.max(dp[0], nums[1]);
for(int i = 2; i<n; i++){
dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]);
}
return dp[n-1];
}
}
给出一个字母字符串,如果相邻两个字母相同或者在字母表中相邻,则标记这两个字母,并把这两个字母的分数加到你获得的分数中,‘a’等于1,‘b’等于2,以此类推,要求被标记过的不能再使用。求最大的分数。
这道题是一个很典型的动态规划题,用一个数组dp来记录最大的分数,dp[i]表示区间[0:i]内的最大分数。由于题目要求标记过的字母不能再使用,那么当i-2, i-1, i三个下标内的字母都满足标记的条件的话,就只能选择i-2, i-1或者i-1, i这两种组合中会得分最高的一种。
package Test;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int[] dp = new int[s.length()];
dp[0] = 0;
dp[1] = getSum(s.charAt(0), s.charAt(1));
for (int i = 2; i < s.length(); i++) {
dp[i] = Math.max(dp[i-1], dp[i-2]+getSum(s.charAt(i), s.charAt(i-1)));
}
System.out.println(dp[s.length()-1]);
}
public static int getSum(char a, char b) {
int x = a - 'a' + 1;
int y = b - 'a' + 1;
if (Math.abs(x - y) <= 1) {
return x + y;
}
return 0;
}
}
参考:https://leetcode-cn.com/problems/longest-common-subsequence/solution/zui-chang-gong-gong-zi-xu-lie-by-leetcod-y7u0/
动态规划最关键的就是找到状态转移方程。在本题目中,我们的目的是找到机器人到星的路径数量。我们用子问题求解原问题的思路上去想。
由于机器人只能向右或者向下移动,那么我们很容易就能发现,机器人到达终点左边和上面的格子所需要的路径数,就是子问题的解。通过将这两个路径数相加,我们就能得到这个问题的解。这里我们就通过了星星前一步的子问题求解了原问题。
建立状态方程:f(i, j) = f(i-1, j) + f(i, j-1)
解题如下,此时时间复杂度O(mn),空间复杂度O(mn)
class Solution {
public int uniquePaths(int m, int n) {
int[][] nums = new int[m][n];
for(int i = 0; i<m; i++){
nums[i][0] = 1;
}
for(int i = 0; i<n; i++){
nums[0][i] = 1;
}
for(int i = 1; i<m; i++){
for(int j = 1; j<n; j++){
nums[i][j] = nums[i-1][j]+nums[i][j-1];
}
}
return nums[m-1][n-1];
}
}
优化:由于只需要前一条网格的路径数,所以存放子问题解的空间可以优化。下面代码空间复杂度O(n)。
class Solution {
public int uniquePaths(int m, int n) {
int[] pre = new int[n];
int[] cur = new int[n];
Arrays.fill(pre, 1);
Arrays.fill(cur,1);
for (int i = 1; i < m;i++){
for (int j = 1; j < n; j++){
cur[j] = cur[j-1] + pre[j];
}
pre = cur.clone();
}
return pre[n-1];
}
}
进一步优化:
class Solution {
public int uniquePaths(int m, int n) {
int[] cur = new int[n];
Arrays.fill(cur,1);
for (int i = 1; i < m;i++){
for (int j =