zoukankan      html  css  js  c++  java
  • 打败算法 —— 按摩师

    本文参考

    出自LeetCode上的题库 —— 按摩师,本篇文章主要是参考LeetCode上的题解@Sweetiee

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

    按摩师问题

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

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

    解题思路

    动态规划问题往往就是求最值的问题,并且我们可以看到将大问题转化为小问题的可能性 —— 每个预约都可以选择接与不接,但是不能接相邻的预约,假设当前状态为f(n),n代表第n个请求,f(n)代表从第1个请求到第n个请求为止的最长预约时间,若当前状态不接受预约,则f(n) = f(n - 1),若当前状态接受预约,则f(n) = f(n - 2) + t(n),t(n)代表第n个预约的时间,两种情况下的两种子结构互相独立,都能获取到最优值,因此具备最优子结构性质

    那么,当前状态到底应不应该接受请求呢?我们需要对两个子状态进行对比,得到最大值赋给当前状态,即f(n) = Max(f(n - 1),f(n - 2) + t(n)),这也就是状态转移方程。有没有觉得这个式子有点眼熟,是不是很像斐波那契数列?我们知道斐波那契数列的暴力递归算法效率很低,同样的,在这个按摩师问题中,我们也不建议采取暴力递归的算法,下面直接上我们的dp数组解法

    但是要自底向上进行dp数组算法的递推,我们还需要定义基状态(base case),在最长公共子序列中我们定义了dp数组的第一行和第一列的值为 空串 或者是 0,在这里我们定义基状态为dp[0] = t(0),第一个预约需要的时间赋给dp数组第一位,dp[1] = Max(t(0),t(1)),第二个预约时间和第一个预约时间相比的最大值赋给dp数组第二位,因为对于仅有两个预约的子问题,就是简单的求出二者中的最大值(按摩师问题的基状态和斐波那契数列问题的基状态也有相似之处,不知注意到没~)

    暴力递归

    代码:

    def force(nums: Array[Int], i: Int): Int = {
      if (i < 0) return 0
      if (i == 0) return nums(0)
      if (i == 1) return Math.max(nums(0), nums(1))

      Math.max(force(nums, i - 1), force(nums, i - 2) + nums(i))
    }

    def main(args: Array[String]): Unit = {
      val nums = Array(2, 1, 4, 5, 3, 1, 1, 3)
      println(force(nums, nums.length - 1))
    }

    输出:

    12

    尽管是暴力递归,但不得不说代码简洁易懂呢

    自底向上的dp数组算法

    代码:

    def massage(nums: Array[Int]): Int = {
      val n = nums.length
      if (n == 0) return 0
      if (n == 1) return nums(0)
      val dp = new Array[Int](n)
      dp(0) = nums(0)
      dp(1) = Math.max(nums(0), nums(1))
      for (i <- 2 until n) {
        dp(i) = Math.max(dp(i - 1), dp(i - 2) + nums(i))
      }
      dp(n - 1)
    }

    def main(args: Array[String]): Unit = {
      val nums = Array(2, 1, 4, 5, 3, 1, 1, 3)
      println(massage(nums))
    }

    输出:

    12

    原本指数级别的时间复杂度,瞬间降到了线性级别,掌握动态规划真是太重要啦

  • 相关阅读:
    userdel -删除使用者帐号及相关档案
    useradd -帐号建立或更新新使用者的资讯
    uptime
    uuid
    Web 在线文件管理器学习笔记与总结(7)重命名文件
    Java实现 LeetCode 116 填充每个节点的下一个右侧节点指针
    Java实现 LeetCode 116 填充每个节点的下一个右侧节点指针
    Java实现 LeetCode 114 二叉树展开为链表
    Java实现 LeetCode 114 二叉树展开为链表
    Java实现 LeetCode 114 二叉树展开为链表
  • 原文地址:https://www.cnblogs.com/kuluo/p/12584820.html
Copyright © 2011-2022 走看看