天天看點

[每日一題] 147. 買賣股票的最佳時機(數組、數學、動态規劃、頂級解法)

文章目錄

    • 1. 題目來源
    • 2. 題目說明
    • 3. 題目解析
      • 方法一:數學+思維+動态規劃+頂級解法
      • 方法二:動态規劃+巧妙解法
      • 方法三:暴力+正常解法

1. 題目來源

連結:買賣股票的最佳時機

2. 題目說明

給定一個數組,它的第

i

個元素是一支給定股票第

i

天的價格。

如果你最多隻允許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能擷取的最大利潤。

注意你不能在買入股票前賣出股票。

示例 1:

輸入: [7,1,5,3,6,4]

輸出: 5

解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。

注意利潤不能是 7-1 = 6, 因為賣出價格需要大于買入價格。

示例 2:

輸入: [7,6,4,3,1]

輸出: 0

解釋: 在這種情況下, 沒有交易完成, 是以最大利潤為 0。

3. 題目解析

方法一:數學+思維+動态規劃+頂級解法

來自題解區大佬:121. 買賣股票的最佳時機 - dp 7 行簡約風格

[每日一題] 147. 買賣股票的最佳時機(數組、數學、動态規劃、頂級解法)
[每日一題] 147. 買賣股票的最佳時機(數組、數學、動态規劃、頂級解法)

原數組兩個元素的最大差等于求差數組的最大子序和!!!

原數組兩個元素的最大差等于求差數組的最大子序和!!!

原數組兩個元素的最大差等于求差數組的最大子序和!!!

以前好像在哪聽過,又忘記了…忘了就記,就練習,就了解,就吃透。

這個結論簡單推導下就可以得出,比如:一個數組中有 [ a , b , c , d ] [a,b,c,d] [a,b,c,d] 這幾個數,那麼 d d d 與 a a a 的內插補點可以用相鄰兩數的內插補點的最大子序和得出。

f = ( b − a ) + ( c − b ) + ( d − c ) = d − a f=(b−a)+(c−b)+(d−c)=d−a f=(b−a)+(c−b)+(d−c)=d−a

針對最大子數組的動态規劃求解。

參見代碼如下:

// 執行用時 :20 ms, 在所有 C++ 送出中擊敗了20.77%的使用者
// 記憶體消耗 :15.6 MB, 在所有 C++ 送出中擊敗了5.09%的使用者

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() <= 1) return 0;
        vector<int> vt(prices.size() - 1);
        for (int i = 0; i < prices.size() - 1; ++i) 
            vt[i] = prices[i + 1] - prices[i];
        
        vector<int> dp(vt.size());
        dp[0] = max(0, vt[0]);
        int max= dp[0];
        for (int i = 1; i < vt.size(); ++i) {
            dp[i] = max(0, dp[i - 1] + vt[i]);
            max= max(max, dp[i]);
        }
        return max;
    }
};
           

方法二:動态規劃+巧妙解法

針對原問題的動态規劃求解。

d p [ i ] dp[i] dp[i] 表示前 i i i 天的最大利潤,因為我們始終要使利潤最大化,則:

d p [ i ] = m a x ( d p [ i − 1 ] ,    p r i c e s [ i ] − m i n p r i c e ) dp[i] = max(dp[i-1], \ \ prices[i]-minprice) dp[i]=max(dp[i−1],  prices[i]−minprice)

參見代碼如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) return 0; // 邊界條件
        int minprice = prices[0];
        vector<int> dp (n, 0);

        for (int i = 1; i < n; i++){
            minprice = min(minprice, prices[i]);
            dp[i] = max(dp[i - 1], prices[i] - minprice);
        }
        return dp[n - 1];
    }
};
           

方法三:暴力+正常解法

兩次循環,暴力解法。時不時會

TLE

// 執行用時 :1820 ms, 在所有 C++ 送出中擊敗了20.77%的使用者
// 記憶體消耗 :14.1 MB, 在所有 C++ 送出中擊敗了5.09%的使用者
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = (int)prices.size(), ans = 0;
        for (int i = 0; i < n; ++i){
            for (int j = i + 1; j < n; ++j){
                ans = max(ans, prices[j] - prices[i]);
            }
        }
        return ans;
    }
};