leetcode200题之动态规划(一)

1.零钱兑换

(1)dp[i]含义:定义dp[i] 为组成金额 i 所需最少的硬币数量

(2)找数组元素之间关系:dp[i]=min\sum dp[i-coins[j]]+1 (j=0,n-1),coins[j]表示可选的硬币面值

(3)初始值(base case):dp[0]=0;

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount+1,amount+1);
        dp[0] = 0;
        for(int coin:coins)
            for(int i = coin;i<=amount;i++)
                dp[i] = min(dp[i],dp[i-coin]+1);
        return dp[amount] == amount+1?-1:dp[amount];
    }
};

2. 最大正方形

(1)dp[i][j]含义:matrix[i][j] 为右下角的正方形的最大边长

(2)关系:对于任意一点dp[i][j],由于该点是正方形的右下角,所以该点右边、下边、右下均不考虑,关心其左边、上边以及左上,也就是要推导dp[i][j]与dp[i][j-1]、dp[i-1][j]和dp[i-1][j-1]之间的关系,画图可得:

                                                  dp[i][j]=min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1])+1.

(3)初始值:如果 i 和 j 中至少有一个为 0,则以位置 (i, j)为右下角的最大正方形的边长只能是 1,因此 dp[i][j]= 1

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.size()<1 || matrix[0].size()<1){
            return 0;
        }
        int row=matrix.size();
        int col=matrix[0].size();
        int max=0;
        vector<vector<int>> dp(row,vector<int>(col));
        for(int i=0; i<row; i++){
            for(int j=0; j<col; j++){
                if(matrix[i][j]=='1'){
                    if(i==0 || j==0) dp[i][j]=1;
                    else  dp[i][j]=min(min(dp[i-1][j],dp[i][j-1]),dp[i-1][j-1])+1;
                }
                max = max > dp[i][j] ? max : dp[i][j];
            }
        }
        
        return max*max;
    }
};

3. 打家劫舍

思路:

对于第 k~(k>2)k (k>2) 间房屋,有两个选项:

偷窃第 k 间房屋,那么就不能偷窃第 k-1 间房屋,偷窃总金额为前 k-2 间房屋的最高总金额与第 k 间房屋的金额之和。

不偷窃第 k 间房屋,偷窃总金额为前 k-1间房屋的最高总金额。

(1)dp[i]含义:表示前 i 间房屋能偷窃到的最高总金额

(2)数组关系:dp[i]=max(dp[i−2]+nums[i],dp[i−1])

(3)边界条件:没有人家 dp[0]=0,    一户人家 dp[1]=nums[0]

class Solution {
public:
    int rob(vector<int>& nums) {
        int len=nums.size();
        if(len==0)  return 0;
        int dp[len+1];
        dp[0]=0;
        dp[1]=nums[0];
        for(int i=2; i<=len;i++){
            dp[i]=max(dp[i-2]+nums[i-1], dp[i-1]);
        }
        return dp[len];
    }
};

4. 买股票的最佳时机(只允许买一次,卖一次)

(1)dp[i]含义:dp[i] 表示前 i 天的最大利润

(2)转移方程:dp[i]=max(dp[i−1], prices[i]−min_price)

(3)边界条件:dp[0]=0;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        if(n<1)  return 0;
        int min_price=prices[0];
        vector<int> dp(n);
        dp[0]=0;
        for(int i=1; i<n; i++){
            if(prices[i]<min_price){
                min_price=prices[i];
            }
            dp[i]=max(dp[i-1],prices[i]-min_price);
        }
        return dp[n-1];
    }
};

5. 买卖股票的最佳时机(不限买卖次数)

(1)dp[i][j]含义:索引为 i 的那一天(具有前缀性质,即考虑了之前天数的收益)能获得的最大利润; j则表示索引为 i 的那一天是持有股票,还是持有现金

(2)数组关系:

//第i天不持有股票  i-1天不持有且无操作     i-1天持有并在i天卖了+prices[i]
dp[i][0] = max(    dp[i - 1][0],         dp[i - 1][1] + prices[i]);
//第i天持有股票    i-1天持有且无操作       i-1天不持有但是买入了-prices[i]
dp[i][1] = max(    dp[i - 1][1],         dp[i - 1][0] - prices[i]);

(3)边界条件:起始的时候:什么都不做:dp[0][0]=0;   买入股票收益为负:dp[0][1]= -prices[0]

(4)注意本题返回值:dp[n-1][0];   因为一定有dp[n-1][0] > dp[n-1][1]

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        if(n<1)  return 0;
        vector<vector<int>> dp(n,vector<int>(2));
        dp[0][0]=0;
        dp[0][1]=-prices[0];
        for(int i=1; i<n; i++){
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);
        }
        return dp[n-1][0];
    }
};

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值