477,动态规划解按摩师的最长预约时间

想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
在这里插入图片描述


问题描述

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

示例 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。


动态规划解决

数组中的值表示的是预约时间,按摩师可以选择接或者不接,如果前一个接了,那么下一个肯定是不能接的,因为按摩师不能接相邻的两次预约。如果上一个没接,那么下一个可以选择接也可以选择不接,视情况而定。


这里可以定义一个二维数组dp[length][2],其中dp[i][0]表示第i+1(因为数组下标是从0开始的,所以这里是i+1)个预约没有接的最长总预约时间,dp[i][1]表示的是第i+1个预约接了的最长总预约时间。那么我们找出递推公式


1,dp[i][0]=max(dp[i-1][0],dp[i-1][1])

他表示如果第i+1个没有接,那么第i个有没有接都是可以的,我们取最大值即可。


2,dp[i][1]=dp[i-1][0]+nums[i]

他表示的是如果第i+1个接了,那么第i个必须要没接,这里nums[i]表示的是第i+1个预约的时间。


递推公式找出来之后我们再来看下边界条件,第一个预约可以选择接,也可以选择不接,所以

  • dp[0][0]=0,第一个没接
  • dp[0][i]=nums[0],第一个接了。

最后再来看下代码

public int massage(int[] nums) {
    //边界条件判断
    if (nums == null || nums.length == 0)
        return 0;
    int length = nums.length;
    int[][] dp = new int[length][2];
    dp[0][0] = 0;//第1个没接
    dp[0][1] = nums[0];//第1个接了
    //从第2个开始判断
    for (int i = 1; i < length; i++) {
        //下面两行是递推公式
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
        dp[i][1] = dp[i - 1][0] + nums[i];
    }
    //最后取最大值即可
    return Math.max(dp[length - 1][0], dp[length - 1][1]);
}

动态规划优化

上面定义了一个二维数组,但每次计算的时候都只是用二维数组的前一对值,在往前面的就永远使用不到了,这样就会造成巨大的空间浪费,所以我们可以定义两个变量来解决,来看下代码

public int massage(int[] nums) {
    //边界条件判断
    if (nums == null || nums.length == 0)
        return 0;
    int length = nums.length;
    int dp0 = 0;//第1个没接
    int dp1 = nums[0];//第1个接了
    //从第2个开始判断
    for (int i = 1; i < length; i++) {
        //防止dp0被修改之后对下面运算造成影响,这里
        //使用一个临时变量temp先把结果存起来,计算完
        //之后再赋值给dp0.
        int temp = Math.max(dp0, dp1);
        dp1 = dp0 + nums[i];
        dp0 = temp;
    }
    //最后取最大值即可
    return Math.max(dp0, dp1);
}

总结

首先这里都是正规的按摩师,使用动态规划是最容易解决的,只要找准递推公式,基本上也没什么难度。


在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据结构和算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值