新年好,今天就做了三道题,全ac了,这是要长脑子了?
leetcode 53. 最大子数组和
思路:
这题很简单,思路也很简单
- 能否拆为子问题?肯定可以,拆为数组前n个元素的最大和
- 后续子问题解只依赖前面的解?是的
- 既然是连续子数组的最大和,我们就要dp[i]代表前i个元素(包含第i个元素)最大和
- 如果dp[i-1] < 0,一定是nums[i]当前最大
- 如果dp[i-1] >= 0,一定是要加上的
基于上面思路,这道题就非常简单,也非常好写,其实不用dp可能更快些
public int maxSubArray(int[] nums) {
if (nums.length == 1) return nums[0];
int[]dp = new int[nums.length];
int max = Integer.MIN_VALUE;
for (int i = 0;i<nums.length;i++){
if (i == 0) dp[0] = nums[0];
if (i - 1 >= 0){
// 如果dp[i-1] < 0,一定是nums[i]当前最大
if (dp[i-1] < 0) dp[i] = nums[i];
// 如果dp[i-1] >= 0,一定是要加上的
if (dp[i-1] >=0) dp[i] = nums[i] + dp[i-1];
}
if (dp[i] > max) max = dp[i];
}
return max;
}
leetcod 55. 跳跃游戏
思路
- 能否拆为子问题?肯定可以,拆为数组前n个元素的能否到达
- 后续子问题解只依赖前面的解?是的
- 既然是连续子数组的最大和,我们就要dp[i]代表前i个元素(包含第i个元素)是否到达?
- 如果dp[i-1]<i,那说明包括i-1在内前面的任何点都不能到达i,此时就可以退出循环了,肯定到不了最后一个
- 本题难一点的思路就是,i下标的dp要取dp[i-1]和i+nums[i]的最大值,为什么呢?因为可能i+nums[i]比dp[i-1]小,这样其实i-1位置也是能跳过i的,也是有可能到达最终点的
- 而且我们不必考虑最后一个点的dp值,前面没break掉,就行了;
- 最终我们判断下最大的dp值,只要大于最后一个点的下标,就能直接跳过去,
基于上述思路,这题也很简单,可能非dp要快些,但是dp真的思路很简单
public boolean canJump(int[] nums) {
if (nums.length == 1) return true;
int[] dp = new int[nums.length];
int max = Integer.MIN_VALUE;
for (int i = 0;i<nums.length-1;i++){
if (i==0) dp[0] = nums[0];
if (i-1 >=0){
if (dp[i-1] < i){break;}
dp[i] = Math.max(dp[i-1],i + nums[i]);
}
if (dp[i] > max) max = dp[i];
}
if (max < nums.length -1 ) return false;
return true;
}
leetcode 62. 不同路径
这题更简单,稍微有一点dp思路,肯定能ac,没想到能ac 100%,运气来了
思路
- 能否拆为子问题?肯定可以,拆为坐标(m,n)到达的路径数
- 后续子问题解只依赖前面的解?是的
- 既然是连续子数组的最大和,我们就要dp[i][j]代表坐标(m,n)到达的路径数
- 因为他只能向下或者向左,那简单了,就是等于这个二维数组的上面和左边的值的和,也就是 dp[i][j] = dp[i-1][j] + dp[i][j-1]
基于上述思路,这题也很简单,dp真的思路真的很简单
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
dp[0][0] = 1;
for (int i =0;i<m;i++){
for (int j=0;j<n;j++){
if (i==0 || j ==0){dp[i][j] = 1;continue;}
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
好啦,今天的学习到此为止,健会身出去泡澡咯