LeetCode 740 - 删除并获取点数
题目
给你一个整数数组 nums,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i],删除它并获得 nums[i] 的点数。之后,你必须删除所有等于 nums[i] - 1 和 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
示例 1
输入:nums = [3,4,2]
输出:6
解释:删除 4 获得 4 点数,因此 3 也被删除;之后删除 2 获得 2 点数,总共 6。
示例 2
输入:nums = [2,2,3,3,3,4]
输出:9
解释:删除 3 获得 3 点数,接着要删除两个 2 和 4;之后再次删除 3 获得 3 点数,再删除 3 获得 3 点数,总共 9。
提示
1 <= nums.length <= 2 * 10^41 <= nums[i] <= 10^4
解题思路
这道题可以转化为打家劫舍问题:
- 首先统计每个数字出现的次数,记录在数组sum中
- sum[i]表示数字i出现的总和(即出现次数 × i)
- 选择某个数字i时:
- 获得sum[i]的点数
- 不能选择i-1和i+1
- 这就变成了:从一个数组中选数字,不能选相邻的数,求最大和
动态规划解法
- 定义dp[i]表示考虑前i个数字能获得的最大点数
- 对于数字i,可以选择要或不要:
- 选择i:dp[i] = dp[i-2] + sum[i]
- 不选i:dp[i] = dp[i-1]
- 取两种情况的最大值
Python 实现
1 | class Solution: |
Python解法说明
这个实现按照原来的思路,做了以下优化:
- 使用字典而不是数组来存储点数,节省空间
- 只考虑实际存在的数字,避免处理空隙
- 明确区分了相邻和不相邻数字的情况
- 特殊情况的处理更加完善
优点:
- 实现更直观,符合题目的原始思路
- 空间效率更高,只存储实际存在的数字
- 时间复杂度保持O(n),但实际运行更快
方法一:使用 Counter 简化统计
1 | from collections import Counter |
方法二:空间优化版本
1 | class Solution: |
Python解法说明
新的实现提供了两种优化方案:
Counter版本的优点:
- 使用内置的Counter类简化统计过程
- 只遍历实际存在的数字,减少无效计算
- 空间复杂度优化为O(k),k为不同数字的个数
空间优化版本的优点:
- 只使用三个变量维护状态,空间复杂度为O(1)
- 代码更加简洁
- 通过滚动数组思想优化空间使用
这两个版本都保持了相同的时间复杂度O(n),但在空间使用和代码简洁性上有所改进。
复杂度分析
- 时间复杂度:O(n),其中n为nums数组中的最大值
- 空间复杂度:O(n),需要额外的数组来存储sum和dp值
总结
这是一道典型的动态规划问题,关键在于将原问题转化为类似打家劫舍的问题模型。通过合理定义状态转移方程,可以高效地解决这个问题。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Never Settle!
评论