Leedcode刷题——6 动态规划(DP问题)

博客主要围绕动态规划算法展开,介绍了其本质是用数组保存已算值以减少重复计算。详细阐述了最大子数组和、三角形最小路径和、不同路径2等多个经典问题的思路,还涉及买卖股票最佳时机、背包问题(包括01背包和完全背包)等,给出了状态表示和计算方法。

注:以下代码均为c++

动态规划的本质:用数组保存之前算过的值,在计算后面的值时直接从数组中取已经算过的值再继续计算,以此减少重复计算。

1. 最大子数组和

在这里插入图片描述
思路:
请添加图片描述

int maxSubArray(vector<int>& nums) {
   
   
    int res = INT_MIN, f = 0;
    for(int i = 0; i < nums.size(); i++){
   
   
        f = max(f, 0) + nums[i];
        res = max(f, res);
    }
    return res;
}

2. 三角形最小路径和

在这里插入图片描述
思路:
请添加图片描述

法1:用nxn的二维数组记录已经求过的结果

int minimumTotal(vector<vector<int>>& triangle){
   
   
    int n = triangle.size();
    vector<vector<int>> f(n,vector<int>(n));  //高维vector初始化:nxn的二维数组
    f[0][0] = triangle[0][0];
    for(int i = 1; i < n; i++){
   
   
        for(int j = 0; j <= i; j++){
   
   
            if(j-1 >= 0  && j < i)
                f[i][j] = min(f[i-1][j-1], f[i-1][j]) + triangle[i][j];
            else if(j-1 < 0)
                f[i][j] = f[i-1][j] + triangle[i][j];
            else
                f[i][j] = f[i-1][j-1] + triangle[i][j];
        }
    }
    int mins = INT_MAX;
    for(int i = 0; i < n; i++){
   
   
        mins = min(mins, f[n-1][i]);
    }
    return mins;
}

法2:优化:用2xn的二维数组(只记录上一层结果)记录已经求过的结果

int minimumTotal(vector<vector<int>>& triangle){
   
   
    int n = triangle.size();
    vector<vector<int>> f(2,vector<int>(n));  //优化:由于只需要记录上一层的结果,所以开两层数组即可。
    f[0][0] = triangle[0][0];
    for(int i = 1; i < n; i++){
   
   
        for(int j = 0; j <= i; j++){
   
   
            if(j-1 >= 0  && j < i)
                f[i & 1][j] = min(f[i-1 & 1][j-1], f[i-1 & 1][j]) + triangle[i][j];  //n%2相当于&1
            else if(j-1 < 0)
                f[i & 1][j] = f[i-1 & 1][j] + triangle[i][j];
            else
                f[i & 1][j] = f[i-1 & 1][j-1] + triangle[i][j];
        }
    }
    int mins = INT_MAX;
    for(int i = 0; i < n; i++){
   
   
        mins = min(mins, f[n-1 & 1][i]);
    }
    return mins;
}

3. 不同路径2

在这里插入图片描述
在这里插入图片描述
思路:
状态表示:f[i][j]:当前路径的数量
状态计算:f[i][j] = f[i-1][j] + f[i][j-1]

下面的代码一个是我自己写的,一个是答案,思路是一样的。

//我自己写的代码
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid){
   
   
    int m = obstacleGrid.size(), n = obstacleGrid[0].size();
    vector<vector<int>> f(m, vector<int>(n));
    for(int i = 0; i < m; i++){
   
   
        for(int j = 0; j < n; j++){
   
   
            if(obstacleGrid[i][j] == 1)     continue;  //如果是障碍物,跳过
            if(i == 0 && j == 0)    f[i][j] = 1;  //如果是左上角赋值为1
            if(i == 0 && j-1 >= 0)  f[i][j] = f[i][j-1];  //第一行
            if(j == 0 && i-1 >= 0)  f[i][j] = f[i-1][j];  //第一列
            if(i-1 >= 0 && j-1 >= 0)    f[i][j] = f[i][j-1] + f[i-1][j];
        }
    }
    return f[m-1][n-1];
}
//答案
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
   
   
    int m = obstacleGrid.size(), n = obstacleGrid[0].size();
    vector<vector<int>> f(m, vector<int>(n));
    for(int i = 0; i < m; i++){
   
   
        for(int j = 0; j < n; j++){
   
   
            if(obstacleGrid[i][j])  //如果是障碍物,跳过
                continue;
            if(i == 0 && j == 0)    f[i][j] = 1;  //如果是左上角
            if(i > 0)   f[i][j] += f[i-1][j];  //如果不是第一行
            if(j > 0)   f[i][j] += f[i][j-1];  //如果不是第一列
        }
    }
    return f[m-1][n-1];
}

4. 解码方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值