Best Time to Buy and Sell Stock 系列问题(leetcode)

关键词:
动态规划,分治

121. Best Time to Buy and Sell Stock

题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/

求最大的一次买卖

122. Best Time to Buy and Sell Stock II

题目地址:
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/

不限买卖次数的最大盈利额

采用动态规划做法,o(n^2)时间复杂度
dp[i]表示截止到第i天 可以获得的最大盈利

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if (len <= 1)
            return 0;

        vector<int> dp(len);

        dp[0] = 0;
        dp[1] = max(0, prices[1] - prices[0]);
        int minVal = min(prices[0], prices[1]);

        int maxP = max(dp[0], dp[1]);

        for (int i = 2; i < len; i++)
        {
            if (prices[i] <= minVal)
            {
                dp[i] = dp[i - 1];
                minVal = prices[i];
                continue;
            }
            int p1 = dp[i - 1];
            int p2 = prices[i] - prices[0];
            dp[i] = max(p1, p2);
            for (int j = 1; j < i; j++){
                if (prices[i] <= prices[j])
                    continue;
                int ptmp = dp[j - 1] + prices[i] - prices[j];
                dp[i] = max(dp[i], ptmp);
            }

            if (dp[i] > maxP)
                maxP = dp[i];
        }

        return maxP;
    }
};

另外一种做法,说
应为不限制次数,因此,每一天都可以卖出,所以只要当前比昨天能够有收入,就可以卖出当天的
(一直递增的序列,其实算的是 最大减去最小的那个值,还是最大的)

最后的ac代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if (len <= 1)
            return 0;

        int result = 0;
        for (int i = 1; i < len; ++i) {
            if (prices[i] - prices[i - 1] > 0) {
                result += prices[i] - prices[i - 1];
            }
        }
        return result;
    }
};

123. Best Time to Buy and Sell Stock III

题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/

最多可以进行2次交易的最大获利,可以2次或1次
有种分治的思想

ac代码如下

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if (len <= 1)
            return 0;
        if (len == 2)
        {
            return max(0, prices[1] - prices[0]);
        }

        int maxP = 0;

        vector<int> left(len); // 包括 price[i] 在内的 左部分的最大一次交易
        left[0] = 0;
        int leftMin = prices[0];
        for (int i = 1; i < len; i++)
        {
            left[i] = max(left[i-1], prices[i] - leftMin);

            if (prices[i] < leftMin){
                leftMin = prices[i];
            }

            if (left[i] > maxP)
                maxP = left[i];
        }

        vector<int> right(len); // 包括 price[i]在内 右部分的最大一次交易
        right[len - 1] = 0;
        int rightMax = max(prices[len - 1], prices[len - 2]);
        for (int i = len - 2; i >= 0; i--)
        {
            right[i] = max(right[i+1], rightMax - prices[i]);
            if (prices[i] > rightMax)
                rightMax = prices[i];
        }

        // 两次交易
        for (int i = 1; i < len - 2; i++)
        {
            int two = left[i] + right[i + 1];
            if (two > maxP)
                maxP = two;
        }

        return maxP;
    }
};

188. Best Time to Buy and Sell Stock IV

题目地址
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/

规定了最大交易次数,是上面几个题目的拓展

思路1

转载文章参考如下
http://www.07net01.com/2015/08/903505.html

基本思想

k次交易,我们需要大小为k的数组记录每一次交易的信息,又因为一次交易包含买和卖两次操作,所以我们需要两个数组。分别命名为hold【】和sell【】。hold[i]表示第i次持有后的盈亏,也就是第i次买入后的状态,sell[i]表示第i次卖出后的盈亏状态。比如上个例子1,3,7,2,1,5.如果我们在第一天买入,那么hold[1]应该是-1,这里可能会问,为什么会是负数?那是因为我们买入了股票,钱已经花出去了,但我们还没有卖出,所以当前你手上是没有现金的,只有股票。
算法核心就是两句:

cur = prices[i];
sell[j] = max(sell[j],hold[j] + cur); // sell 递推式
hold[j] = max(hold[j],sell[j-1] - cur); // hold递推式

在第i天第j次持有的盈亏最大是取两个的较大值,前一个表示继续持有,后一个表示在第j-1次卖出后,第i天又买入了。
在第i天第j次卖出的盈亏最大同上,也是比较两数取较大。

最后的ac代码如下:

class Solution {
public:

    int maxProfit(int k, vector<int>& prices) {
        int len = prices.size();
        if (len <= 1 || k <= 0)
            return 0;

        if (k > len / 2) // 不限制次数
        {
            int result = 0;
            for (int i = 1; i < len; ++i) {
                if (prices[i] - prices[i - 1] > 0) {
                    result += prices[i] - prices[i - 1];
                }
            }
            return result;
        }

        int INF = 0x7fffffff;
        int MIN = -1 - INF;

        vector<int> hold(k + 1, MIN); // 第k次交易持有的亏损
        vector<int> sell(k + 1,0); // 第k次交易卖出后的盈利情况
        int cur;
        for (int i = 0; i < len; i++)
        {
            cur = prices[i];
            for (int j = 1; j <= k; j++)
            {
                sell[j] = max(sell[j], hold[j] + cur); // 当前卖出 + 上一次的买入
                hold[j] = max(hold[j], sell[j - 1] - cur); // 当前买入  + 上一次的卖出
            }
        }

        return sell[k];
    }
};

思路二

转载:Code_Ganker
原文地址:
http://blog.csdn.net/linhuanmars/article/details/23236995

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值