有這麼一道小面試算法題:給定一個長度爲 n 的整數數組,下標爲 i 的元素表示第 i 天某個股票的價格,每次最多持有一股,每次買賣最多一股,在最多隻買賣一次的狀況下(先買後賣,不考慮融券等複雜形式),最大的收益是多少。面試
先考察一下可能的數據:算法
0 1 2 3 4 5 6 7 12 9 6 10 8 22 20 15
因爲是先買後賣,從數據上看,是在 2 處買入,5 處賣出時,獲得收益爲 16 最大。數組
而在股票一直下跌的狀況下,不買不賣,獲得的收益爲 0 最大。優化
o(n^2)
直觀算法code
最簡單的思路,就是從前向後逐個計算收益,求最大收益,以下:it
price[n] max_profit = 0 for i = 0...n-2: for j = i+1...n-1: profit = price[j] - price[i] if profit > max_profit: max_profit = profit
這個算法的複雜度爲 o(n^2)
,能不能繼續優化?基礎
o(n)
算法數據
用概括法分析一下,在第 n-1 天時,最大收益爲 max_profit ,其中最小的價格爲 min_price,那麼第 n 天時,最大的收益計算爲:co
if price[n] - min_price > max_profit: max_profit = price[n] - min_price
所以,可把算法改成:
price[n] max_profit = 0 min_price = price[0] for i = 1...n-1: profit = price[i] - min_price if profit > max_profit: max_profit = profit if min_price > price[i]: min_price = price[i]
變化爲 o(n)
複雜度。
推廣變化
如今,考慮更加複雜的形式,先來個容許不限次數的買賣,那麼,在每個遞增的子區間,都能獲得收益,總收益爲各個收益的和:
price[n] sum_profit = 0 for i = 1...n-1: profite = price[i] - price[i-1] if profite > 0: sum_profit += profit
再複雜一點,容許進行融券形式(即容許從券商借出後先賣後買),一樣限制最多持有或融入 1 股,在結束前使得手上股票數爲 0 。這種規則下,股票價格升降都會獲得收益,總收益爲:
price[n] sum_profit = 0 for i = 1...n-1: profite = price[i] - price[i-1] if profite < 0: sum_profite += -profite else: sum_profite += profite
在此基礎上,還能夠放開一些限制條件,如不限制持有的數量等等。更進一步,可設定一個收益目標,符合收益目標的買賣組合,這樣就更加現實意義有意思了。