动态规划之股票问题

  坚持写博客也是一件挺难的事情……

一次交易问题

问题描述:
假如你有一个数组,其中第i个元素是股票在第i天的价格,你有一次买入和卖出的机会。(只有买入了股票后才可以卖出)。请你设计一个算法来计算可以获得最大的收益。
示例1:
输入:[1、3、4]
输出:3

解法一

我们应该很快就有一个解题思路,这题就是让我们对这个数组的元素按照顺序进行减操作,然后要求得到最大的结果。毋庸置疑我们可以用冒泡的思想,将每个元素的都进行一次减操作,然后得到结果。具体代码如下:

    int maxProfit(vector<int>& prices) {
        // write code here
        //冒泡排序
        int len = prices.size();
        int max = 0;
        for(int i=0;i<len-1;i++)
        {
            for(int j=i+1;j<len;j++)
            {
                if(prices[j] - prices[i] > max)
                {
                    max = prices[j] - prices[i];
                }
            }
        }
        return max;
    }
解法二:

上面的解法很轻易的我们就能想到,但是它的时间复杂度是O(n2)。那么我们有没有办法在节省时间呢?接下来我们用O(n)的时间复杂度尝试解决问题。
每一天我们对股票的操作只有两个状态:1、当天买入股票需要的最小花费。2、当天卖出股票的最大收益。于是乎,
我们可以定义一个dp二维数组用来描述每一天的状态。其中规定:dp[i][0]:代表第i天买入股票需要花费的最小值,dp[i][1]:代表第i天卖出股票的最大收益。然后我们可计算出相关的转移方程:
第一天的时候,我们只能买入,没有办法卖出。所以

dp[0][0] = prices[0],dp[0][1] = 0;

第i天的时候:

dp[i][0] = min(dp[i-1][0],prices[i]);//买入股票最小花费。
dp[i][1] = max(dp[i-1][1],prices[i]- dp[i-1][0]);//卖出股票的最大收益

 完整的代码:

int maxProfit(vector<int>& prices) {
        // write code here
        int len = prices.size();
        if(len == 0) return 0;
        int dp[len][2];
        dp[0][0] = prices[0];
        dp[0][1] = 0;
        for(int i=1;i<len;++i)
        {
            dp[i][0] = min(dp[i-1][0],prices[i]);
            dp[i][1] = max(dp[i-1][1],prices[i] - dp[i-1][0]);
        }
        return dp[len-1][1];
    }

两次交易

题目描述:
假定你知道某只股票每一天价格的变动。你最多可以同时持有一只股票。但你最多只能进行两次交易(一次买进和一次卖出记为一次交易。买进和卖出均无手续费)。请设计一个函数,计算你所能获得的最大收益。
示例:
输入:[8,9,3,5,1,3]
输出:4
输出解释:第三天买入,第四天卖出。第五天买入,第六天卖出。
 仅仅只是多了一次交易,但是题目的难度却不止上升一倍。我们需要同时知道在每一天每一次买入卖出的实际情况。记录每一天的所有状态。而,每一天的状态其实就5类。分别是:
1、没有做任何交易。
2、第一次买入股票最小花费。
3、第一次卖出股票最大收益。
4、第二次买入股票最小花费。
3、第二次卖出股票最大收益。
 当然我们可以定义一个dp[][5]来记录每一天股票交易的状态。计算得到的转移方程如下:
 首先,仍然是第一天的时候,只可以买入,不可以卖出。对dp[0][]进行初始化:

dp[0][0] = 0;
dp[0][1] = prices-[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;

 第i天的操作:

dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i]);
dp[i][2] = max(dp[i-1][2],prices[i] - dp[i-1][1]);
dp[i][3] = max(dp[i-1][3],dp[i][2] - prices[i]);
dp[i][4] = max(dp[i-1][4],prices[i] - dp[i-1][3]);

完整的代码:

int maxProfit(vector<int>& prices) {
          // write code here
       //二次交易
        int len = prices.size();//获得天数
        if(len == 0) return 0;
        int dp[len][5];//规划数组,代表每一个状态
        //dp[i][0]--->代表第i天没有做任何操作的最大收益
        //dp[i][1]--->代表第i天买入第一次股票的最大收益
        //dp[i][2]--->代表第i天卖出第一次股票的最大收益
        //dp[i][3]--->代表第i天买入第二次股票的最大收益
        //dp[i][4]--->代表第i天卖出第一次股票的最大收益
        //于是用了动态规划
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;
        dp[0][3] = -prices[0];
        dp[0][4] = 0;
        for(int i = 1;i<len;++i)
        {
            dp[i][0] = dp[i-1][0];//这个就像一个装饰
            dp[i][1] = max(dp[i-1][1],dp[i][0] - prices[i]);//获得第一次买入股票的最小值
            dp[i][2] = max(dp[i-1][2],prices[i] + dp[i-1][1]);//获得第一次卖出股票的最大值 
            dp[i][3] = max(dp[i-1][3],dp[i][2]-prices[i]);//获得第二次买入股票的最小消费
            dp[i][4] = max(dp[i-1][4],prices[i] + dp[i-1][3]);
        }
        return dp[len-1][4];
    }

n次交易

题目描述:
假定你知道某只股票每一天价格的变动。你最多可以同时持有一只股票。但你可以无限次的交易(买进和卖出均无手续费)。请设计一个函数,计算你所能获得的最大收益。
虽然是N次交易,但是它的解题就非常简单,只要prices[i] - prices[i-1] > 就可以加入到总收益当中。代码如下:


 int maxProfit(vector<int>& prices) {
        // write code here
        int res = 0;//代表最终收益
        for(int i= 1;i < prices.size();i ++){
            int temp = prices[i]-prices[i-1];//收益
            if(temp > 0) res += temp;//如果为正收益就加和
        }
        return res;
    }

以上就是股票交易的问题解法,记录出来希望可以帮助到需要的人,也让自己下次不会出错。

posted @ 2021-03-28 12:35  lisui  阅读(392)  评论(0编辑  收藏  举报