- 将问题拆分成小问题,先解决最小的问题,然后再一步步的解决大问题
- 寻找大问题和小问题间的关系,通过小问题来求解大问题
- 动态规划的使用条件:
- 子问题是离散的,不存在相互依赖的关系
- 存在一定的约束条件,求最值
经典题目
爬楼梯问题
public class ClimbingStairs {
public int climbStairs(int n) {
if (n<=2) {
return n;
}
int dp[]=new int[n+1];
dp[0]=0;
dp[1]=1;
dp[2]=2;
for (int i=3;i<n+1;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
}
//子问题:求第1阶和第2阶……第n阶
//确认状态:dp[n]代表n阶台阶有多少种走法
//边界: dp[1]=1;dp[2]=2;
//状态转移方程:dp[i]=dp[i-1]+dp[i-2];
偷盗问题
//子问题:前n个房间的最优解
//确认状态: dp[n]为前n个房间的最优解
//边界: dp[1];dp[2];
//状态转移方程:Math.max(dp[i-1],dp[i-2]+num[n]);
public class HouseRobber {
public static void main(String[] args){
rob(new int[]{1,2,3,1});
}
public static int rob(int[] nums) {
if (nums.length==0) {
return 0;
}else if(nums.length==1){
return nums[0];
}
int[] dp=new int[nums.length];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for (int index=2;index<nums.length;index++){
dp[index]=Math.max(dp[index-1],dp[index-2]+nums[index]);
}
return dp[nums.length-1];
}
}
最大子连续串问题
//子问题:求前n个中,包含nums[n]!!! 的最大序列
//确认状态: dp[n]为 包含nums[n]!!的最大连续序列
//边界: dp[1];dp[2];
//状态转移方程:Math.max(nums[n],dp[n-1]+nums[n]);
public class MaximumSubarray {
public int maxSubArray(int[] nums) {
if (nums.length==0) {
return 0;
}
int[] dp=new int[nums.length];
dp[0]=nums[0];
int max=dp[0];
for (int i=1;i<nums.length;i++){
dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
max=Math.max(dp[i],max);
}
return max;
}
}
零钱问题
public class CoinChange {
public static void main(String[] args){
coinChange(new int[]{1,2,5},11);
}
public static int coinChange(int[] coins, int amount) {
if (amount==0) {
return 0;
}
Arrays.sort(coins);
int[] dp=new int[amount+1];
for (int i=0;i<amount+1;i++){
dp[i]=-1;
}
dp[0]=0;
for (int target=1;target<amount+1;target++){
for (int coin:coins){
if (target-coin>=0 && dp[target-coin]!=-1) {
if (dp[target]==-1) {
dp[target]=dp[target-coin]+1;
}else{
dp[target]=Math.min(dp[target],dp[target-coin]+1);
}
}
}
}
return dp[amount];
}
}