股票买卖问题

题解:https://segmentfault.com/a/1190000006672807

121. Best Time to Buy and Sell Stock
求一个数列中的最小值和最大值,要求最小值要在最大值之前

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

122. Best Time to Buy and Sell Stock II
https://blog.csdn.net/musechipin/article/details/70858483

309. Best Time to Buy and Sell Stock with Cooldown
这道题可以用状态转移的方法做,上面的网页讲的很清楚,有一点可以优化:当天的买卖状态只与前一天有关,因此可以使用O(1)的空间复杂度。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size()<=1) return 0;
        vector<int> hold;//第i天持有股票的的最大收益
        vector<int> unhold;//第i天不持有(已经过了冷却时间)的最大收益
        vector<int> cold;//第i天在冷却期 (说明第i-1天是hold)的最大收益
        
        hold.push_back(-prices[0]);
        unhold.push_back(0);
        cold.push_back(0);
        
        for (int i=1;i<prices.size();i++) {
            hold.push_back(max(hold[i-1],unhold[i-1]-prices[i]));
            unhold.push_back(max(unhold[i-1],cold[i-1]));
            cold.push_back(hold[i-1]+prices[i]);
        }
        
        int n=prices.size()-1;
        return max(hold[n],max(unhold[n],cold[n]));
    }
};

123. Best Time to Buy and Sell Stock III
相当于找两个没有交叉的最大差值区间。使用双向动态规划可以降低时间复杂度,从左到右相当于第一个段时间(0..i)内得到的最大差值,从右向左算一遍相当于第二段时间(i..n)内的最大差值,找到一个i,使得两边之和最大即可。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        if (n<=1) return 0;
        vector<int> left(n,0);
        vector<int> right(n,0);
        
        int min1=prices[0];
        left[0]=0;//表示从头到i交易一次所能得到的最大收益
        for (int i=1;i<n;i++) {
            min1=min(min1,prices[i]);//先求最小值
            left[i]=max(left[i-1],prices[i]-min1);//即使后边部分小于0,前一天的盈利也可累积 
        }
        
        int max1=prices[n-1];
        right[n-1]=0;//表示从i到尾交易一次所能得到的最大收益
        for (int i=n-2;i>=0;i--) {
            max1=max(max1,prices[i]);
            right[i]=max(max1-prices[i],right[i+1]);   
        }
        int sum=0;
        for (int i=0;i<n;i++) 
            sum=max(sum,right[i]+left[i]);
        return sum;
    }
};

393. 买卖股票的最佳时机 IV
还是利用状态转移,但是要注意一次买入卖出算一次交易。

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n=prices.size();
        if (n<=1) return 0;
        if (k>=n/2) {//如果k次数足够多,退化成任意次数买卖的情况
            int profit=0;
            for (int i=1;i<n;i++) 
                profit+=max((prices[i]-prices[i-1]),0);
            return profit;
        }
        
        vector<vector<int>> hold(n,vector<int>(k+1,0));//第i天,交易j次,且持有股票的最大盈利
        vector<vector<int>> unhold(n,vector<int>(k+1,0));//第i天,交易j次,且不持有股票的最大盈利
        for (int i=0;i<n;i++) 
        {
            for (int j=1; j<=k; j++) {
                if (i==0) hold[i][j]=-prices[i];
                else {
                    hold[i][j]=max(unhold[i-1][j-1]-prices[i],hold[i-1][j]);
                    unhold[i][j]=max(hold[i-1][j]+prices[i],unhold[i-1][j]);
                    //注意这里是hold[i-1][j],不是hold[i-1][j-1],因为买入再卖出才算一次,j在买入时+1
                }
            }
        }
            
        return unhold[n-1][k];//卖出才有钱
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值