【leetcode】股票买卖系列总结

股票买卖系列总结

股票买卖系列的题目在面试中还是比较经典的,这里对这一系列做一些简单的总结。

1. 只允许买卖一次

假设股票价格序列为(3, 5, 7, 3, 8, 1)

动态规划。整个过程中的行为选择有3种,买/卖/无操作。

d p [ i ] dp[i] dp[i]表示第 i i i天的行为是”卖出“时,能得到的最大收益。显然,我们固定了卖出的时间,只要在这个时间点之前的时间中选择股票价格比最小的时候买入,就可以确定 d p [ i ] dp[i] dp[i]的值。

所以我们可以遍历价格序列,cur_min不断更新以记录当前时间点之前的股票最低价格,所以 d p [ i ] = m a x ( 0 , p r i c e s [ i ] − c u r _ m i n ) dp[i] = max(0, prices[i]-cur\_min) dp[i]=max(0,prices[i]cur_min),最后所有dp[i]中的最大值就是只进行一次买卖能得到的最大利润。可以在求 d p [ i ] dp[i] dp[i]的同时用一个变量来记录其最大值。

因为 d p [ i ] dp[i] dp[i]只用到一次,所以没必要开一个数组专门来存储。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 只允许最多一次交易 求最大收益
        // 记录当前最小  cur_min dp[i]表示在第i天卖出的最大收益
        if(prices.size()<=1) return 0;
        int cur_min = prices[0], res = 0;
        for(int i=1; i<prices.size(); i++){
            res = max(prices[i]-cur_min, res);// dp[i] = prices[i] - cur_min;
            cur_min = min(cur_min, prices[i]);
        }
        return res;
    }
};

2. 不限制买卖次数

假设股票价格序列为(1, 2, 3, 4, 5)。其实这是一个特殊情况,我们可以在第0天买入,然后在最后一天卖出。此时最大收益就是4。

我们也可以在第0天买入,第一天卖出。第一天买入,第二天卖出。。。这样的结果和上面是一样的,最大收益都是4。

所以,对于比较常规的情况,比如说(7, 6, 3, 4, 5),在第一天和第二天是不能买入的,因为,之后找不到比当前价格更大的数了。另外的话,可以在3的时候买入,4的时候卖出,然后4又买入,5卖出。最后最大收益是2.

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 不限制股票的买卖次数
        // 只要是遇到比当前价格更高的就卖掉
        if(prices.size() <=1) return 0;
        int buy = INT_MAX, profit = 0;
        for(int i=0; i<prices.size(); i++){
            if(prices[i]<=buy) buy = prices[i];
            else{
                profit += prices[i]-buy;
                buy = prices[i];
            }
        }
        return profit;
    }
};

可以将上面代码进行简化:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size() <=1) return 0;
        int buy = INT_MAX, profit = 0;
        for(int i=0; i<prices.size(); i++){
            if(prices[i] > buy) profit += prices[i] - buy;// 只有当当前价格大于假设买入的价格时,才进行卖出
            buy = prices[i];// 每次都在当前进行“假设”买入
        }
        return profit;
    }
};

3. 最多只能买卖2次

b u y 1 buy1 buy1表示在第 i i i天进行第一次买入时可以获得的最大收益
b u y 2 buy2 buy2表示在第 i i i天进行第二次买入时可以获得的最大收益
s e l l 1 sell1 sell1表示在第 i i i天进行第一次卖出时可以获得的最大收益
s e l l 2 sell2 sell2表示在第 i i i天进行第二次卖出时可以获得的最大收益

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 最多只能买卖2次 求最大收益
        // buy1 sell1 buy2 sell2 分别表示当前天如果是第一次买/卖、第二次买/卖时的最大收益
        int buy1 = INT_MIN, buy2 = INT_MIN, sell1 = 0, sell2 = 0;
        for(int price:prices){
            sell2 = max(sell2, buy2+price);
            buy2 = max(buy2, sell1-price);
            sell1 = max(sell1, buy1+price);
            buy1 = max(buy1, -price);
        }
        return sell2;
    }
};

4. 有冷冻期不限制买卖次数

b u y [ i ] buy[i] buy[i]表示第 i i i天之前最后一次行为是buy时,最大的收益

s e l l [ i ] sell[i] sell[i]表示第 i i i天之前最后一次行为是sell时,最大的收益

r e s t [ i ] rest[i] rest[i]表示第 i i i天之前最后一次行为是冷冻rest时,最大的收益

b u y [ i ] = m a x ( b u y [ i − 1 ] , r e s t [ i − 1 ] − p r i c e s [ i ] ) buy[i] = max(buy[i-1], rest[i-1] - prices[i]) buy[i]=max(buy[i1],rest[i1]prices[i]),max(第i天冷冻, 第i天是卖出)

s e l l [ i ] = m a x ( s e l l [ i − 1 ] , b u y [ i − 1 ] + p r i c e s [ i ] ) sell[i] = max(sell[i-1], buy[i-1] + prices[i]) sell[i]=max(sell[i1],buy[i1]+prices[i]),max(第i天冷冻,第i天是买入)

r e s t [ i ] = m a x ( r e s t [ i − 1 ] , b u y [ i − 1 ] , s e l l [ i − 1 ] ) rest[i] = max(rest[i-1], buy[i-1], sell[i-1]) rest[i]=max(rest[i1],buy[i1],sell[i1])

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 有冷冻期 不限制买卖次数 但是卖完股票后有一天的冷冻期才能再接着买
        int n = prices.size();
        if(n<=1) return 0;
        vector<int> buy(n, INT_MIN), sell(n, INT_MIN), rest(n, INT_MIN);
        buy[0] = -prices[0];
        sell[0] = 0;
        rest[0] = 0;
        for(int i=1; i<n; i++){
            buy[i] = max(buy[i-1], rest[i-1]-prices[i]);
            sell[i] = max(sell[i-1], buy[i-1]+prices[i]);
            rest[i] = max(rest[i-1], max(buy[i-1], sell[i-1]));
        }
        return max(buy[n-1], max(sell[n-1], rest[n-1]));
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值