LeetCode算法練習——動態規劃入門(三)

LeetCode198. 打家劫舍 && LeetCode 面試題 17.16. 按摩師

打家劫舍

你是一個專業的小偷,計劃偷竊沿街的房屋。每間房內都藏有一定的現金,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定一個代表每個房屋存放金額的非負整數數組,計算你 不觸動警報裝置的情況下 ,一夜之內能夠偷竊到的最高金額。

示例 1:

輸入:[1,2,3,1]
輸出:4
解釋:偷竊 1 號房屋 (金額 = 1) ,然後偷竊 3 號房屋 (金額 = 3)。
     偷竊到的最高金額 = 1 + 3 = 4 。

示例 2:

輸入:[2,7,9,3,1]
輸出:12
解釋:偷竊 1 號房屋 (金額 = 2), 偷竊 3 號房屋 (金額 = 9),接着偷竊 5 號房屋 (金額 = 1)。
     偷竊到的最高金額 = 2 + 9 + 1 = 12 。

按摩師

一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鐘數。

示例 1:

輸入: [1,2,3,1]
輸出: 4
解釋: 選擇 1 號預約和 3 號預約,總時長 = 1 + 3 = 4。

示例 2:

輸入: [2,1,4,5,3,1,1,3]
輸出: 12
解釋: 選擇 1 號預約、 3 號預約、 5 號預約和 8 號預約,總時長 = 2 + 4 + 3 + 3 = 12。

這兩題看似不同,實則相同,一個是不能搶劫相鄰的房子,一個是不能連續兩天預約,而起點同樣可以從索引爲0和索引爲1的位置開始。我們得出狀態轉移方程:dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]),dp[i - 2] + nums[i]很容易理解,最後一步完成前的上一次服務爲兩天前的服務/與上一次搶劫的房子相隔一個房子,而dp[i - 1]的含義爲:當我們從索引0位置以題設方式到達i - 1的位置時,同樣可以從索引1位置開始以題設方式到達i終點位置時,故取dp[i - 1]表示該情況。

class Solution {
public:
    int rob(vector<int>& nums) {
    //int massage(vector<int>& nums) {
        int length = nums.size();
        vector<int> dp(length + 1, 0);
        if(length == 0)  return 0;
        if(length == 1) return nums[0];
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]); 
        for(int i = 2; i < length; i++){
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[length - 1];
    }

LeetCode213. 打家劫舍 II

你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都圍成一圈,這意味着第一個房屋和最後一個房屋是緊挨着的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。

給定一個代表每個房屋存放金額的非負整數數組,計算你在不觸動警報裝置的情況下,能夠偷竊到的最高金額。

示例 1:

輸入: [2,3,2]
輸出: 3
解釋: 你不能先偷竊 1 號房屋(金額 = 2),然後偷竊 3 號房屋(金額 = 2), 因爲他們是相鄰的。

示例 2:

輸入: [1,2,3,1]
輸出: 4
解釋: 你可以先偷竊 1 號房屋(金額 = 1),然後偷竊 3 號房屋(金額 = 3)。
     偷竊到的最高金額 = 1 + 3 = 4 。

分析:這個題打家劫舍1的區別在於,房屋是環形的,這意味着,第一個房間和最後一個房間不能同時偷竊。這就意味着,將原來的問題轉化爲兩個子問題:偷竊1 ~ n-1個房間的最大值以及偷竊 2~n 個房間的最大值。最終,取二者的最大值即爲解因此可以對上一個問題進行兩次dp即可。

class Solution {
public:
    int rob(vector<int>& nums) {
        //偷竊1 ~ n-1個房間的最大值以及偷竊 2 ~ n 個房間的最大值。最終,取二者的最大值即爲解。
        int length = nums.size();
        vector<int> dp(length + 1, 0);
        if(length == 0)  return 0;
        if(length == 1) return nums[0];
        dp[0] = nums[0];
        dp[1] = max(nums[0], nums[1]); 
        //1 ~ n-1的最大值
        for(int i = 2; i < length - 1; i++){
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        int res = dp[length - 2];
        //2 ~ n的最大值
        dp[0] = 0;
        dp[1] = nums[1];
        for(int i = 2; i < length; i++){
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return max(res, dp[length - 1]);
    }
};

LeetCode121. 買賣股票的最佳時機 && 劍指 Offer 63. 股票的最大利潤

給定一個數組,它的第 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。

核心思路是用當前價格減去之前最小的價格,即記錄當前索引最大利潤的dp[i] = price[i] - min{price[0] ~ price[i - 1]},怎麼來表示這個 min{price[0] ~ price[i - 1]}呢——將設置初值爲dp[1] = prices[1] - prices[0],我們會巧妙地發現:

  • dp[2] = price[2] - min(price[1] - dp[1], price[1]),問題轉換成dp[2] = price[2] - min(price[0], price[1])
  • dp[3] = price[3] - min(price[2] - dp[2], price[2]),問題轉換成dp[3] = price[3] - min(min(price[0], price[1]),price[2])
  • 以此類推加入循環後dp[i] = prices[i] - min(prices[i - 1] - dp[i - 1], prices[i - 1])就表示爲dp[i] = price[i] - min{price[0] ~ price[i - 1]}
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int length = prices.size();
        if(length <= 1) return 0;
        vector<int> dp(length + 1, 0);
        dp[1] = prices[1] - prices[0];
        int res = max(0, dp[1]);
        for(int i = 2; i < length; i++){
            //dp[i] = price[i] - min{price[0] ~ price[i - 1]}
            dp[i] = prices[i] - min(prices[i - 1] - dp[i - 1], prices[i - 1]);
            res = max(res, dp[i]);
        }
        return res;
    }
};

 

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