每日算法-1 买卖股票的最佳时机 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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii

解法:

一、暴力搜索

根据题意:因为不限制交易次数,在每一天,可以根据当前是否持有股票选择相应的操作。“暴力搜索” 也叫 “回溯搜索”、“回溯法”,首先来个示例。

[7,1,5,3,6,4]

第一次循环,第 i 天股票价格=7,第 (i+1) 天股票价格=1,当前买的股票价格为0,最大利润为0,不买入(因为第i天股票价格>第(i+1)天股票价格,并且当前没有买股票

第二次循环,第 i 天股票价格=1,第 (i+1) 天股票价格=5,买入*(因为第i天股票价格<第(i+1)天股票价格,并且当前没有买股票)*

第三次循环,第 i 天股票价格=5,第 (i+1) 天股票价格=3,卖出(因为第i天股票价格>第(i+1)天股票价格,并且当前买了股票)(收益增加:第i天股票价格 - 买时的股票价格)

第四次循环,第i天股票价格为3,第 (i+1) 天股票价格为6,买入*(因为第i天股票价格<第(i+1)天股票价格,并且当前没有买股票)*

第五次循环,第i天股票价格为6,第(i+1)天股票价格为4,卖出(因为第i天股票价格>第(i+1)天股票价格,并且当前买了股票)(收益增加:第i天股票价格 - 买时的股票价格)

第六次循环,因为第(i+1)天股票不存在,判断当前是否有买入股票,那么有的话直接卖出


由此,我们可以使用foreach循环,写出下面的代码:
class Solution
{
    
    

    /**
     * @param Integer[] $prices
     * @return Integer
     */
    function maxProfit($prices)
    {
    
    
        //赚的钱 初始值为0
        $income = 0;
        $currentPrice = 0;
        //当前买入的价格$current_price=0
        foreach ($prices as $k => $price) {
    
    
            //如果是最后1天,直接跳过
            if (!isset($prices[$k + 1])) {
    
    
                if ($currentPrice > 0) {
    
    
                    $income += $price - $currentPrice;
                }
                continue;
            }

            //如果 第i天的价格>第(i+1)天的价格 并且 当前current_price==0
            if ($price < $prices[$k + 1] && $currentPrice === 0) {
    
    
                // 第i天买入,记录current_price=第i天的价格
                $currentPrice = $prices[$k];
            } elseif ($price > $prices[$k + 1] && $currentPrice > 0) {
    
    
                //如果 第i天的价格<第(i+1)天的价格 并且当前买入了
                // 第i天卖出,赚的钱+=第i天的价格-current_price
                $income += $price - $currentPrice;
                $currentPrice = 0;
            }
        }
        return $income;
    }
}

对于数组[7,1,5,3,6,4]无疑是能够获得正确结果 7 的。

不过,算法就是这么的不符合实际,给了这么个数组

[2, 1, 2, 0, 1]

没办法,题目说了0 <= prices[i] <= 10 ^ 4,股票是存在0元的情况的,题目是大爷,听他的来。

修改一下,使用false来代表没有买入股票。


版本1:

class Solution
{
    
    

    /**
     * @param Integer[] $prices
     * @return Integer
     */
    function maxProfit($prices)
    {
    
    
        //赚的钱 初始值为0
        $income = 0;
        $currentPrice = false;
        //当前买入的价格$current_price=0
        foreach ($prices as $k => $price) {
    
    
            //如果是最后1天,直接跳过
            if (!isset($prices[$k + 1])) {
    
    
                if ($currentPrice !== false) {
    
    
                    $income += $price - $currentPrice;
                }
                continue;
            }

            //如果 第i天的价格>第(i+1)天的价格 并且 当前current_price==0
            if ($price < $prices[$k + 1] && $currentPrice === false) {
    
    
                // 第i天买入,记录current_price=第i天的价格
                $currentPrice = $prices[$k];
            } elseif ($price > $prices[$k + 1] && $currentPrice !== false) {
    
    
                //如果 第i天的价格<第(i+1)天的价格 并且当前买入了
                // 第i天卖出,赚的钱+=第i天的价格-current_price
                $income += $price - $currentPrice;
                $currentPrice = false;
            }
        }
        return $income;
    }
}

版本1

什么?战胜18.78%?不行,改改再来

思路:

  1. 慢的可能性有哪些呢?foreach运行效率较低。改用while来试一试。
  2. 内存使用能否再缩短?$currentPrice占了一小块内存,既然股票是一个数组,那改成存储数组下标来标识当前买入的股票。

版本2:

class Solution
{
    
    

    /**
     * @param Integer[] $prices
     * @return Integer
     */
    function maxProfit($prices)
    {
    
    
        //赚的钱 初始值为0
        $i = 0;
        $income = 0;
        $currentPricePos = false;
        //当前买入的价格$current_price=0
        while (true) {
    
    
            if (!isset($prices[$i + 1])) {
    
    
                if ($currentPricePos !== false) {
    
    
                    $income += $prices[$i] - $prices[$currentPricePos];
                }
                break;
            }
            if ($currentPricePos === false && $prices[$i] < $prices[$i + 1]) {
    
    
                $currentPricePos = $i;
            } elseif ($prices[$i] > $prices[$i + 1] && $currentPricePos !== false) {
    
    
                $income += $prices[$i] - $prices[$currentPricePos];
                $currentPricePos = false;
            }
            $i++;
        }
        return $income;
    }
}

版本2

这个效率还差不多。搜索算法的效率也大概就到这里,那有没有其他算法能够更好提高效率呢?

二、贪心算法

这道题使用贪心算法的流程是这样的:

从第 i 天(这里 i >= 1)开始,与第 i - 1 的股价进行比较,如果股价有上升(严格上升),就将升高的股价( prices[i] - prices[i- 1] )记入总利润,按照这种算法,得到的结果就是符合题意的最大利润。

下面对这个算法进行几点说明:

1、该算法仅可以用于计算,但计算的过程并不是真正交易的过程,但可以用贪心算法计算题目要求的最大利润。下面说明这个等价性:以 [1, 2, 3, 4] 为例,这 4 天的股价依次上升,按照贪心算法,得到的最大利润是:

$res = ($prices[3] - $prices[2]) + ($prices[2] - $prices[1]) + ($prices[1] - $prices[0]) = $prices[3] - $prices[0];

写成代码如下:

/**
     * @param Integer[] $prices
     * @return Integer
     */
    function maxProfit($prices)
    {
    
    
        $income = 0;
        for ($i = 1; $i < count($prices); $i++) {
    
    
            $temp = $prices[$i] - $prices[$i - 1];
            if ($temp > 0) {
    
    
                $income += $temp;
            }
        }
        //当前买入的价格$current_price=0
        return $income;
    }

版本3

这运行效率,杠杠的。


最后给大家安利下算法题来源好网站:力扣

来一起学学算法吧!

猜你喜欢

转载自blog.csdn.net/weixin_38125045/article/details/106899074