动态规划问题 -- 多状态模型(删除并获得点数)
目录
- 动态规划分析问题五步曲
- 题目概述
- 预处理阶段
- 代码编写
动态规划分析问题五步曲
不清楚动态规划分析问题是哪关键的五步的少年们可以移步到
链接: 动态规划算法基础
这篇文章非常详细的介绍了动态规划算法是如何分析和解决问题的
题目概述
链接: 删除并获得点数
预处理阶段
分析题目要求,发现nums中的每一种数都存在删除并获取其点数和不删除直接跳到后续的操作 ,确定本题用一个dp表是解决不了问题的是一个多状态的dp问题
对麻烦的下标映射进行预处理,以方便未来动态规划
看到实例2,删除3则要去删除前面所有2和4。如果未来nums数组很长呢那么呢?想要控制 下标达成题目中:每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素”的要求的下标控制非常困难
解决方案,不妨把所有相同的值合并在一起,并新建一个数组这个数组的下标表示 nums中的元素值:price[i] 表示nums中等于i的所有元素之和
nums = [2,2,3,3,3,4] -> price = {0,0,4,9,4};
(可见数组newnums的大小应该为nums的最大值+1)
预处理完成后,分析第i个位置时,就只需要控制i位置相邻的下标了!!!
- 状态表示(题目要求+自己的经验)
本题状态:
deleteNums[i] :表示到第i位置并且删除获得i位置的点数,能获得的最大点数
NoDeleteNums[i] : 表示到第i位置并且不删除该位置,能获得的最大点数
- 状态转移方程推导
从预处理后的nums,price的第i个位置进行分类讨论
轻松得出状态转移方程
- 初始化(防止越界+结合状态表示初始化)
根据状态转移方程,当i = 0时会发生,越界
因为题目已经说明nums[i] >= 1 ,因此price[0] = 0
那么deleteNums[0] = deleteNums[0] = 0;
- 填表顺序(分析要填i位置前一个依赖状态的位置)
本题两个表显然都是从左到右填表
- 返回值(由题目要求来)
根据两个状态表的状态表示
return max(deleteNums[n-1] , NodeleteNums[n-1]) ;
代码编写
有了动态规划五步曲我们就可以写出非常优雅的代码了
int deleteAndEarn(vector<int>& nums) {int numsMax = INT_MIN;for(auto& e : nums)numsMax = max(numsMax,e);int n = numsMax + 1;vector<int> price(n); // 开最大值加一个大小1for(auto& e : nums)price[e] += e;vector<int> DeleteNums(n);vector<int> NoDeleteNums(n);for(int i = 1 ; i < n ; i++){DeleteNums[i] = NoDeleteNums[i-1] + price[i];NoDeleteNums[i] = max(DeleteNums[i-1],NoDeleteNums[i-1]);}return max(DeleteNums[n-1],NoDeleteNums[n-1]);}
少年,今天你又进步了一点点哟,明天继续加油吧