1. 程式人生 > >LintCode 買賣股票的最佳時期I II III 之Python 程式碼

LintCode 買賣股票的最佳時期I II III 之Python 程式碼

假設你有一個數組,它的第i個元素是一支給定的股票在第i天的價格。設計一個演算法來找到最大的利潤。
I:如果你最多隻允許完成一次交易。
II:你可以完成儘可能多的交易(多次買賣股票)。
III:你最多可以完成兩筆交易。

買賣股票的最佳時期I

(I)簡單粗暴的思路:雙指標遍歷所有情況,選擇最大利潤。時間複雜度O(n2)
程式碼如下:

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices)
:
# write your code here result = 0 for i in range(len(prices)-1): for j in range(i + 1, len(prices)): result = max(result, prices[j] - prices[i]) return result #The shortest running time is about 1500ms.

(II)動態規劃:選取最小的價格購買,保留最大的利潤。只需一次遍歷。時間複雜度O

(n)
程式碼如下:

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        # if len(prices) < 2:return 0
        if prices is None or len(prices) == 0:
            return 0
        Begin_value = prices[0
] result = 0 #初始化結果為0 for p in prices: result = max(result, p-Begin_value) Begin_value = min(Begin_value, p) return result

買賣股票的最佳時期II

有 I 的基礎,這題便不難。只買漲的,不買跌的。
程式碼如下:

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        if prices is None or len(prices) < 2:
            return 0
        result = 0
        Begin_value= prices[0]
        for p in prices:
            if p > Begin_value:
                result += p-Begin_value  #漲股利潤累加
                Begin_value = p          #重新買股
            else:
                Begin_value = min(Begin_value, p)
        return result

買賣股票的最佳時期III

解法一:

同 I 題最初的思路,簡單粗暴:做一個遍歷prices的指標index,將prices分成2部分,再分別算出2個部分的最大利潤並返回其和的最大值,即為題設結果。時間複雜度O(n2)
程式碼如下:

def maxProfit(self, prices):
        # write your code here
        if prices is None or len(prices) < 2:
            return 0
        result = 0
        def Solve(part):
            if part is None or len(part) == 0:
                return 0
            Min = part[0]
            res = 0
            for p in part:
                res = max(res, p-Min)
                Min = min(Min, p)
            return res

        for i in range(len(prices)-1):
            one = prices[:i]
            two = prices[i:]
            result = max(result, (Solve(one) + Solve(two)))
        return result 

解法二:

考慮到最多隻能交易兩次,我們先考慮交易一次,得到當次最大利潤,再討論第二次交易的情況。對於prices陣列list,不妨設該次開始交易的指標為begin,賣出當前股票時指標為stop,那麼整個list就被begin、stop指標分為3個part,其中我們在第一次交易時已求得part_2最大利潤值。對於第二次交易,有三種情況,即可能處於part_1或part_2或part_3中。

(i)如果是part_1,則返回part_1及part_2最大利潤的和;
(ii)如果是part_2,類似’N’型的折線,結果應當是第一次交易的最大利潤加上兩次極值轉折跌價的差值
而兩次極值轉折跌價的差值實際是part_2倒序的最大利潤值,也就是程式碼中Solve函式引數 t = -1 的情況;
(iii)如果是part_3,則返回part_2及part_3最大利潤的和。
最後在選取上述三種情況的最大值。

相比 I 題,我們只需在求解最大利潤的同時找到其開始買入(begin)以及賣出股票(stop)的list指標,在分別算出3個part的最大利潤,最後返回題設的最大利潤。

class Solution:
    """
    @param prices: Given an integer array
    @return: Maximum profit
    """
    def maxProfit(self, prices):
        # write your code here
        if prices is None or len(prices) < 2:
            return 0
        def Solve(part, t):
            if t == -1:
                part = part[::-1]
            if part is None or len(part) < 2:
                return 0
            Begin_value = part[0]
            result = 0
            for p in part:
                result = max(result, p-Begin_value)
                Begin_value = min(Begin_value, p)
            return result

        begin, index, stop = 0, 0, 1    #開始買入指標,臨時指標,結束賣出指標
        Sum, Max = 0, 0
        for i in range(len(prices)-1):
            Sum += prices[i+1]-prices[i]
            if Sum > Max:
                Max = Sum
                stop = i + 1
                begin = index
            Sum = max(0, Sum)
            if Sum == 0:
                index = i + 1
        part_1 = Max + Solve(prices[:begin], 1)
        part_2 = Max + Solve(prices[begin:stop+1], -1)if Max > 0 else 0
        part_3 = Max + Solve(prices[stop+1:], 1)
        #part_2中的判斷語句是因為可能出現part_2最大利潤Max為0,即遞減陣列,而第二次交易又在此part,第二次的最大利潤>0,矛盾。
        return max(part_1, part_2, part_3)

當然還另有終極版本的,也就是找出至多交易k次的最大利潤。
參考[Code Ganker的部落格]動態規劃結合遞推求解。(http://blog.csdn.net/linhuanmars/article/details/23236995)
目前想到一個劃分合併的方法,不過細節處理有些複雜,還得細細考慮優化演算法來處理這些細節。佔個坑,以後想到了再補充。