作业题目
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
暴力破解
如果我每天每天都买,每天都卖,最后进行对比,我终究能够找到获利最大那天(虽然肯定是亏本)。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
last_day = len(prices)
earn = []
for buy_day in range(0, last_day - 1):
buy_price = prices[buy_day]
for sell_day in range(buy_day+1, last_day):
sell_price = prices[sell_day]
sell_earn = sell_price - buy_price
earn.append(sell_earn)
return max(earn)
直接判断
我关心的只是最高价值,所以
max
。但是这一步我是不是可以在循环中完成,融入流程,就可以省略容器了。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
last_day = len(prices)
max_earn = 0
for buy_day in range(0, last_day - 1):
buy_price = prices[buy_day]
for sell_day in range(buy_day+1, last_day):
sell_price = prices[sell_day]
sell_earn = sell_price - buy_price
if sell_earn > max_earn:
max_earn = sell_earn
return max_earn
买入时机
假如我今天卖,我赚多少具体和什么相关呢?
没毛病,必定和我买入的那天的价格相关,
earn = sell_price - buy_price
。也就是说,今天卖出的话,我必定是以今天之前的最低价格进行买入的。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
last_day = len(prices)
max_earn = 0
min_buy_price = int(1e9)
for buy_day in range(0, last_day - 1):
buy_price = prices[buy_day]
if buy_price < min_buy_price:
min_buy_price = buy_price
for sell_day in range(buy_day+1, last_day):
sell_price = prices[sell_day]
max_sell_earn = sell_price - min_buy_price
if max_sell_earn > max_earn:
max_earn = max_sell_earn
return max_earn
当前状态
前面已经做了这么一个操作:将最后的比对融入到每次循环中,丢弃容器
现在也有一个问题,那就是我们今天要做什么。
整道题的思路,然我们以为这是必要的:在之前的某一天买入,在后面的某一天卖出
但是,这一天到底是哪天,这是不确定的。
就是这个原因,导致我们必须标记买入的那一天,然后再标记卖出的那一天。
现在,就决定今天的事情吧,我要卖出还是买入
如果我今天要买入,那么,今天的价格必定比以前的价格要低
today_price < before_min_price
如果我今天要卖出,那么,今天的收益必定比以前的收益要搞
today_earn > before_max_earn
更有意思的是,我们并非要买入才面临卖出,如果我们买了一个垃圾股,每天都面临卖出。
我们在第一天并非就只能买入,就这样,每天都是今天,每天我们都要思考。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
before_max_earn = 0
before_min_price = int(1e9)
for today_price in prices:
today_earn = today_price - before_min_price
if today_earn > before_max_earn:
before_max_earn = today_earn
if today_price < before_min_price:
before_min_price = today_price
return before_max_earn
总是说某一天,这表示时间是受我们管控的。
我们选择的是管理时间,但是我觉得还有一个选择,那就是回到过去。
伴随容器是一个浪费的操作,但是我觉得它告诉了我们一个隐含的真理:我们是可以在多个时间中进行选择的
回顾一下当时的操作:
- 每天都进行买入
- 每天都进行卖出
- 计算每天的收益
- 选择最高的获利
但是,是什么让我们变得愚蠢。没错,就是因为聪明,自作聪明。
当我们有了更方便的方式,我们就更想直接的获取答案。
不过别忘记一点,我们有更聪明的方式,只能改变我们自己,却改变不了事实本身。
因此,我们的直接,只能针对那些本来就能够直接的事情。
就当前的事情来说,它不能够完全的直接,我们妄想整体的直接,就颠覆了事实本身,脱离最初的目的了。
对于这道题目,错误的思想(对我个人而言),就是明白了哪天该卖出或者买入(if
)。
然后,妄想直接的选定那一天。
最原始,最粗糙,最笨拙的方式中,它每天都是进行买入卖出的。
这在能够判断是否买入卖出的时候的确是显得愚蠢,但是真理(关于这道题)是
就算你什么也不做,也需要过完这一天,过完每一天。
只有全部经历完成,你才能评定,才能选定获利最高的那一天。
关于递归
递归是计算自身,但是它之所以方便,不是它本身,而是一种思想:拆解,分而治之。
将庞大的东西按照最小的组织关联起来
最近喜欢上了闭包这个东西,没错,可以将递归看做是一种闭包。
每次的递归的深入,都是一个拆包的过程,每一次递归的回溯,就是包的组织过程。
- 先将复杂的东西拆解为简单的东西,进行计算
- 然后将简单的计算结果,再层级的组合成为复杂的东西
让人惊叹的是,它的简单计算和开闭过程是如此的简单,就是这么简单的规则,可以构成无限的复杂。
尤为重要的是,它拆解之后,每个分支的无关性,每个小包,都是如此的独立,无怪乎能够进行简单计算。
自圆满,无依赖,或者可以拆解为更细的闭包,范围不溢出,又是它本质的一种。
代码修饰
或者,这个代码还能更短小一些
class Solution:
def maxProfit(self, prices: List[int]) -> int:
before_max_earn = 0
before_min_price = int(1e9)
for today_price in prices:
before_max_earn = max(before_max_earn, today_price - before_min_price)
before_min_price = min(before_min_price, today_price)
return before_max_earn
再进一步
按照这个思路,还能够再进一小步
- 有必要每天计算收益,然后对比么
可见的是,如果买入价格是一定的,我们要想收益更高,应该卖的更贵。
只有超过了原来更高的卖出价格,才有必要进行卖出。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
before_max_earn = 0
before_min_price = int(1e6)
before_max_sell_price = 0
for today_price in prices:
if today_price > before_max_sell_price or today_price < before_min_price:
before_max_sell_price = today_price
today_earn = today_price - before_min_price
if today_earn > before_max_earn:
before_max_earn = today_earn
if today_price < before_min_price:
before_min_price = today_price
return before_max_earn
当然,如果存在买入,对比的卖出价格是以买入价格为准的,需要进行更新。