今天的前几道题也很简单,重点是最后一题,卡了很久没想明白,看了大佬的思路后豁然开朗!
leetcode 63. 不同路径 II
思路
- 能发拆成小问题?可以呢,就是到坐标(i,j)的路径条数
- 后面问题只依赖前面问题的解?肯定,
- 同样用dp[i][j]来代表到(i,j)点的路径条数
- 这个题和之前那个基本一个思路,只不过注意障碍点的dp为0;
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
if (obstacleGrid[0][0] == 1) return 0;
for (int i =0;i<m;i++){
for (int j = 0;j<n;j++){
if (i==0 && j==0) {dp[i][j] = 1;continue;}
if ((i==0 || j==0)){
if (obstacleGrid[i][j] == 1) dp[i][j] = 0;
else {dp[i][j] = i==0 ?dp[i][j-1]:dp[i-1][j];}
continue;
}
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];
}
leetcode 64. 最小路径和
思路
- 能发拆成小问题?可以呢,就是到坐标(i,j)的最小路径和
- 后面问题只依赖前面问题的解?肯定,
- 同样用dp[i][j]来代表到(i,j)点的最小路径和
- 这个题和上一个题那个基本一个思路,只不过(i,j)点的dp值=min(dp[i-1][j],dp[i][j]) + grid[i][j];
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];
// 第一行和第一列,只有前面一点
// 其他,每点只有两个前一点,去两个的dp小值 + grid值就是了
for (int i =0;i<m;i++){
for (int j = 0;j<n;j++){
if (i==0 && j==0) {dp[i][j] = grid[0][0];continue;}
if (i==0 || j==0) {
dp[i][j] = grid[i][j];
dp[i][j] += i==0 ?dp[i][j-1]:dp[i-1][j];
continue;
}
dp[i][j] = grid[i][j] + Math.min(dp[i][j-1], dp[i-1][j]);
}
}
return dp[m-1][n-1];
}
leetcode 70. 爬楼梯
- 能发拆成小问题?可以呢,就是到第i层的跳跃方法总数
- 后面问题只依赖前面问题的解?肯定,
- 同样用dp[i]来代表到第i层的跳跃方法总数
- 由于一次只能跳一个或者两个,第i层的dp值=dp[i-1] + dp[i-2];
很标准的dp算法题
public int climbStairs(int n) {
if (n==1) return 1;
if (n==2) return 2;
int[]dp = new int[n];
dp[0] = 1;
dp[1] = 2;
for (int i = 2;i<n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n-1];
}
leetcode 45. 跳跃游戏 II
今天最难题,做这道题花了很长时间还没有ac,主要是没有很好的dp思路,直到看到一位大佬的题解,和另一位大佬的dp教学 一份给算法新人们的「动态规划」讲解
- 能发拆成小问题?可以呢,就是到第i点的最小跳跃次数
- 后面问题只依赖前面问题的解?肯定,
- dp确定:
- 定义: 用dp[i]来代表到第i点的最小跳跃次数
- 状态转移方程:dp[i]的值应该是第一个能跳到i的点的dp值+1
- 起始值:dp[0]=0,dp[1]=1
- 那么我们怎么判断第一个能跳到i的点呢?如果j点的下标 + j点能跳的距离 >= i的下标,就可以认为能跳到i点,那么我们就要找尽可能小的j点
public int jump1(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = 0;
int j = 0;
for (int i = 1; i < nums.length; i++) {
while(j + nums[j] < i){
j++;
}
dp[i] = dp[j] + 1;
}
return dp[nums.length - 1];
}