个人主页:元清加油_【C++】,【C语言】,【数据结构与算法】-CSDN博客
个人专栏
力扣递归算法题
http://t.csdnimg.cn/yUl2I
【C++】
http://t.csdnimg.cn/6AbpV
数据结构与算法
http://t.csdnimg.cn/hKh2l
前言:这个专栏主要讲述动态规划算法,所以下面题目主要也是这些算法做的
我讲述题目会把讲解部分分为3个部分:
1、题目解析
2、算法原理思路讲解
3、代码实现
按摩师
题目链接:按摩师
题目
一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约。给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
注意:本题相对原题稍作改动
示例 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[i] 表示
:选择到
i
位置时,此时的最⻓预约时⻓。
但是我们这个题在
i
位置的时候,会⾯临「选择」或者「不选择」两种抉择,所依赖的状态需要细分:
- f[i] 表示:选择到 i 位置时, nums[i] 必选,此时的最⻓预约时⻓;
- g[i] 表示:选择到 i 位置时, nums[i] 不选,此时的最⻓预约时⻓。
- 状态转移方程
因为状态表⽰定义了两个,因此我们的状态转移⽅程也要分析两个:
- 对于 f[i] : 如果 nums[i] 必选,那么我们仅需知道 i - 1 位置在不选的情况下的最⻓预约时⻓, 然后加上 nums[i] 即可,因此 f[i] = g[i - 1] + nums[i] 。
- 对于 g[i] : 如果 nums[i] 不选,那么 i - 1 位置上选或者不选都可以。因此,我们需要知道 i - 1 位置上选或者不选两种情况下的最⻓时⻓,因此 g[i] = max(f[i - 1], g[i-1])。
- 初始化(防止填表时不越界)
这道题的初始化⽐较简单,因此⽆需加辅助节点,仅需初始化
f[0] = nums[0], g[0] = 0
即可。
- 填表顺序
根据「状态转移⽅程」得「从左往右,两个表⼀起填」。
- 返回值
根据「状态表⽰」,应该返回
max(f[n - 1], g[n - 1])
。
代码实现
class Solution {
public:
int massage(vector<int>& nums)
{
int n = nums.size();
if(n == 0) return 0; // 处理边界条件
vector<int> f(n);
auto g = f;
f[0] = nums[0];
for(int i = 1; i < n; i++)
{
f[i] = g[i - 1] + nums[i];
g[i] = max(f[i - 1], g[i - 1]);
}
return max(f[n - 1], g[n - 1]);
}
};