题目描述
一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。
在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,
替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
注意:本题相对原题稍作改动
示例 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。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/the-masseuse-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
动态规划
题目理解
按摩师对于每一个预约请求:
- 可以接受预约;
- 可以不接受预约;
- 且不能接受相邻的预约请求;
- 最后需要得出请求序列总预约时间最长
举例1:预约序列为 [1,2,3,1]有以下几种可能:
- 假设我们接受1号预约,则不能接受2号预约;
- 为了总预约时长最长;
- 在3号/4号预约中,选择3预约;
- 总时长为:1+3=4;
- 假设我们不接受1号预约,则可选择接受2号/3号预约;
- 假设选择2号预约,则必须选择4号预约:总时长为:2+1=3;
- 假设选择3号预约,由于不接受相邻预约,则后面的预约不接受;总时长为:3
综上:最佳选择为:1+3=4;
标准动态规划问题:
- 定义状态:dp[i]表示:序列中 0 至 i 区间,接受预约请求最大的时长;
- 状态转移方程:
- 接受预约:则前一天一定休息,由于状态dp[i-1]定义涵盖了
i-1
这一天接受预约的情况,- 状态转移:dp[i]的状态一定由 dp[i-2]+nums[i] 转移而来;
- 不接受预约:则前一天可以休息,也可以不休息,
- 状态转移:dp[i]的状态由 下标为
i-1
的 dp[i-1]状态转移而来
- 状态转移:dp[i]的状态由 下标为
- 状态转移方程为:dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
- 接受预约:则前一天一定休息,由于状态dp[i-1]定义涵盖了
- 初始化:
- 由状态转移方程可知,下标最小为
i-2
; - 因此需要初始化dp[0],dp[1],从dp[2]开始计算,即:第三天开始动态规划;
- 考虑到需接受预约请求最大的时长:
- dp[0]:只有一天的时候,必须接受预约;
- dp[0]=nums[0];
- dp[1]:前两天,由于不能同时接受预约,因此最优解为:
- dp[1]=max(nums[0],nums[1]);
- dp[0]:只有一天的时候,必须接受预约;
- 由状态转移方程可知,下标最小为
代码
/**
* @param {number[]} nums
* @return {number}
*/
var massage = function(nums) {
let len=nums.length;
if(len==0){
return 0;
}
if(len==1){
return nums[0]
}
// 定义状态:dp[i]表示:0 至 i区间,接受预约请求最大的时长;
let dp=[len];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(let i=2;i<len;i++){
// 今天是否接受预约,选则一个时间最长的
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return dp[len-1]
};
解题思路
滚动数组思想
- 由于只涉及到dp[i]、dp[i-1]、dp[i-2];
- 当i=2时:
- dp[i%3]=Math.max(dp[(i-1)%3],dp[(i-2)%3]+nums[i]);
- dp[2%3]=Math.max(dp[(2-1)%3],dp[(2-2)%3]+nums[i]);
- dp[2]=Math.max(dp[1],dp[0]+nums[i]);
- dp[i%3]=Math.max(dp[(i-1)%3],dp[(i-2)%3]+nums[i]);
- 使用3个变量滚动完成计算,将空间优化到常数级别;
/**
* @param {number[]} nums
* @return {number}
*/
var massage = function(nums) {
let len=nums.length;
if(len==0){
return 0;
}
if(len==1){
return nums[0]
}
// 定义状态:dp[i%3]表示:0 至 i区间,接受预约请求最大的时长;
let dp=[3];
dp[0]=nums[0];
dp[1]=Math.max(nums[0],nums[1]);
for(let i=2;i<len;i++){
// 今天是否接受预约,选则一个时间最长的
dp[i%3]=Math.max(dp[(i-1)%3],dp[(i-2)%3]+nums[i]);
}
return dp[(len-1)%3]
};
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!