1. 程式人生 > >【算法分析與設計】【第一周】121.Best Time to Buy and Sell Stock&122. Best Time to Buy and Sell Stock II

【算法分析與設計】【第一周】121.Best Time to Buy and Sell Stock&122. Best Time to Buy and Sell Stock II

部分 簡化 是我 -i 復雜 style 代碼 求一個 時間

原題來自:121:https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/

122:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/

第一周,小試牛刀吧。

題目121不復雜,就是英文原題讀起來怪怪的。意思是,在保證先買後賣且最多只能買賣一次的情況下,計算最大利潤。

思路很簡單:逐個求差,差最大且被減數的下標大於減數的下標就可以了。最簡單暴力的方法是用兩重循環:

int maxProfit(int* prices, int
pricesSize) { int max = 0; for (int i = 0; i < pricesSize; i++) { for (int j = i; j < pricesSize; j++) { if (prices[j] - prices[i] > max) { max = prices[j] - prices[i]; } } } return max; }

技術分享

顯然,此算法的時間復雜度為0(n^2)。根據leetcode給出的分析圖,雖然AC,我的方法還有很大的優化空間。

優化的話,思路本質上還是一樣的。就是求一個峰值和谷底值之差,且峰值在谷底值後面。主要是能否想到一個巧妙的方法避開雙重循環,目前還沒想好。

--------------------------------------------------

做完121,發現還有升級版122。122的意思是,在保證先買後賣且在一個買賣周期內最多只能買賣一次的情況下,計算最大利潤。也就是說,賣出之後還可以再進行買入等操作。

這就很有意思了。在沒有買賣次數限制的情況下,同樣是獲得最大利潤,情況可以有多種。一開始我是懵的。第一反應是窮舉,計算出所有能盈利的情況,再進行比較,得到最大利潤。先不說這是個比較浩大的工程量,最重要的是我根本不知道這看似簡單的方法從何下手(ˉ▽ˉ;)...。

後來觀摩了一下討論區,發現一位大牛的做法很有意思。大牛的思路很巧妙,就是逐個相減,差大於零就盈利,把盈利的部分加起來;差小於零就進入往後挪,繼續相減。哇,簡直神奇!把n天切割成n次買賣,每次在第i天買入,第i+1天賣出。只看上升的小段,疊加,忽略下降的小段。

舉個簡單的例子。對於一種情況{4, 1, 2, 3, 5}來說,最佳盈利策略應當是在1的時候買入,5的時候賣出,盈利為4,一手買賣即可。而按照上面的方法,將這一手買賣分解為1買2賣,2買3賣,3買5賣,共盈利4,三次買賣利潤與前面的一手買賣利潤一致,但是解釋起來更加簡便、清晰。

對於另一種情況{4, 1, 3, 2, 5}來說,兩個峰,只看上升的小段,看起來就更加清楚了。

技術分享

這種方法就相當於把長線買賣都簡化成了“如果保證盈利,買了馬上就賣”的小短線模式的疊加,與周五剛剛學過的“分治”思想還真有異曲同工之妙。

代碼實現起來就很簡單了:

int maxProfit(int* prices, int pricesSize) {
    int total = 0;
    for (int i=0; i< pricesSize-1; i++) {
        if (prices[i+1] > prices[i]) total += prices[i+1] - prices[i];
    }
    return total;
}

【算法分析與設計】【第一周】121.Best Time to Buy and Sell Stock&122. Best Time to Buy and Sell Stock II