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];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章