Leetcode--买卖股票的最佳时机总结

Leetcode121 Best Time to Buy and Sell Stock (至多一笔交易)

(https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)
详细题解: https://www.acwing.com/solution/LeetCode/content/214/

题目描述
假设你有一个数组,其中第i个元素表示第i天某个股票的价格。
如果您只允许完成**至多一笔交易**(即买入一只股票并卖出一只股票),则设计一种算法以找到最大利润。
必须先购买股票再出售股票。

样例
Example 1:

输入: [7,1,5,3,6,4]
输出: 5
解释: 在第二天买(price = 1) ,在第五天卖 (price = 6), 利润 = 6-1 = 5.

思路:
贪心算法
扫描一遍,每次更新最大利润和最低价格即可。

代码:

int maxProfit(vector<int>& prices) {
        if (!prices.size()) return 0;
        int len = prices.size();
        int minv = INT_MAX;
        int res = 0;
        for (int i = 0; i < len; i++){
            res = max(res, prices[i] - minv);
            minv = min(minv, prices[i]);
        }
        return res;
}

LeetCode 122. Best Time to Buy and Sell Stock II (不限次交易)

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
详细题解: https://www.acwing.com/solution/LeetCode/content/261/

假设你有一个数组,其中第i个元素表示第i天某个股票的价格。
设计一种算法以找到最大利润,可以完成**任意多次交易**,但必须先购买股票再出售股票,不能同时多次交易。

样例
Example 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 第二天买(price = 1),第三天卖(price=5),利润为4;
第四天买(price = 3),第五天卖(price=6),利润为3。

思路1:
 贪心算法
遍历一次数组,低进高出,把所有上升区间的价格差相加起来就是最终利润。
可以拆分成以下几种情况,
递增,如[1,2,3],那么1买3卖 与 每天都买入卖出 等价
递减,如[3,2,1],赚钱是赚不了的
先高再低,如[1,3,2],那么只能在1买3卖捞一笔
先低再高,如[2,1,3],那么同样只能在1买3卖捞一笔
短数组的情况可以推广到所有数组。

代码:

int maxProfit(vector<int>& prices) {
        int ans = 0;
        int len = prices.size();
        for (int i = 1; i < len; i++){
            if (prices[i] > prices[i - 1])
                ans += prices[i] - prices[i - 1];
        }
        return ans;
    }
思路2:
动态规划
记录两个状态: g[i]表示第i天,当前不持有股票的最大收益;f[i]表示第i天,当前持有股票的最大收益。
状态转移为:
g[i] = max(g[i - 1], f[i - 1] + prices[i]),
f[i] = max(f[i - 1], g[i - 1] - prices[i]).
初始化: f = INT_MIN, g = 0  //初始化要仔细考虑
最终答案为f[n - 1],即最后一天不持有股票的最大收益。
优化
注意到状态转移之和前一层有关,故可以优化掉第一维。
每次提前取出前一层的值,用其更新为新的值即可。

代码:

int maxProfit(vector<int>& prices) {
        if(!prices.size()) return 0;
        int len = prices.size();
        int f = INT_MIN; // 持股  //初始化要仔细考虑一下
        int g = 0; // 不持股
        for(int i = 0; i < len; i++){
            int newf = max(f, g - prices[i]);
            int newg = max(g, f + prices[i]);
            f = newf;
            g = newg;
        }
        return g;
    }

LeetCode 123. Best Time to Buy and Sell Stock III (最多两次交易)

(https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/)
详细题解: https://www.acwing.com/solution/LeetCode/content/219/

题目描述
假设你有一个数组,其中第i个元素表示第i天某个股票的价格。
设计一种算法以找到最大利润,可以完成**最多两次交易**(一买一卖算一次交易),但必须先购买股票再出售股票,不能同时多次交易。

样例
Example 1:
输入: [3,3,5,0,0,3,1,4]
输出: 7
解释: 第四天买(price = 0),第六天卖(price=3),利润为3;
第七天买(price = 1),第八天卖(price=4),利润为3。

思路:
算法1 动态规
在整个区间的每一点切开, 然后分别计算左子区间和右子区间的最大值,然后再用O(n)时间找到整个区间的最大值。
遍历一遍数组,求[0,i−1][0,i−1]区间的最大利润f(i)f(i),具体做法是找当前最低价格low,判断是要以low买入当天卖出,还是不动
从后往前遍历,求[i,n−1][i,n−1]区间的最大利润g(i)g(i),具体做法是找当前最高价格high,判断是要当天买入以high卖出,还是不动
遍历,求最大利润max(f(i)+g(i))max(f(i)+g(i))

代码:

int maxProfit(vector<int>& prices) {
        if (!prices.size()) return 0;
        int len = prices.size();
        vector<int> f(len, 0);
        vector<int> g(len, 0);
        int minv = INT_MAX;
        for (int i = 1; i < len; i++){
            f[i] = max(f[i - 1], prices[i - 1] - minv);  // 这里一次max就可以  取从前往后 f 的最大值
            minv = min(minv, prices[i - 1]);
        }
        int maxv = prices[len - 1];
        for (int i = len - 2; i >= 0; i--){   // 注意边界
            g[i] = max(max(0, maxv - prices[i]), g[i + 1]);  //两次max嗷  取从后往前 g 的最大值
            maxv = max(maxv, prices[i]);
        }
        int res = 0;
        for (int i = 0; i < len; i++){
            res = max(res, f[i] + g[i]);
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值