题目
给定一个整型数组,它的第i个元素是一支给定股票第i天的价格。如果最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7, 1, 5, 3, 6, 4]
输出: 5
解释: 在第2天(股票价格=1)的时候买入,在第5天(股票价格=6)的时候卖出,最大利润为6-1=5。
注意:利润不能是7-1=6, 因为卖出价格需要大于买入价格;同时,不能在买入前卖出股票。
示例 2:
输入: [7, 6, 4, 3, 1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为0。
暴力法
暴力法的基本思想是尝试数组中每一种可能的买卖组合,即先遍历每一个可能的买入日子,然后对于每一天,再遍历之后的所有日子寻找卖出的最佳时机。这样可以确保找到每一种可能的利润,并从中选取最大值。使用暴力法求解本题的主要步骤如下。
1、遍历数组中的每个元素作为买入的候选日。
2、对于每个买入日,从该日之后继续遍历数组,寻找卖出日,计算潜在的利润。
3、保存并更新到目前为止找到的最大利润。
4、遍历结束后,返回最大利润。
根据上面的算法步骤,我们可以得出下面的示例代码。
def stock_trading_brute_force(prices):if not prices:return 0max_profit = 0for i in range(len(prices)):for j in range(i + 1, len(prices)):profit = prices[j] - prices[i]if profit > max_profit:max_profit = profitreturn max_profitprint(stock_trading_brute_force([7, 1, 5, 3, 6, 4]))
迭代法
迭代法,也称为循环法,是通过重复执行一段代码块(循环体)来逐步推进问题解决的过程。对于该问题,迭代法的思路非常直观:我们只需要遍历一次股票价格数组,同时追踪到目前为止遇到的最低价格和基于这个最低价格所能获得的最大潜在利润。通过这种方式,我们可以在遍历的过程中实时更新最大利润,最终遍历完成后得到的结果就是最大可获得的利润。使用迭代法求解本题的主要步骤如下。
1、初始化。设置两个变量,min_price 初始化为数组第一个元素,表示目前观察到的最低股票价格。max_profit 初始化为0,表示目前的最大利润。
2、遍历数组。从数组的第二个元素开始遍历,直到数组末尾。
(1)计算潜在利润。对于每个遍历到的股票价格,计算当前价格与min_price的差值,作为潜在的利润。
(2)更新最低价格。如果当前价格比已知的最低价格还要低,则更新min_price。
(3)更新最大利润。如果计算出的潜在利润大于当前的max_profit,则更新max_profit为这个更大的利润值。
3、返回结果。遍历结束后,max_profit即为在整个遍历过程中可以获取的最大利润。
根据上面的算法步骤,我们可以得出下面的示例代码。
def stock_trading_iteration(prices):min_price = prices[0]max_profit = 0for price in prices[1:]:min_price = min(min_price, price)max_profit = max(max_profit, price - min_price)return max_profitprint(stock_trading_iteration([7, 1, 5, 3, 6, 4]))
总结
使用暴力法时,外层循环遍历每个元素作为买入日,内层循环则从该日起遍历之后的每个元素作为卖出日,故总的时间复杂度是O(n^2),其中n是数组的长度。
迭代法只进行了一次遍历,故总的时间复杂度是O(n),其中n是数组的长度。这是一种比较高效的解法,特别是相比于最初的暴力解法,它在处理大数据集时能显著提高效率。