這原本是一個網友提的問題,我作了很詳細的回答。結果被爬蟲網站爬過去當作文章了。因而整理了一下,發表成文章吧。php
題目是這樣的:算法
給定數組n,包含n天股票的價格price. 一我的一共最多能夠買2手股票,但在第一手股票賣出前不能買入第二手股票。若是不買,收益爲0.假設每手只買1股。計算這我的最大收益。 輸入:[3,8,5,1,7,8] 輸出:12
當時正在Starbucks寫網站,因而就順手寫了以下的代碼:數組
<?php function getMaxProfilt(array $arr) { $len = count($arr); $array_tmp = array(); echo '輔助數組:', '<br />'; for($i = 0; $i < $len; $i++) { for($j = 0; $j < $len; $j++) { $array_tmp[$i][$j] = $arr[$j] - $arr[$i]; echo $array_tmp[$i][$j] . ' '; } echo '<br />'; } $maxProfit_i = 1; $maxProfit_j = 2; $maxProfit = $array_tmp[1][2]; for($i = 1; $i < $len; $i++) { for($j = 2; $j < $len; $j++) { if($array_tmp[$i][$j] > $maxProfit && $j > $i) { $maxProfit = $array_tmp[$i][$j]; $maxProfit_i = $i; $maxProfit_j = $j; } } } echo 'maxProfit is :', $maxProfit, '; maxProfit_i is:', $maxProfit_i, '; maxProfit_j is :', $maxProfit_j, '<br />'; $secondProfit = $array_tmp[0][1]; $secondProfit_i = 0; $secondProfit_j = 1; for($i = 0; $i < $maxProfit_i; $i++) { //這裏控制第二手買入要在第一手賣出的狀況下才能買入 for($j = 1; $j < $maxProfit_i; $j++) { if($array_tmp[$i][$j] > $secondProfit && $j > $i) { $secondProfit = $array_tmp[$i][$j]; $secondProfit_i = $i; $secondProfit_j = $j; } } } echo 'second profit is : ', $secondProfit, '; secondProfit_i is :', $secondProfit_i, '; secondProfit_j is :', $secondProfit_j, '<br />'; return $maxProfit + $secondProfit; } // $array = [3, 8, 5, 1, 7, 8]; // $array = [1,2,3,4,5,6,7,8]; $array = [2,9,1,9,2,4,8,6,2]; echo getMaxProfilt($array);
如下是思路:網站
爲了方便理解,我畫了張圖,以下:spa
定義參數數組爲array
;code
一開始我把問題想的很簡單,覺得只要把兩個最大收益相加就行,由於你有一個條 件,第一手沒有賣出前不能買入第二手。麻煩的就是這裏,因此一開始寫代碼的時候才發現仍是有點複雜。因此用到了二維數組用來控制條件:第二手買入前要賣出第一手;圖片
圖上能看到二維數組的元素都來自於array
後面的數減去其前面的數,並且只有右上方纔是真正的收益,假設x軸方向元素下標爲j
,y軸方向元素下標爲i
.即有效的收益第一條件爲:j>i
;rem
有一個很關鍵的問題要明白,明白這個以後,後面的就好理解了,以下:get
小明在股價3元的時候買入,在第一個8元的時候賣出,獲得收益5元,這時候,他就永遠不會獲得5元后面的收益,即2,-2,4,5。可是能獲得5的右下角(不包括5所在的行和列)的收益。咱們把這個例子叫作有效收益原則,後面會用到。it
很明顯圖中最大的收益是6和7,可是這違反了有效收益原則。
根據有效收益原則逆推,若是咱們能肯定最大收益的位置,即7的位置,咱們就能把兩個有效最大收益的範圍縮小,一個是7,另外一個在7(不包括7的行和列)的左上角。因此我在獲得輔助數組後就先找到了7的位置。之因此從-3開始找,是爲了排除第一個5是最大收益的狀況。
獲得了兩個最大收益的範圍,就差最後一個且最重要的條件了:第二手買入必須在第一手賣出以後。
我仍是舉例來講明,根據圖片咱們知道最大收益是7,想要獲得7,第一手就必須在股票價格爲1的時候賣出第一手股票,而後當即買入。或者股票價格爲1的時候第一手股票已經賣出。而7的下標(從0開始)爲i=3,j=5
.根據有效收益原則,第二大的收益的範圍就縮小到i=j=3
的左上角了。知道了範圍,代碼中第三個雙重循環就能找到第二大的收益了。
總體的過程就是這樣了。不過尚未去分析過複雜度,有興趣的朋友能夠試一試。若是有更好的算法歡迎交流。