【算法题】动态规划学习总结-2

68 阅读2分钟

新年好,今天就做了三道题,全ac了,这是要长脑子了?

leetcode 53. 最大子数组和

image.png

思路:

这题很简单,思路也很简单

  • 能否拆为子问题?肯定可以,拆为数组前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. 跳跃游戏

image.png

思路

  • 能否拆为子问题?肯定可以,拆为数组前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%,运气来了 image.png

思路

  • 能否拆为子问题?肯定可以,拆为坐标(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];
}

好啦,今天的学习到此为止,健会身出去泡澡咯