zoukankan      html  css  js  c++  java
  • 动态规划之股票问题

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

    一次交易问题

    问题描述:
    假如你有一个数组,其中第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;
        }
    
    

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

  • 相关阅读:
    DJango简单的后台定义登录验证
    简单聊聊HTTP/TCP/IP协议
    简单的线程说明
    设计模式 -- 常用设计模式
    网络知识 -- 第二部
    c#利用脚本,本地执行linux命令
    Json和类之间的转化
    关于地址映射穿透和套接字复用的说明
    多线程调用中的注意事项
    Task多线程的常规用法
  • 原文地址:https://www.cnblogs.com/kadcyh/p/14588277.html
Copyright © 2011-2022 走看看