leetcode之动态规划刷题总结2
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之动态规划刷题总结2相关的知识,希望对你有一定的参考价值。
leetcode之动态规划刷题总结2
1-跳跃游戏
题目链接:题目链接戳这里!!!
思想:dp[i]表示在第i个位置能否跳到最后,从后向前遍历,如果前一个位置的数字大于等于1,代表可以跳到下一个位置,否则前一个位置跳不到当前位置,再往前一个位置想跳到当前位置就必须能跳跃的距离大于等于2,依次类推。
AC代码如下:
class Solution
public boolean canJump(int[] nums)
int lens = nums.length ;
boolean [] dp = new boolean [lens] ;
int cnt = 1 ;
dp[lens-1]=true ;
for(int i=lens-1; i>=1; i--)
if(nums[i-1]>=cnt)
dp[i-1] = true ;
cnt = 1 ;
else
cnt ++ ;
return dp[0] ;
2-跳跃游戏II
题目链接:题目链接戳这里!!!
思路:这题用动态规划的效率并不是太高,dp[i]表示从位置0跳到位置i所需的最小次数,初始化dp[0]为0,后面分别遍历从1到lens-1位置,所需的最小跳跃次数。
AC代码如下:
class Solution
public int jump(int[] nums)
int lens = nums.length ;
int [] dp = new int [lens] ;
dp[0] = 0 ;
for(int i=1; i<lens; i++)
dp[i] = Integer.MAX_VALUE;
for(int j=0; j<i; j++)
if(nums[j]>=i-j)
dp[i] = Math.min(dp[i], dp[j] + 1) ;
return dp[lens-1] ;
3-最小路径和
题目链接:题目链接戳这里!!!
这题用grid数组做为dp数组初始化第一行和第一列,因为只能往下和往右走,所以第一行和第一列的最短路径是固定的,dp[i][j]是到达(i,j)所需的最短路径,然后递推表达式:dp[i][j] = dp[i][j-1]+dp[i-1][j],即到达其余所有的最短路径取决于左边和上方的最小值。
AC代码如下:
class Solution
public int minPathSum(int[][] grid)
int m = grid.length ;
int n = grid[0].length ;
for(int i=1; i<n; i++)
grid[0][i] += grid[0][i-1] ;
for(int i=1; i<m; i++)
grid[i][0] += grid[i-1][0] ;
for(int i=1; i<m; i++)
for(int j=1; j<n; j++)
grid[i][j] += Math.min(grid[i][j-1], grid[i-1][j]) ;
return grid[m-1][n-1] ;
4-不同路径
题目链接:题目链接戳这里!!!
思路:这题和上一题很像,dp[i][j]表示到达(i,j)有多少条路径,第一行和第一列的dp要初始化为1,因为所有点只有一种,其余的点的路径数量等于左边和上方点的路径总和。
AC代码如下:
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][j-1] + dp[i-1][j]) ;
return dp[m-1][n-1] ;
5-不同路径II
题目链接:题目链接戳这里!!!
思路:这题和上一题很像,不过难了一点,因为加了障碍物,dp[i][j]数组表示到达位置(i,j)有多少条路径,我们初始化第一行和第一列为1,一旦发现有障碍物,后面就不用初始化了,然后从第一行第一列开始每个位置等于左方和上方的可能路径之和,如果当前位置有障碍,直接跳过就可以。
class Solution
public int uniquePathsWithObstacles(int[][] obstacleGrid)
int m = obstacleGrid.length ;
int n = obstacleGrid[0].length ;
int [][] dp = new int [m][n] ;
for(int j=0; j<n; j++)
if(obstacleGrid[0][j]==1)
break ;
else
dp[0][j] = 1 ;
for(int i=0; i<m; i++)
if(obstacleGrid[i][0] == 1)
break ;
else
dp[i][0] = 1 ;
for(int i=1; i<m; i++)
for(int j=1; j<n; j++)
if(obstacleGrid[i][j]==1)
continue ;
else
dp[i][j] += dp[i][j-1] + dp[i-1][j] ;
return dp[m-1][n-1] ;
6-三角形最小路径和
题目链接:题目链接戳这里!!!
思路:自底向上,把两个值中小的那个依次加到上层,依次迭代到最顶端就可以了。
AC代码如下:
class Solution
public int minimumTotal(List<List<Integer>> triangle)
int row = triangle.size() ;
int col = triangle.size() ;
int [][] dp = new int [row][col] ;
for(int i=0; i<triangle.size(); i++)
for(int j=0; j<triangle.get(i).size(); j++)
dp[i][j] = triangle.get(i).get(j) ;
for(int i=row-1; i>=0; i--)
for(int j=0; j<=i; j++)
if(i-1>=0 && j+1<=i)
dp[i-1][j] += Math.min(dp[i][j],dp[i][j+1]) ;
return dp[0][0] ;
7-买卖股票的最佳时机
题目链接:题目链接戳这里!!!
思路:这题不难,不过容易容易超时,不支持O(n^2)的时间复杂度,这题的思路是记录之前购买的最小值,并且计算当前卖出的最大值,一轮遍历的最大值就是卖股票盈利最多的。
AC代码如下:
class Solution
public int maxProfit(int[] prices)
int n = prices.length ;
int min = prices[0] ;
int max = 0 ;
for(int i=1; i<n; i++)
max = Math.max(max, prices[i]-min) ; //记录当前天卖出去的最大值
min = Math.min(min, prices[i]) ;//记录之前所有天买入的最小值
return max ;
8-买股票的最佳时机II
题目链接:题目链接戳这里!!!
这题比较好想的是贪心策略,只要当前天股票价格比前一天股票价格高,就将股票卖出,就是获利最大的。
AC代码如下:
class Solution
public int maxProfit(int[] prices)
int max = 0 ;
for(int i=1; i<prices.length; i++)
if(prices[i]>prices[i-1])
max += (prices[i]-prices[i-1]) ;
return max ;
当然这题主要还是考的动态规划
思路:第i天就两种状态,持有股票或者不持有股票
若持有股票,则又分为两种情况:1-前一天就持有,2-今天买入
若不持有股票,也分为两种情况:1-前一天不持有,2-今天卖出
我们最后找到最后依次不持有,就是我们的答案了
dp[i][1]:表示第i天持有
dp[i][0]:表示第i天不持有
AC代码如下:
class Solution
public int maxProfit(int[] prices)
int n = prices.length ;
int [][] dp = new int [n][2] ;
dp[0][0] = 0;
dp[0][1] = -prices[0] ;
for(int i=1; i<n; i++)
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]) ;
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]) ;
return dp[n-1][0] ;
9-买股票的最佳时机III
题目链接:题目链接戳这里!!!
思路1:每次记录四个变量即可
firstBuy:第一次买可以获得的最大利润
firstSell:第一次卖出可以获得的最大利润
secondBuy:第二次买入可以获得的最大利润
secondSell:第二次卖出可以获得的最大利润
AC代码如下:
class Solution
public int maxProfit(int[] prices)
int firstBuy = Integer.MIN_VALUE ; //第一次买入可获得的最大利润
int secondBuy = Integer.MIN_VALUE ;//第二层买入可获得的最大利润
int firstSell = 0, secondSell = 0 ; //第一次和第二次卖出可获得的最大利润
for(int i=0; i<prices.length; i++)
firstBuy = Math.max(firstBuy, -prices[i]) ;
firstSell = Math.max(firstSell, firstBuy+prices[i]) ;
secondBuy = Math.max(secondBuy, firstSell-prices[i]) ;
secondSell = Math.max(secondSell, secondBuy+prices[i]) ;
return secondSell ;
当然上面的方式比较好理解,但是不是标准话的动态规划表示形式,把四个变量换成一维数组就可以。
AC代码如下:
class Solution
public int maxProfit(int[] prices)
int [] dp = new int [4] ;
dp[0] = -prices[0] ; //第一次买入可获得的最大利润
dp[2] = -prices[0];//第二次买入可获得的最大利润
for(int i=0; i<prices.length; i++)
dp[0] = Math.max(dp[0], -prices[i]) ;
dp[1] = Math.max(dp[1], dp[0]+prices[i]) ;
dp[2] = Math.max(dp[2], dp[1]-prices[i]) ;
dp[3] = Math.max(dp[3], dp[2]+prices[i]) ;
return dp[3] ;
10-最大正方形
题目链接:题目链接戳这里!!!
思路:dp[i][j]表示以第i行j列为右下角能构成侧最大正方形边长,每次当矩阵中的值为1时,可以得到的递推表达式如下:
dp[i][j] = Math.min(Math.min(dp[i-1][j-1], dp[i-1][j]), dp[i][j-1]) + 1 ;
然后依次比较所有dp[i][j],找到最大值就可以。
max = Math.max(max, dp[i][j]) ;
class Solution
public int maximalSquare(char[][] matrix)
//dp[i][j]表示以第i行第j列为右下角能构成的最大正方形边长
int m = matrix.length ;
int n = matrix[0].length ;
int max = 0 ;
int [][] dp = new int [m+1][n+1] ;
for(int i=1; ileetcode之动态规划刷题总结3