leetcode-數組-簡單-買賣股票的最佳時機

題目

給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。如果你最多隻允許完成一筆交易(即買入和賣出一支股票一次),設計一個算法來計算你所能獲取的最大利潤。注意:你不能在買入股票前賣出股票

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

輸入: [7,1,5,3,6,4]
輸出: 5
解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。
     注意利潤不能是 7-1 = 6, 因爲賣出價格需要大於買入價格;同時,你不能在買入前賣出股票。

輸入: [7,6,4,3,1]
輸出: 0
解釋: 在這種情況下, 沒有交易完成, 所以最大利潤爲 0。

解答

方法一:

我剛一開始分析這個題,覺得題目就是這樣的特徵

  • 找到數組中兩個數的差值最大
  • 後邊的數要比前邊的數大

直接思路就是循環每一個元素,然後拿這個元素前邊的元素和這個數挨個進行差值,找到最大值,返回的時候判斷一下是否大於0

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = prices[1] - prices[0];
        for (int i = 2; i <prices.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (prices[i] - prices[j] > res_max) {
                    res_max = prices[i] -prices[j];
                }
            }
        }
        return res_max > 0 ? res_max : 0;
    }
};

一運行,超出時間限制,看來暴力方法越來越不讓用了。

 可是又不想放棄這個思路,我覺得這個很合理啊,一般第一反應大家都會這麼想吧,爲了得到提交結果,我想暴力方法肯定是多算了不少東西,看看嘗試優化一下。

  • 第一把默認最大值設爲0,這樣不用返回的時候每次進行一次三元運算,而且中間的數據判斷碰到負數也不用進入if內部。
  • 第二因爲每個元素都會把之前的全部計算完一遍差值,那麼在計算下一個元素的時候,如果下一個元素比這個元素小,是沒有計算的必要的,因爲小的話,假設這個元素位置最大差值變了,那麼上一個元素比它大,肯定差值更大,那必然會提前計算出來,這個位置的計算也是沒有必要的。加上這個判斷應該能減少不少循環。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = 0;
        for (int i = 1; i < prices.size(); ++i) {
            ///這種情況不要計算,因爲如果i + 1 產生最大差值,
            ///那麼 i的差值一定更大,肯定提前就計算完成了
            if (prices[i] <= prices[i - 1]) {
                continue;
            }
            for (int j = 0; j < i; ++j) {
                if (prices[i] - prices[j] > res_max) {
                    res_max = prices[i] -prices[j];
                }
            }
        }
        return res_max;
    }
};

果然這種方案沒有超時。 

方法二:

又想了一個方案看看能不能一次循環搞定。

  • 標記一個買點位置,一個賣點位置,然後讓他們移動
  • 賣點位置一定在買點位置後邊
  • 如果出現比買點小的值,那麼應該移動買點
  • 如果出現比賣點大的值,那麼應該移動賣點
  • 每次都計算買點和賣點的差值,就可以找出最大值了
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        //假設差值最大的位置f_n 
        int res_max = prices[1] - prices[0];
        int buy_index = 0, sell_index = 1;
        for (int i = 1; i < prices.size(); i++) {
            // 發現有比買點小的,就移動買點
            if (prices[buy_index] > prices[i]) {
                buy_index = i;
            }
            //發現有比賣點大的 就移動賣點
            if (prices[sell_index] <= prices[i]) {
                sell_index = i;
            }
            if (sell_index < buy_index) {
                //買點移動之後,賣點也要移動
                sell_index = buy_index;
                continue;
            }
            res_max = max(res_max, prices[sell_index] - prices[buy_index]);
        }
        return res_max;     
    }
};

方法三:

看了其他人的方法得到的答案

思路應該大致和方法二相同,不過更簡潔。

  • 記錄最小值,只要最小值有變化就更新最小值。
  • 每一個元素都和最小值相減。比較大小。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = 0;
        int min = prices[0]; //記錄過往的最小值
        for (int i = 1; i < prices.size(); i++) {
            if (prices[i] > min) {
                res_max = max(res_max, prices[i] - min);
            } else {
                min = prices[i];
            }
        }
        return res_max;     
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章