leetcode:按摩師

題目來源:力扣

題目介紹:

一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鐘數。
注意:本題相對原題稍作改動
=============================================================
示例 1:
輸入: [1,2,3,1]
輸出: 4
解釋: 選擇 1 號預約和 3 號預約,總時長 = 1 + 3 = 4。
示例 2:
輸入: [2,7,9,3,1]
輸出: 12
解釋: 選擇 1 號預約、 3 號預約和 5 號預約,總時長 = 2 + 9 + 1 = 12。
示例 3:
輸入: [2,1,4,5,3,1,1,3]
輸出: 12
解釋: 選擇 1 號預約、 3 號預約、 5 號預約和 8 號預約,總時長 = 2 + 4 + 3 + 3 = 12。=============================================================

審題:

首先介紹一下我自己的思路,該思路時間時間複雜度爲O(N2)O(N^2),而官方題解給出的最優解法時間複雜度爲O(N)O(N).

我們記S[0]S[0]爲數組a[0:n]中最佳預約序列的總時長,假設當前第k個活動爲最佳預約序列的第一個預約.我們可以推導出如下最優子結構:S[0]=T[k]+S[K+2]S[0] = T[k] +S[K+2],其中T[k]爲k號預約的時長.若當前共有n個活動,則S[n1]=T[n1]S[n-1] = T[n-1].我們不難發現各子問題間存在重疊部分,因此我們可以使用動態規劃算法解決該問題.基於以上最優子結構設計,我們的算法中需要解決的子問題個數共有O(N)個,而每一子問題的選擇有O(N)個,因此該算法的時間複雜度爲O(N2)O(N^2).

從另一個角度構建最優子結構,即S[k]S[k]爲數組[0,k]的最長預約時間,當前S[k]S[k]可能由兩種情況轉移而來,選擇第k個預約活動與不選擇第k個預約活動:
1)如果選擇第k個預約活動,則S[k]=S[k2]+T[k]S[k] = S[k-2] + T[k]
2)如果不選擇第k個預約活動,則S[k]=S[k1]S[k] = S[k-1]
因此,S[k]=max{S[k2]+T[k],S[k1]}S[k] = max\{S[k-2] + T[k], S[k-1]\}
基於以上最優子結構,我們的算法需要解決的子問題爲O(N),每一子問題的選擇爲O(1),因此該算法的時間複雜度爲O(N).

由於當前活動最多僅與前其兩步活動有關,因此我們在計算S[k]時,無需知道S[k-2],…S[0],基於此,我們不需要使用O(N)的空間複雜度,我們僅需使用大小爲3的數組保存當前最近3個活動值即可.

java算法:

O(N2)O(N^2)時間複雜度
class Solution {
    public int massage(int[] nums) {
        if(nums.length == 0)
            return 0;
        int[] S = new int[nums.length+2];

        S[nums.length+1] = 0;
        S[nums.length] = 0;
        S[nums.length-1] = nums[nums.length-1];
        for(int i = nums.length-2; i >= 0; i--){
            for(int j = i; j < nums.length; j++){
                S[i] = Math.max(S[i], nums[j] + S[j+2]);
            }
        }
		return S[0];
    }
}
O(N)O(N)時間複雜度
class Solution {
    //S[i]表示數組[0, i]的最長預約時間
    //S[i]可能包含兩種情況, 第i個活動預約,第i個活動不預約
    //如果第i個活動預約, 則S[i] = S[i-2] + T[i]
    //如果第i個活動不預約, 則S[i] = S[i-1]
    //其中S[0] = T[0]
    //S[1] = max{T[0], T[1]}

    public int massage(int[] nums) {
        if(nums.length == 0)
            return 0;
        if(nums.length == 1)
            return nums[0];
        int[] S = new int[nums.length];
        S[0] = nums[0];
        S[1] = Math.max(nums[0], nums[1]);
        for(int i = 2; i < nums.length; i++)
            S[i] = Math.max(S[i-2]+nums[i], S[i-1]);
        return S[S.length-1];
    }
}
時間複雜度O(N)O(N),空間複雜度O(1)O(1)
class Solution {
    //S[i]表示數組[0, i]的最長預約時間
    //S[i]可能包含兩種情況, 第i個活動預約,第i個活動不預約
    //如果第i個活動預約, 則S[i] = S[i-2] + T[i]
    //如果第i個活動不預約, 則S[i] = S[i-1]
    //其中S[0] = T[0]
    //S[1] = max{T[0], T[1]}

    public int massage(int[] nums) {
        if(nums.length == 0)
            return 0;
        if(nums.length == 1)
            return nums[0];
        int[] S = new int[3];
        S[0] = nums[0];
        S[1] = Math.max(nums[0], nums[1]);
        for(int i = 2; i < nums.length; i++)
            S[i%3] = Math.max(S[(i-2)%3]+nums[i], S[(i-1)%3]);
        return S[(nums.length-1) % 3];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章