面试题17.16 按摩师(2021-04-21)

面试题 17.16 按摩师

链接:https://leetcode-cn.com/problems/the-masseuse-lcci/

一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。

输入: [1,2,3,1]
输出: 4
解释: 选择 1 号预约和 3 号预约,总时长 = 1 + 3 = 4。

输入: [2,7,9,3,1]
输出: 12
解释: 选择 1 号预约、 3 号预约和 5 号预约,总时长 = 2 + 9 + 1 = 12。

输入: [2,1,4,5,3,1,1,3]
输出: 12
解释: 选择 1 号预约、 3 号预约、 5 号预约和 8 号预约,总时长 = 2 + 4 + 3 + 3 = 12。

解法1:动态规划

我的思路是,用dp[i]表示第i个预约的话能获得的最大预约时长,最后要求的是dp[i]dp[i - 1]中的较大者(因为这两个都有可能是满足条件的)

然后找出状态转移方程,因为需要间隔预约,所以如果预约了dp[i],那么dp[i - 1]是一定不能预约的,要比较的就是dp[i - 2]dp[i - 3]的大小,至于dp[i - 4]不需要比较了,因为它月dp[i - 2]又相隔了一次预约,可以累加到dp[i - 2]中了

然后需要给出初始值,dp[0]只能等于nums[0]dp[1]应该是nums[0]nums[1]的较大者,dp[2]应该是nums[0] + nums[2]nums[1]的较大者

var massage = function (nums) {
  const length = nums.length;

  if (nums.length === 0) {
    return 0;
  }

  if (nums.length === 1) {
    return nums[0];
  }

  if (nums.length === 2) {
    return Math.max(nums[0], nums[1]);
  }

  if (nums.length === 3) {
    return Math.max(nums[0] + nums[2], nums[1]);
  }

  let dp = [nums[0], Math.max(nums[0], nums[1]), Math.max(nums[0] + nums[2], nums[1])];

  for (let i = 3; i < length; i++) {
    dp[i] = Math.max(dp[i - 2], dp[i - 3]) + nums[i];
  }

  return Math.max(dp[length - 1], dp[length - 2]);
};

执行用时:76ms, 在所有JavaScript提交中击败了90.05%的用户,内存消耗:37.6MB, 在所有JavaScript提交中击败了87.34%的用户

解法2:动态规划

其实本质上仍然是上一种思路,只不过换了一种思考方式,更容易理解一些(为什么我想到的思路都是乱七八糟的)

因为是间隔预约,所以要比较的是dp[i- 1]dp[i - 2] + nums[i]的较大者

var massage = function (nums) {
  const length = nums.length;

  if (nums.length === 0) {
    return 0;
  }

  if (nums.length === 1) {
    return nums[0];
  }

  if (nums.length === 2) {
    return Math.max(nums[0], nums[1]);
  }

  let dp = [nums[0], Math.max(nums[0], nums[1])];

  for (let i = 2; i < length; i++) {
    dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
  }

  return dp[length - 1];
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值