java|动态规划刷题攻略(二)

序列型动态规划 java|动态规划刷题攻略(二)
文章图片

265. 粉刷房子 II ---- 序列型动态规划
java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分一:确定状态
动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片

优化后代码:
public int minCost(int[][] A) { if(A.length == 0){ return 0; } int n = A.length; int k = A[0].length; int[][] f = new int[n + 1][k]; int min1,min2; int j1 = 0,j2 = 0; //j1,j2代表最小值和次小值的下标 for(int j = 0; j < k; j++){ f[0][j] = 0; } for(int i = 1; i <= n; i++){ //计算min1,min2(求最小值和次小值) min1 = min2 = Integer.MAX_VALUE; //min1 = f[i - 1][j1] //min2 = f[i - 1][j2] for(int j = 0; j < k; j++){ if(f[i - 1][j] < min1){ //比原来的最小值都小,则把原来的最小值放到次小值里 //然后再把现在的值赋给最小 min2 = min1; j2 = j1; min1 = f[i - 1][j]; j1 = j; }else{ //比最小值大,比次小值小 if(f[i - 1][j] < min2){ min2 = f[i - 1][j]; j2 = j; } } } for(int j = 0; j < k; j++){ if(j != j1){ f[i][j] = f[i - 1][j1] + A[i - 1][j]; }else{ //j == j1(正好是那个最小值) f[i][j] = f[i - 1][j2] + A[i - 1][j]; } } } int res = Integer.MAX_VALUE; for(int j = 0; j < k; j++){ res = Math.min(res,f[n][j]); } return res; }

动态规划常见优化 java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片

剑指 Offer II 089. 房屋偷盗 ----- 序列型动态规划??????
动态规划组成部分一:确定状态 java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片

动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

简化:
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分三:初始条件和边界情况 【java|动态规划刷题攻略(二)】java|动态规划刷题攻略(二)
文章图片

动态规划组成部分四:计算顺序 初始化f[0]
计算f[1],f[2],....,f[n]
答案是f[n]
时间复杂度O(N),空间复杂度O(1)
public int rob(int[] nums) { int n = nums.length; if(n == 0){ return 0; } int[] f = new int[n + 1]; f[0] = 0; f[1] = nums[0]; for(int i = 2; i <= n; i++){ f[i] = Math.max(f[i - 1],f[i - 2] + nums[i - 1]); } return f[n]; }

剑指 Offer II 090. 环形房屋偷盗 ---- 序列型动态规划
java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片
小结:
java|动态规划刷题攻略(二)
文章图片

买卖股票系列问题 121. 买卖股票的最佳时机
java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片

public int maxProfit(int[] prices) { int minPrice = Integer.MAX_VALUE; int maxProfit = 0; for(int i = 0; i < prices.length; i++){ if(prices[i] < minPrice){ minPrice = prices[i]; }else if(prices[i] - minPrice > maxProfit){ maxProfit = prices[i] - minPrice; } } return maxProfit; }

122. 买卖股票的最佳时机 II
java|动态规划刷题攻略(二)
文章图片

只看相邻两点!!!!
java|动态规划刷题攻略(二)
文章图片

public int maxProfit(int[] prices) { int res = 0; for(int i = 0; i < prices.length - 1; i++){ if(prices[i + 1] - prices[i] > 0){ res += prices[i + 1] - prices[i]; } } return res; }

123. 买卖股票的最佳时机 III
题目大意和I,II基本相似
只能最多两次买卖
所以需要记录已经买卖了多少次
动态规划组成部分一:确定状态 记录阶段
java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片
最后一步
java|动态规划刷题攻略(二)
文章图片
java|动态规划刷题攻略(二)
文章图片
思考:需要把今天的红利加上
java|动态规划刷题攻略(二)
文章图片

子问题
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

动态规划组成部分三:初始条件和边界情况 java|动态规划刷题攻略(二)
文章图片

动态规划组成部分四:计算顺序 java|动态规划刷题攻略(二)
文章图片

public int maxProfit(int[] prices) { int n = prices.length; if(n == 0){ return 0; } int[][] f = new int[n + 1][5 + 1]; //初始条件 //刚开始(前0天),处于阶段1,最大利润为0 f[0][1] = 0; f[0][2] = f[0][3] = f[0][4] = f[0][5] = Integer.MIN_VALUE; for(int i = 1; i <= n; i++){ //1,3,5 for(int j = 1; j <= 5; j += 2){ //max{f[i - 1][j],f[i - 1][j - 1] + Pi - 1 - Pi - 2} f[i][j] = f[i - 1][j]; if(j > 1 && i > 1 && f[i - 1][j - 1] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j - 1] + prices[i - 1] - prices[i - 2]); } } for(int j = 2; j <= 5; j += 2){ //max{f[i - 1][j] + Pi - 1 - Pi - 2,f[i - 1][j - 1],f[i - 1][j - 2] + Pi-1 - Pi-2} f[i][j] = f[i - 1][j - 1]; if(i > 1 && f[i - 1][j] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j] + prices[i - 1] - prices[i - 2]); } if(j > 2 && i > 1 && f[i - 1][j - 2] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j - 2] + prices[i - 1] - prices[i - 2]); } } } return Math.max(Math.max(f[n][1],f[n][3]),f[n][5]); }

188. 买卖股票的最佳时机 IV
java|动态规划刷题攻略(二)
文章图片

思考:为啥是 N / 2 ?
如果K > N / 2,并且买了超过一半的次数;此时,一定有几天是连着买卖的(即第一天买,第二天卖,第三天买,第四天卖,第五条买....); 此时可以看作第一天买,第N天买,中间的过程忽略不看,不管咋样买卖的,都可以等价的看作任意一次买卖
动态规划组成部分一:确定状态 java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片

动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

动态规划组成部分三:初始条件和边界情况 java|动态规划刷题攻略(二)
文章图片

动态规划组成部分四:计算顺序 java|动态规划刷题攻略(二)
文章图片

//注意大小写K的区别 public int maxProfit(int K, int[] prices) { int n = prices.length; if(n == 0){ return 0; } int i, j, k; //k > n / 2时,可以看做,任意多次的买卖股票II if(K > n / 2){ int result = 0; for(i = 0; i < n - 1; i++){ result += Math.max(prices[i + 1] - prices[i],0); } return result; } int[][] f = new int[n + 1][2 * K + 1 + 1]; //初始条件 //刚开始(前0天),处于阶段1,最大利润为0 f[0][1] = 0; for(k = 2; k <= 2 * K + 1; k++){ f[0][k] = Integer.MIN_VALUE; } for(i = 1; i <= n; i++){ //1,3,5 for(j = 1; j <= 2 * K + 1; j += 2){ //max{f[i - 1][j],f[i - 1][j - 1] + Pi - 1 - Pi - 2} f[i][j] = f[i - 1][j]; if(j > 1 && i > 1 && f[i - 1][j - 1] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j - 1] + prices[i - 1] - prices[i - 2]); } } for(j = 2; j <= 2 * K + 1; j += 2){ //max{f[i - 1][j] + Pi - 1 - Pi - 2,f[i - 1][j - 1],f[i - 1][j - 2] + Pi-1 - Pi-2} f[i][j] = f[i - 1][j - 1]; if(i > 1 && f[i - 1][j] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j] + prices[i - 1] - prices[i - 2]); } if(j > 2 && i > 1 && f[i - 1][j - 2] != Integer.MIN_VALUE){ f[i][j] = Math.max(f[i][j],f[i - 1][j - 2] + prices[i - 1] - prices[i - 2]); } } } int res = Integer.MIN_VALUE; for(i = 1; i <= 2 * K + 1; i += 2){ res = Math.max(res,f[n][i]); } return res; }

序列 + 状态型动态规划小结 java|动态规划刷题攻略(二)
文章图片

java|动态规划刷题攻略(二)
文章图片

最长序列型动态规划 java|动态规划刷题攻略(二)
文章图片

大部分序列型题目通常也是坐标型的,
java|动态规划刷题攻略(二)
文章图片

比如这道序列型的题目也可以用坐标型的方法去做(之前的)
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分一:确定状态 最后一步
java|动态规划刷题攻略(二)
文章图片

子问题
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

动态规划组成部分三:初始条件和边界情况 java|动态规划刷题攻略(二)
文章图片

动态规划组成部分四:计算顺序 java|动态规划刷题攻略(二)
文章图片

public int lengthOfLIS(int[] nums) { int n = nums.length; if(n == 0){ return 0; } int[] f = new int[n]; int res = 0; for(int j = 0; j < n; j++){ //case 1: f[j] = 1; //case 2: for(int i = 0; i < j; i++){ if(nums[i] < nums[j] && f[i] + 1 > f[j]){ f[j] = f[i] + 1; } } res = Math.max(res,f[j]); } return res; }

思考:如何做到nlog(n)[第七讲会讲]
354. 俄罗斯套娃信封问题
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分一:确定状态 java|动态规划刷题攻略(二)
文章图片

子问题
java|动态规划刷题攻略(二)
文章图片

动态规划组成部分二:转移方程java|动态规划刷题攻略(二)
文章图片

动态规划组成部分三:初始条件和边界情况 java|动态规划刷题攻略(二)
文章图片

动态规划组成部分四:计算顺序 f[0],f[1],...,f[N - 1]
时间复杂度O(N^2),空间复杂度O(N)
public int maxEnvelopes(int[][] envelopes) { if(envelopes.length == 0){ return 0; } Arrays.sort(envelopes,new Comparator(){ public int compare(int[] a,int[] b){ //长度相等,宽度任意排序 if(a[0] == b[0]){ return a[1] - b[1]; }else{ //长度从小到大 return a[0] - b[0]; } } }); int n = envelopes.length; int[] f = new int[n]; int res = 0; for(int i = 0; i < n; i++){ f[i] = 1; for(int j = 0; j < i; j++){ //信封 j 能被放进信封 i if(envelopes[j][0] < envelopes[i][0] && envelopes[j][1] < envelopes[i][1]){ f[i] = Math.max(f[i],f[j] + 1); } } res = Math.max(res,f[i]); } return res; }




    推荐阅读