为什么引用这首诗呢?因为就像动态规划所适应的问题一样,我们走上了不同的路,我们最终的人生
到达了不同的目的地,我们想要知道哪种最好,我们想要知道那弯曲的小路尽头我们能获得最大的成就,动态规划的神奇的地方就在于 解题过程中不用担心选择,我们只需在迈向下一步的过程中考虑有几个路口 走了这些路口我们会失去什么,会获得什么,会变成什么,动态规划会“替我们选择”。
(虽然实质也不是太“美丽”,通过暴力循环也是把路都走了遍,才知道每条路的酸甜苦辣。。)
(2)找怎么由之前的情况推理过来 注意推理过来的情况之间彼此的不同 小技巧:考虑最后 一步是怎么由前面过来的
(3)可能初值需要出口 列好初值(一维一般列f【0】 二维有时列边界dp【0】【i】
dp【i】【0】 其核心还是看下面的循环要用什么初值) 然后在一层或者二层循环中
(2)dp[n]=dp[n-1]+dp[n-2]//利用小技巧,我们站在最后的台阶上,由前面迈两步
(2)dp[n]=dp[n-1]*(n-1) 我们最后一封信装错了,有n-1个位置可以装错
其它也都装错有dp【n-1】种,在最后一封信装错到不同位置上的基础上必然是不同的装错
(1)dp[n]:以s【n】为结尾的最长递增长度//以...结尾这种巧妙设置状态方式记住,以后常用
(2)dp[n]=max{1,if(s[n]>=s[i]) dp[i]+1}//考虑最后一步,比如1,2,4,3,7,6
我们指向6了,6比3大,6也比4大,故都可以作为它们的递增序列结尾。
(2)dp[n]=max{1,if(s[n]>=s[i]) dp[i]+1}
dt[n]=个数(max{1,if(s[n]>=s[i]) dp[i]+1})
(1)dp[i][j]:s1前i个字符长度 s2前j个字符长度 的最长公共子序列长度
(2) dp[i][j]=dp[i-1][j-1]+1 s1[i]=s2[j]
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
有不同的钱 和不同的货物的价值 如何花最少的钱 获得最大的钱
(1) dp[i][j] 在不超过j(总钱)的情况下 前i件能达到的最大的价值
(2)dp[i][j]=max(dp[i-1][j],dp[i-1][j-money[i]]+value[i])
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
//对于dp[i][j]=max{dp[i-1][j-weight[i]]+value[i],dp[i-1][j]}
dp[i][j]=Integer.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
(1)dp[i][j] 字符串s1前i个字符 字符串s2前j个字符 替换最小的步骤
(2)IF(S1[i]==s2[j]) 假如两个字母相同 我们让他俩匹配
dp[i][j]=min{dp[i-1][j]+1,dp[i-1][j-1],dp[i][j-1]+1}
IF(S1[i]!=s2[j]) 假如两个字母不同 我们让s1【i】替换
dp[i][j]=min{dp[i-1][j-1]+1,dp[i-1][j]+1,dp[i][j-1]+1}
(3)public int minDistance(String word1, String word2) {
//dp[i][j]表示 字符串1 i索引前 与字符串2 j索引前 最少的操作数 (注意本题是对word1进行操作)
// if(s1[i]==s2[j])两个字母相等的话 可以相互匹配
// 也可以不相互匹配 如horse 和 seeh 若h与h相匹配则 会使操作数变得很大 (匹配或把s1[i]删除,
//dp[i][j]=min(dp[i-1][j-1],dp[i-1][j]+1,dp[i][j-1]+1)
//dp[i][j]=min(dp[i-1][j]+1,dp[i-1][j-1]+1,dp[i][j-1]+1)
int[][] dp=new int[n1+1][n2+1];
if(word1.charAt(i-1)==word2.charAt(j-1))
dp[i][j]=Integer.min(Integer.min(dp[i-1][j-1], dp[i-1][j]+1), dp[i][j-1]+1);
dp[i][j]=Integer.min(Integer.min(dp[i-1][j]+1, dp[i-1][j-1]+1), dp[i][j-1]+1);
dp[i][j]=max{dp[i][j-1],dp[i-1][j-1]+money[j]*money[j-1]*money[j+1]}
dp[i][j]=dp[i-1][j]+dp[i][j-1]
public int uniquePaths(int m, int n) {
//dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i][j-1](可能 左边 上边到达该点)
for(int i=0;i<n;i++) dp[0][i]=1;
for(int i=0;i<m;i++) dp[i][0]=1;
dp[i][j]=dp[i-1][j]+dp[i][j-1];
dp[i][j]=dp[i-1][j]+dp[i][j-1]
public int uniquePathsWithObstacles(int[][] map) {
//if(map[i-1][j]==0&&map[i][j-1]==0) 左边和上面都没有障碍物
//dp[i][j]=dp[i-1][j]+dp[i][j-1]
//else if(map[i-1][j]==1&&map[i][j-1]==0) 上面有障碍物 左边没有障碍物
//else if(map[i-1][j]==1&&map[i][j-1]==0) 左边有障碍物 上面有障碍物
//else if(map[i-1][j]==0&&map[i][j-1]==0) 左边没有障碍物 上面没有障碍物
int n=map[0].length;//横 dp[竖][横]
for(int i=0;i<m&&map[i][0]==0;i++)
for(int i=0;i<n&&map[0][i]==0;i++)
if(map[i-1][j]==0&&map[i][j-1]==0)
dp[i][j]=dp[i-1][j]+dp[i][j-1];
else if(map[i-1][j]==1&&map[i][j-1]==0)
else if(map[i-1][j]==0&&map[i][j-1]==1)
else if(map[i-1][j]==1&&map[i][j-1]==1)
到此时 例题已经结束了!!随博主一起去练5道把 都做出来就动态规划算作掌握了!!
(leetcode 选标签动态规划的题 选5道 自己独立思考哦 不会的话去看下题解)
(1)f[x]表示以序列x结尾的摆动序列最长长度(这种状态的设置借鉴了最长递增子序列)
(2)f[i]=max{ numl[1]表示下个数要增 numl【-1】表示下个数要减
//if(numl【j】==1&&num[i]>numl[j]) f[j]+1
//else if(numl【j】==-1&&num[i]<numl[j]) f[j]+1
//else if(numl[j]=0) f[j]+1 } 记得更新numl
public int wiggleMaxLength(int[] nums) {
//numl[]=1表示下一个数该增减 -1表示下一个数该减少
//if(numl【j】==1&&num[i]>numl[j]) f[j]+1
//else if(numl【j】==-1&&num[i]<numl[j]) f[j]+1
//else if(numl[j]=0) f[j]+1 记得更新numl
if(numl[j]==0&&nums[i]!=nums[j])
else if(numl[j]==1&&nums[i]>nums[j])
else if(numl[j]==-1&&nums[i]<nums[j])
(3) public boolean isSubsequence(String s, String t) {
for(int i=0;i<=m;i++) dp[i][0]=0;
for(int i=0;i<=n;i++) dp[0][i]=1;
if(s.charAt(i-1)==t.charAt(j-1))
有4种 (顺序不一样 但数字一样算一种) 1111 112 22 13
(1)dp[i][j] 表示用序列 i前的包括序列i的数字组成j有多少种方式(nums序列假设从1开始)
(2)dp[i][j]=dp[i-1][j-k*nums[i](剩余的数满足不了nums[i])]+...+dp[i-1][j-nums[i]]+dp[i][j]
(3)public static int combinationSum4(int[] nums, int target) {
//dp[i][j] 表示用序列 i前的包括序列i的数字组成j有多少种方式(nums序列假设从1开始)
//dp[i][j]=dp[i-1][j-k*nums[i](剩余的数满足不了nums[i])]+...+dp[i-1][j-nums[i]]+dp[i][j]
int[][] dp=new int[n+1][target+1];