每日一道 LeetCode (31): 买卖股票的最佳时机 II

极客挖掘机

共 842字,需浏览 2分钟

 ·

2020-08-29 07:56

每天 3 分钟,走上算法的逆袭之路。

前文合集

每日一道 LeetCode 前文合集

代码仓库

GitHub:https://github.com/meteor1993/LeetCode

Gitee:https://gitee.com/inwsy/LeetCode

题目:买卖股票的最佳时机 II

题目来源:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

  • 1 <= prices.length <= 3 * 10 ^ 4
  • 0 <= prices[i] <= 10 ^ 4

解题思路

这道题看到第一眼就觉得自己会做,果然写完了以后自己确实会做。

从题目上来看,股票有起起落落,但是如果你真的做过交易的话,就会明白,在一段时间内,想要利润最大化,那就是吃掉所有的涨幅。

怎么说呢?因为做题嘛,是上帝视角,我们都已经知道了一只股票的涨跌了,那就是只要有涨就买,跌了就不买。

转化成算法就是第一天只要比第二天高,那就第一天买入第二天再卖出,如果第三天接着涨,那就第二天卖出以后接着买入,第三天再卖出,直到遇到第 n + 1 天小于第 n 天,那么我们就不再操作了。

因为这是题目,所以可以这么干,我国的股票交易是 T + 1 的,实际上并不可能这么操作,想想就好了。

思路这么清晰了,代码实际上也就出来了:

public int maxProfit(int[] prices) {
    int maxProfit = 0;

    for (int i = 1; i < prices.length; i++) {
        if (prices[i] > prices[i - 1]) {
            maxProfit += prices[i] - prices[i - 1];
        }
    }

    return maxProfit;
}

耗时还可以对吧,至少比昨天的那个 300 多毫秒要好到不知道哪里去了,接下来看看答案,有啥更好的解法。

解题方案一:暴力法

说实话,这道题我没用暴力解法去解,属实是因为暴力解法不是很好写,但是架不住答案送上门来了,我就抄抄看。

public int maxProfit_1(int[] prices) {
    return calculate(prices, 0);
}

public int calculate(int prices[], int s) {
    if (s >= prices.length)
        return 0;
    int max = 0;
    for (int start = s; start < prices.length; start++) {
        int maxprofit = 0;
        for (int i = start + 1; i < prices.length; i++) {
            if (prices[start] < prices[i]) {
                int profit = calculate(prices, i + 1) + prices[i] - prices[start];
                if (profit > maxprofit)
                    maxprofit = profit;
            }
        }
        if (maxprofit > max)
            max = maxprofit;
    }
    return max;
}

这段代码光说看的话,还是比较好理解的,但是要说让我自己写的话,还真的挺困难的,不过耗时超出我是真的第一次见,是我见识少,我错了。

解题方案二:峰谷法

这个方案跟我一开始的方案有点像,我把官方答案的图借过来用下:

这个算法的思路是寻找每一次的峰和谷,在这个之间的就是我们的利润。

先看下代码:

public int maxProfit_2(int[] prices) {
    int i = 0;
    int valley = prices[0];
    int peak = prices[0];
    int maxprofit = 0;
    while (i < prices.length - 1) {
        while (i < prices.length - 1 && prices[i] >= prices[i + 1])
            i++;
        valley = prices[i];
        while (i < prices.length - 1 && prices[i] <= prices[i + 1])
            i++;
        peak = prices[i];
        maxprofit += peak - valley;
    }
    return maxprofit;
}

这个算法先定义了峰 peak 和谷 valley ,然后先在最外层开始循环整个数组,然后在内层加了两个循环。

在外层的一次循环中,第一个循环先找出来谷 valley ,只要是谷就赋值给 valley ,然后在接着找峰,找到峰就赋值给 peak ,最后把这个利润赋值加到 maxprofit 上面去,然后进入下一次循环。

值得注意的是:这里面外层循环的 i 并不一定是每循环一次都只加 1 ,完全看里面两个循环会把 i 加到多少。

今天这道题,我倒是觉得只有暴力法的那段代码是最难写的。



感谢机械工业出版社华章科技的大力支持

当当实付满200-40优惠码:TZSEAM

叠加每满100减50活动,

实现花160买400的书!

有效期:8月24日至9月6日

下周一开始可用,提前选书放购物车啦


感谢阅读



浏览 50
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报