力扣打怪记006

力扣打怪记006

这是一期关于动态规划(dp)的练习文章~~
会按题目的类型分多期

系列题目一:买卖股票

入门级:
给定一个数组 prices ,它的第 i 个元素 prices[i-1] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。
如果你不能获取任何利润,返回 0 。

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

分析:
解法一:
一道很典型的dp题,我们可以不用dp来做,避免排序,减小时间空间复杂度
解法如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // vector<int>dp(prices.size(),0);
        int result=INT_MAX, maxprofit=0;
        if(prices.size()==0)
        return 0;
        for(int i=0;i<prices.size();++i)
        {
            result=min(prices[i],result);
            if(result<prices[i])
            // dp[i]=prices[i]-result
            maxprofit=max(maxprofit,prices[i]-result);}
        return maxprofit;
}
};

解法二:使用dp来做,要注意本题关键在于找到历史最小值result,把dp设置为利润大小,比较每天的利润就行。

状态转移方程可抽象为:dp[i]=max(dp[i-1],prices[i]-result)
代码表示如下:

 for(int i=0;i<prices.size();++i)
        {
            result=min(prices[i],result);
            if(result<prices[i])
            dp[i]=prices[i]-result;}
        return *max_element(dp.begin(),dp.end());

全代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<int>dp(prices.size(),0);
        int result=INT_MAX;
        if(prices.size()==0)
        return 0;
        for(int i=0;i<prices.size();++i)
        {
            result=min(prices[i],result);
            if(result<prices[i])
            dp[i]=prices[i]-result;}
        return *max_element(dp.begin(),dp.end());
}
};

提高级:
给定一个数组 prices ,其中 prices[i-1] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:
输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:
输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

分析:
此题是买卖股票常规题,相较于入门题此题增加了操作次数不限的
条件,那么对任意一天状态,要么持有股票,要么卖掉股票,我们用0和1表示,
状态转移方程:(dp[i][j]:i表示天数,j表示是否持有股票,dp表示当天该状况最大利润)
状态转移方程:
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])
可能很多朋友就会问了,为什么是加上prices[i],这是因为我们把第一次买入记作:dp[0][1]=-prices[0],所以某天卖出的利润包含在dp+prices[i+n]

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

进阶级:
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。
你最多可以完成两笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例 2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例 4:
输入:prices = [1]
输出:0

分析:
这道题比较上一题多了限制条件只进行两次交易,所以我们此题可以用四个变量来表示:
buy1,sell1,buy2,sell2表示当前状态利润值
buy1表示第一次买,sell1表示第一次卖,buy2和sell2同理,
状态转移方程:
buy1=max[buy1,-prices[i]];
sell1=max[prices[i]+buy1,sell1];
buy2=max[sell1-prices[i],buy2];
sell2=max[buy2+prcies[i],sell2];
这里朋友们可能会有疑问,如果我有一天买了股票然后又卖了股票,那么情况会怎样呢,你可以假设一下,你同一天买卖等于没操作,sell为0,对结果无影响

初始值:
buy1=-prices[0];sell1= 0;
buy2=-prices[0];sell2= 0;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        int buy1=-prices[0],sell1=0;
        int buy2=-prices[0],sell2=0;
        for(int i=0;i<n;++i)
        {
            buy1=max(buy1,-prices[i]);
            sell1=max(sell1,buy1+prices[i]);
            buy2=max(buy2,sell1-prices[i]);
            sell2=max(sell2,buy2+prices[i]);
        }
        return sell2;}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值