引用一下別的大佬寫的介紹還有知乎上的十問十答
搞清楚什么是動態規划,和什么時候用動態規划。
p.s.百度百科和算法數上那一大堆看完也沒什么意思,不如從實例入手。掌握分析遞推關系才是王道。
集合存儲狀態+狀態轉移方程
超級樓梯
共兩種爬樓方式——一次上一個台階&一次上兩個台階,問上到第n階台階的方法共多少種。
設狀態dp[i]為上i階台階的方法種數,dp[1]=1;dp[2]=1; 狀態轉移方程 dp[i]=dp[i-1]+dp[i-2];//上一階和兩階
有了該遞推式,我們就不用遞歸暴力解決了。(遞歸開銷是真的大
dp[i][j]為到單元格(i,j)的方法數,dp[0][]=1;dp[][0]=1; dp[i][j]=dp[i-1][j]+dp[i][j-1];//向下走和向右走
public int uniquePaths(int m, int n) { int[][] dp = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i == 0 || j == 0) dp[i][j] = 1; else { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } } return dp[m - 1][n - 1]; }
進階:不同路徑 II

public int uniquePathsWithObstacles(int[][] obstacleGrid) { int row=obstacleGrid.length; int col=obstacleGrid[0].length; int[][] dp=new int[row][col]; if(obstacleGrid[0][0]==1){ return 0; } for(int i=0;i<row;i++){ for(int j=0;j<col;j++){ if(obstacleGrid[i][j]==0){ if(i==0&&j==0){ dp[i][j]=1; }else if(i==0){ dp[i][j]=dp[i][j-1]; }else if(j==0){ dp[i][j]=dp[i-1][j]; }else{ dp[i][j]=dp[i-1][j]+dp[i][j-1]; } }else{ dp[i][j]=0; continue; } } } return dp[row-1][col-1]; }
上面幾個都是連續型問題,樓梯台階連續,走的格子連續。
0-1背包問題
背包的容量j因放入物品的重量w不同,變化非連續,但一般都有額外的空間(表)來存儲狀態信息。
遞歸遍歷解法:

int []w={15,17,20,12,9,14}; int []p={32,37,46,26,21,30}; public int solve(int i,int n,int j,int max){ if(i<n){ if(j>=w[i]){ return Math.max(solve(i+1,n,j-w[i],max+p[i]),solve (i+1,n,j,max)); }else{ return solve(i+1,n,j,max); } }else return max; }
dp[i][j]表示前i件物品恰放入一個容量為j的背包可獲得的最大價值 dp[i][j]=max{dp[i-1][j],dp[i-1][j-w[i]]+p[i]};
public int Packet(int c){ int []w={15,17,20,12,9,14}; int []p={32,37,46,26,21,30}; int packets=w.length; int [][]dp=new int[packets+1][c+1]; for(int i=0;i<=packets;i++) for(int j=0;j<=c;j++){ if(i==0||j==0) dp[i][j]=0; else if(j>=w[i-1]){ dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-w[i-1]]+p[i-1]); }else dp[i][j]=dp[i-1][j]; } return dp[packets][c]; }
與貪心算法的每步取”最優“不同,動態規划存儲狀態信息,並有針對於狀態變量的狀態轉移策略。
dp[i]表示截止到i的最大連續字串和,dp[0]=nums[0]; dp[i]=max{dp[i-1]+nums[i],nums[i]}
class Solution { public int maxSubArray(int[] nums){ int len=nums.length; int[] dp=new int[len]; for(int i=0;i<len;i++) if(i==0) dp[i]=nums[i]; else dp[i]=Math.max(dp[i-1]+nums[i], nums[i]); Arrays.sort(dp); return dp[len-1]; } }
大佬寫的經空間優化后的代碼:
public int maxSubArray(int[] nums) { int res = nums[0]; int sum = 0; for (int num : nums) { if (sum > 0) sum += num; else sum = num; res = Math.max(res, sum); } return res; }