参考文章
https://blog.csdn.net/u013309870/article/details/75193592
https://blog.csdn.net/baidu_28312631/article/details/47418773
动态规划
凡是可以大事化小的都可以用动态规划
一般解题步骤:找出最优子结构,找到状态转移方程,找到边界值
动态规划和贪心算法的区别
https://blog.csdn.net/weixin_39332529/article/details/89440114
最大的区别:贪心是通过局部最优解推导全局最优解
dp是通过所有的最优解推导全局最优解
所以贪心算法推到的全局最优解未必正确
dp常见题目
第一道题目展示dp的优点,将阶时间复杂度
import java.util.HashMap;
import java.util.Map;
/**
* You are climbing a stair case. It takes n steps to reach to the top.
*
* Each time you can either climb 1 or 2 steps. In how many distinct ways can
* you climb to the top?
*
* Note: Given n will be a positive integer.
*
* Example 1:
*
* Input: 2 Output: 2 Explanation: There are two ways to climb to the top. 1. 1
* step + 1 step 2. 2 steps Example 2:
*
* Input: 3 Output: 3 Explanation: There are three ways to climb to the top. 1.
* 1 step + 1 step + 1 step 2. 1 step + 2 steps 3. 2 steps + 1 step
*
*/
public class Lc70 {
/*
* 递归: fn=fn-1+fn-2; f1=1 f2=2
*/
public static int climbStairs(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return climbStairs(n - 1) + climbStairs(n - 2);
}
/*
* 递归优化 备忘录
*/
public static int climbStairs1(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
Map map = new HashMap<>();
if (map.containsKey(n)) {
return map.get(n);
} else {
int value = climbStairs1(n - 1) + climbStairs1(n - 2);
map.put(n, value);
return value;
}
}
/**
* 动态规划
*
* 最优子结构:最后一步到顶点的步长? 状态转移方程: 若最后一步走一步,之前到最后一步为x种,若最后一步走俩步,则到最后一步有y中,那么到最后顶点为 x+y
* 边界:f1=1; f2=2;
*
* @param n
* @return
*/
public static int climbStairs2(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
int a = 1;// ’走台阶1
int b = 2;// ‘走台阶2
for (int i = 3; i <= n; i++) {
int temp = a + b;// 走当前台阶等于上一次加上上一次
a = b;
b = temp;
}
return b;
}
public static void main(String[] args) {
System.out.println(climbStairs(10));
System.out.println(climbStairs1(10));
System.out.println(climbStairs2(10));
}
}
之后的题目展示dp常见的类型
import java.util.Arrays;
/**
* Perfect Squares
*
*/
public class Lc279 {
/**
* dp 最优子结构:完全平方数个数等于 非完全平方数 + 1(完全平方数) 状态转移方程:dp[n] =
* min(dp[a-x*x]+1,dp(a+x*x)) 边界值 所有的平方值为1
*/
public static int numSquares(int n) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
for (int i = 0; i * i <= n; i++) {
dp[i * i] = 1;
}
for (int i = 0; i <= n; i++) {
for (int j = 0; i + j * j <= n; j++) {
dp[i + j * j] = Math.min(dp[i + j * j], dp[i] + 1);
}
}
return dp[n];
}
public static void main(String[] args) {
System.out.println(numSquares(12));
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 问题: Given a non-empty string s and a dictionary wordDict containing a list of
* non-empty words, determine if s can be segmented into a space-separated
* sequence of one or more dictionary words.
*
*/
public class Lc139 {
/**
* dp 最优子结构:若0到i截取的串可以匹配,若i到末尾也可以匹配则证明可以被串都匹配;
*
* 状态转移方程:dp[i] = true
*
* dp[j]= true dp[0] = true
*/
public static boolean wordBreak(String s, List wordDict) {
int len = s.length();
boolean[] dp = new boolean[len + 1];
dp[0] = true;
for (int i = 1; i <= len; i++) {
for (int j = i - 1; j >= 0 && !dp[i]; j--) {
String str = s.substring(j, i);
dp[i] = dp[j] && wordDict.contains(str);
}
}
return dp[len];
}
public static void main(String[] args) {
String s = "leetcode";
String s1 = "leet";
String s2 = "code";
List wordDict = new ArrayList();
wordDict.add(s1);
wordDict.add(s2);
System.out.println(wordBreak(s, wordDict));
}
}
这是dp找最大路径的模型
/**
* 数字三角形,求最大路径和
*
*/
public class LcMaxSum {
public static int maxSum(int[][] array) {
if (array == null) {
return 0;
}
int row = array.length;
int dp[] = array[row - 1];
for (int i = row - 2; i >= 0; i--) {
for (int j = 0; j < array[i].length; j++) {
dp[j] = Math.max(array[i][j] + dp[j], array[i][j] + dp[j + 1]);
}
}
return dp[0];
}
public static void main(String[] args) {
int[][] array = { { 1 }, { 2, 3 }, { 4, 5, 6 } };
System.out.println(maxSum(array));
}
}
/**
* You are a professional robber planning to rob houses along a street. Each
* house has a certain amount of money stashed, the only constraint stopping you
* from robbing each of them is that adjacent houses have security system
* connected and it will automatically contact the police if two adjacent houses
* were broken into on the same night.
*
* Given a list of non-negative integers representing the amount of money of
* each house, determine the maximum amount of money you can rob tonight without
* alerting the police.
*/
public class Lc198 {
/*
* 若dp[i]表示为当前最大值 则对于某个位置i ,存在取和不取,即dp[i-2]+num[i],dp[i-1]
* 则状态转移方程max(dp[i-2]+num[i],dp[i-1])
*/
public static int rob(int[] nums) {
if (nums.length == 0) {
return 0;
}
int dp[] = new int[nums.length];
if (nums.length >= 1) {
dp[0] = nums[0];
}
if (nums.length >= 2) {
dp[1] = Math.max(nums[0], nums[1]);
}
if (nums.length >= 3) {
for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
}
}
return dp[nums.length - 1];
}
public static void main(String[] args) {
int[] nums = { 2, 1, 1, 2 };
System.out.println(rob(nums));
}
}