代码随想录打卡-动态规划

avatar
作者
猴君
阅读量:0

一、动态规划基础

1.1 动态规划:斐波那契数

class Solution {     public int fib(int n) {         if(n<=1){             return n;         }         int[] dp = new int[n+1];         //初始化         dp[0] = 0;         dp[1] = 1;         for(int i = 2;i<n+1;i++){             dp[i] = dp[i-1]+dp[i-2];         }         return dp[n];     } }

1.2 动态规划:爬楼梯

class Solution {     public int climbStairs(int n) {         if(n<3){             return n;         }         int[] dp = new int[n+1];         //初始化         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.3 动态规划:使用最小花费爬楼梯1

class Solution {     public int minCostClimbingStairs(int[] cost) {         int[] dp = new int[cost.length+1];         //从0、1开始都不用钱         for(int i = 2;i<cost.length+1;i++){             dp[i] = Math.min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);         }         return dp[cost.length];     } }

1.4 动态规划:不同路径

class Solution {     public int uniquePaths(int m, int n) {         int[][] dp = new int[m][n];         //初始化         for(int i = 0;i<m;i++){             dp[i][0] = 1;          }         for(int j = 0;j<n;j++){             dp[0][j] = 1;         }          for(int i = 1;i<m;i++){             for(int j = 1;j<n;j++){                 dp[i][j] = dp[i-1][j]+dp[i][j-1];             }         }         return dp[m-1][n-1];     } }

1.5 动态规划:不同路径还不够,要有障碍!

class Solution {     public int uniquePathsWithObstacles(int[][] obstacleGrid) {         int m = obstacleGrid.length;         int n = obstacleGrid[0].length;         int[][] dp = new int[m][n];         //初始化,为0:只有一条路,路上还有障碍         //初始化,为1:只有一条路,路上无障碍         for(int i = 0;i<m && obstacleGrid[i][0]==0;i++){             dp[i][0] = 1;         }         for(int j = 0;j<n && obstacleGrid[0][j]==0;j++){             dp[0][j] = 1;         }         for(int i = 1;i<m;i++){             for(int j = 1;j<n;j++){                 if(obstacleGrid[i][j]==1){                     //遇到障碍                     dp[i][j] = 0;                 }else{                     dp[i][j] = dp[i-1][j]+dp[i][j-1];                 }             }         }         return dp[m-1][n-1];     } }

1.6 动态规划:整数拆分,你要怎么拆?

class Solution {     public int integerBreak(int n) {         int[] dp = new int[n+1];         //初始化         dp[2] = 1;         for(int i = 3;i<n+1;i++){             //j往后加也是重复             for(int j = 1;j<=i;j++){                 dp[i] = Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));             }         }         return dp[n];     } }

1.7 动态规划:不同的二叉搜索树(opens new window)

class Solution {     public int numTrees(int n) {         int[] dp = new int[n+1];         //初始化         dp[0] = 1;         dp[1] = 1;         for(int i = 2;i<n+1;i++){             for(int j = 1;j<=i;j++){                 //j为头节点,左子树上总元素个数为j-1,总共i个元素,则右子树要减去左子树和头节点,为i-j                 dp[i] += dp[j-1]*dp[i-j];             }         }         return dp[n];     } }

二、背包问题系列

详见:代码随想录打卡-dp之背包问题-CSDN博客

三、打家劫舍系列

198.打家劫舍

213.打家劫舍II

337.打家劫舍III

class Solution {     public int rob(int[] nums) {         if(nums==null || nums.length==0){             return 0;         }         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 i = 2;i<nums.length;i++){             dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]);         }         return dp[nums.length-1];     } }

注意: Arrays.copyOfRange()方法会返回一个新的数组,其中包含原始数组 original 中从索引 fromto-1(不包含to)的元素

class Solution {     public int rob(int[] nums) {         if(nums==null || nums.length<1){             return 0;         }         if(nums.length==1){             return nums[0];         }         return Math.max(robAction(Arrays.copyOfRange(nums,0,nums.length-1)),robAction(Arrays.copyOfRange(nums,1,nums.length)));      }      private int robAction(int[] nums){         int pre = 0,cur = 0,tmp;         for(int i = 0;i<nums.length;i++){             tmp = cur;             cur = Math.max(cur,pre+nums[i]);             pre = tmp;         }         return cur;     } }

注意:本题dp数组就是一个长度为2的数组! 

/**  * Definition for a binary tree node.  * public class TreeNode {  *     int val;  *     TreeNode left;  *     TreeNode right;  *     TreeNode() {}  *     TreeNode(int val) { this.val = val; }  *     TreeNode(int val, TreeNode left, TreeNode right) {  *         this.val = val;  *         this.left = left;  *         this.right = right;  *     }  * }  */ class Solution {     public int rob(TreeNode root) {         //后序遍历         //dp数组是一个长度为2的数组         //0:不偷该节点 1:偷该节点         int[] dp = new int[2];         dp = robAction(root);         return Math.max(dp[0],dp[1]);     }     private int[] robAction(TreeNode root){         int[] res = new int[2];         if(root==null){             return res;         }         int[] left = robAction(root.left);         int[] right = robAction(root.right);         //不偷节点,左右子节点分别取最大的         res[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);         //偷节点,左右子节点都不能偷         res[1] = root.val+left[0]+right[0];         return res;     } }

四、股票系列  

详见:代码随想录打卡-股票问题-CSDN博客

五、子序列系列

5.1 最长递增子序列

300.最长递增子序列

注意:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度

           初始化:全部为1,只要有一个数字,长度就为1开始(这里利用到了Arrays.fill()方法)

class Solution {     public int lengthOfLIS(int[] nums) {         //dp[i]表示以nums[i]结尾的最长递增子序列         int[] dp = new int[nums.length];         Arrays.fill(dp,1);         int res = 1;          for(int i = 0;i<nums.length;i++){             for(int j = 0;j<i;j++){                 if(nums[j]<nums[i]){                     dp[i] = Math.max(dp[i],dp[j]+1);                 }                 res = Math.max(res,dp[i]);             }         }         return res;     } }

5.2 最长连续递增序列 

674. 最长连续递增序列

注意:与上题的区别在于,这题要求连续

class Solution {     public int findLengthOfLCIS(int[] nums) {         //动态规划         int[] dp = new int[nums.length];         Arrays.fill(dp,1);         int res = 1;         for(int i = 1;i<nums.length;i++){             if(nums[i]>nums[i-1]){                 dp[i] = dp[i-1]+1;             }             res = Math.max(res,dp[i]);         }         return res;     } }

5.3 最长重复子数组 

718.最长重复子数组

注意:这里要求是连续的,所以不相等时的dp[i][j]不需要考虑了

class Solution {     public int findLength(int[] nums1, int[] nums2) {         int[][] dp = new int[nums1.length+1][nums2.length+1];         int res = 0;         for(int i = 1;i<nums1.length+1;i++){             for(int j = 1;j<nums2.length+1;j++){                 if(nums1[i-1]==nums2[j-1]){                     dp[i][j] = dp[i-1][j-1]+1;                 }                 res = Math.max(res,dp[i][j]);             }         }         return res;     } }

 5.4 最长公共子序列

1143.最长公共子序列

注意:与上题区别是,本题不要求连续,故不相等的情况也要考虑

class Solution {     public int longestCommonSubsequence(String text1, String text2) {         //不要求连续         char[] ch1 = text1.toCharArray();         char[] ch2 = text2.toCharArray();         int[][] dp = new int[ch1.length+1][ch2.length+1];         int res = 0;         for(int i = 1;i<ch1.length+1;i++){             for(int j = 1;j<ch2.length+1;j++){                 if(ch1[i-1]==ch2[j-1]){                     dp[i][j] = dp[i-1][j-1]+1;                 }else{                     dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);                 }                 res = Math.max(res,dp[i][j]);             }         }         return res;     } }

5.5 不相交的线

1035.不相交的线

class Solution {     public int maxUncrossedLines(int[] nums1, int[] nums2) {         //问题转换:不连续、公共         int[][] dp = new int[nums1.length+1][nums2.length+1];         int res = 0;         for(int i = 1;i<nums1.length+1;i++){             for(int j = 1;j<nums2.length+1;j++){                 if(nums1[i-1]==nums2[j-1]){                     dp[i][j] = dp[i-1][j-1]+1;                 }else{                     dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);                 }                 res = Math.max(res,dp[i][j]);             }         }         return res;     } }

5.6 最大子数组和

53.最大子数组和

注意:连续。并且要明确dp[i]的概念,是包含了i为下标的数的,所以要么是nums[i]加上前面的和,要么就是单独nums[i],也就是以nums[i]为一个新的开头

class Solution {     public int maxSubArray(int[] nums) {         //连续         int[] dp = new int[nums.length];         dp[0] = nums[0];         int res = nums[0];         for(int i = 1;i<nums.length;i++){             //看是加上前面的大,还是以这个数为起点大             dp[i] = Math.max(dp[i-1]+nums[i],nums[i]);             res = Math.max(res,dp[i]);         }         return res;     } }

5.7 编辑距离问题 

详见:https://blog.csdn.net/supercool7/article/details/140353805?spm=1001.2014.3001.5502

5.8 回文子串

647.回文子串

注意:本题要求连续,故只要已经不是回文,后面再加也一定不是回文了

                注意遍历顺序需要根据推导顺序来

布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false

class Solution {     public int countSubstrings(String s) {         char[] ch = s.toCharArray();         boolean[][] dp = new boolean[ch.length][ch.length];         int res = 0;//记录回文字符数         //已默认初始化,dp为false         for(int i = ch.length-1;i>=0;i--){             for(int j = i;j<ch.length;j++){                 if(ch[i]==ch[j]){                     if(j-i<=1 || dp[i+1][j-1]){                         //由于本题要求是连续,所以若已经不是回文,直接为默认值false即可,不需要再推导,后面都是false                         res++;                         dp[i][j] = true;                     }                 }             }         }         return res;     } }

5.9 最长回文子序列

516.最长回文子序列

注意:与上题的区别是,本题不要求连续!

class Solution {     public int longestPalindromeSubseq(String s) {         char[] ch = s.toCharArray();         int[][] dp = new int[ch.length][ch.length];         for(int i = ch.length-1;i>=0;i--){             //初始化             dp[i][i] = 1;             for(int j = i+1;j<ch.length;j++){                 if(ch[i]==ch[j]){                     dp[i][j] = dp[i+1][j-1]+2;                 }else {                     dp[i][j] = Math.max(dp[i+1][j],dp[i][j-1]);                 }             }         }         return dp[0][ch.length-1];     } }

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!