(笔试题)风口的猪-中国牛市

题目:

风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设计算法,计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100

输入例子:

3,8,5,1,7,8

输出例子:

12

思路:

1、动态规划

i表示第i天,k表示第k次交易

  • 状态转移方程:
    • pmax = max{ f(j,k-1)+prices[i]-prices[j] } (0<=j<i)}
    • f(i,k) = max{ f(i-1,k), pmax}
    • 即f(i,k ) = max{  f(i-1,k) ,  max { f(j,k-1) + prices[i]-prices[j]  |  0<=j<i } }
  • f(i-1,k)表示第i天不交易
  • max{ f(j,k-1)+prices[i]-prices[j] } (0<=j<i)}表示第i天卖,而这次交易的买应该来自第j天,f(j,k-1) +prices[i] - prices[j] ,0<=j<i ,取最大值。
  • max{ f(j,k-1)+prices[i]-prices[j] } (0<=j<i)},这一步可以通过单调队列来优化,可以参考一下:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html,简单的来说,就是将方程中包含j的部分单独拿出来处理,即max(f(j,k-1)-prices[j])

2、前缀、后缀数组

通过前缀数组A来计算0次或1次交易的最大收益;

通过后缀数组B来计算0次或1次交易的最大收益;

通过遍历0-n,计算max(A[i]+B[i])即为最大收益;

代码:

1、简单的动态规划

class Solution {
public:
    /**
     * 计算你能获得的最大收益
     * 
     * @param prices Prices[i]即第i天的股价
     * @return 整型
     */
    int kTransaction(vector<int> prices,int k){
        int n=prices.size();
        vector<vector<int> > dp(n,vector<int>(k+1,0));
        int mx;
        for(int i=1;i<n;i++){
            for(int t=1;t<=k;t++){
                mx=dp[i-1][t];
                for(int j=i-1;j>=0;j--)
                    mx=max(mx,dp[j][t-1]+prices[i]-prices[j]);
                dp[i][t]=mx;
            }
        }
        return dp[n-1][k];
    }
     
    int calculateMax(vector<int> prices) {
    return kTransaction(prices,2);
    }
};

2、单调队列优化的动态规划

class Solution {
public:
    /**
     * 计算你能获得的最大收益
     * 
     * @param prices Prices[i]即第i天的股价
     * @return 整型
     */
    int kTransaction(vector<int> prices,int k){
        int n=prices.size();
        vector<vector<int> > dp(n,vector<int>(k+1,0));
        vector<int> pMax(k+1,0);
        int mx;
        for(int i=0;i<=k;i++)
            pMax[i]=-prices[0];
        for(int i=1;i<n;i++){
            pMax[0]=max(pMax[0],dp[i][0]-prices[0]);
            for(int t=1;t<=k;t++){
                mx=dp[i-1][t];
                mx=max(mx,pMax[t-1]+prices[i]);
                pMax[t-1]=max(pMax[t-1],dp[i][t-1]-prices[i]);
                dp[i][t]=mx;
            }
        }
        return dp[n-1][k];
    }
     
    int calculateMax(vector<int> prices) {
    return kTransaction(prices,2);
    }
};

3、前缀后缀数组

class Solution {
public:
    /**
     * 计算你能获得的最大收益
     * 
     * @param prices Prices[i]即第i天的股价
     * @return 整型
     */
    int calculateMax(vector<int> prices) {
        int n=prices.size();
        vector<int> leftMax(n);
        vector<int> rightMax(n);
        int lmin=prices[0];
        leftMax[0]=0;
        for(int i=0;i<n;i++){
            lmin=min(lmin,prices[i]);
            leftMax[i]=max(leftMax[i-1],prices[i]-lmin);
        }
        int rmax=prices[n-1];
        rightMax[n-1]=0;
        for(int i=n-2;i>=0;i--){
          rmax=max(rmax,prices[i]);
            rightMax[i]=max(rightMax[i+1],rmax-prices[i]);
        }
        int pmax=0;
        for(int i=0;i<n;i++)
            pmax=max(pmax,leftMax[i]+rightMax[i]);
        return pmax;
    }
};
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值