力扣740.删除并获得点数 预处理与动态规划的巧妙融合
题意解析:
给定一组数字,每当你选择一个数字x时,所有等于x-1和x+1的数字都会被自动移除。你需要通过巧妙的选择顺序,最大化获得的点数总和。这个问题可以转化为对离散化数字分布的动态规划问题——将相邻数字视为互斥选项,通过预处理聚合同类数值,转化为经典的序列决策问题。
思路解析:
代码通过预处理聚合+动态规划实现高效求解:
1.数值聚合:
创建num1数组存储每个数字的总和(例如数字3出现两次则num1[3]=6)
将原始问题转化为不能选择相邻数值的最优决策问题
2.动态规划初始化:
dp[0]直接取num1[0](唯一选择)
dp[1]取前两个值的较大者
dp[2]对比三种可能路径:选首尾、选中间、全不选
3.递推策略设计:
从第三位开始,状态转移方程为dp[i] = max(隔前两位抢当前,隔前三位抢当前)
动态维护全局最大值dpmax,避免遍历最终数组
易读注释版代码:
class Solution { public: int num1[10001]; // 预处理数组:索引为数字,值为该数字总和 Solution() { // 初始化数组清零 for (int i = 0; i < 10001; i++) { num1[i] = 0; } } int deleteAndEarn(vector<int>& nums) { // 预处理阶段:聚合相同数字的总和 for (int i = 0; i < nums.size(); i++) { num1[nums[i]] += nums[i]; // 累加相同数字的值 } // 动态规划初始化 int dp[10001]; dp[0] = num1[0]; // 只有数字0可选时的收益 dp[1] = max(num1[0], num1[1]); // 0和1互斥,取较大者 dp[2] = max(num1[0] + num1[2], num1[1]); // 三种情况比较 int dpmax = dp[2]; // 初始化当前最大值 // 递推求解 for (int i = 3; i < 10001; i++) { // 状态转移核心:比较两种跨步方案 dp[i] = max(dp[i - 2] + num1[i], // 方案一:隔两数选当前 dp[i - 3] + num1[i]);// 方案二:隔三数选当前 dpmax = max(dpmax, dp[i]); // 更新全局最大值 } return dpmax; // 返回历史最大收益 } };
原创内容 转载请注明出处