解题思路
这道题可以转化为打家劫舍问题:
- 首先统计每个数字出现的次数,记录在数组sum中
- sum[i]表示数字i出现的总和(即出现次数 × i)
- 选择某个数字i时:
- 这就变成了:从一个数组中选数字,不能选相邻的数,求最大和
动态规划解法
- 定义dp[i]表示考虑前i个数字能获得的最大点数
- 对于数字i,可以选择要或不要:
- 选择i:dp[i] = dp[i-2] + sum[i]
- 不选i:dp[i] = dp[i-1]
- 取两种情况的最大值
Python实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Solution: def deleteAndEarn(self, nums: List[int]) -> int: if not nums: return 0 points = {} for num in nums: points[num] = points.get(num, 0) + num unique_nums = sorted(points.keys()) n = len(unique_nums) if n == 1: return points[unique_nums[0]] dp = [0] * n dp[0] = points[unique_nums[0]] if unique_nums[1] - unique_nums[0] == 1: dp[1] = max(dp[0], points[unique_nums[1]]) else: dp[1] = dp[0] + points[unique_nums[1]] for i in range(2, n): curr_num = unique_nums[i] prev_num = unique_nums[i-1] if curr_num - prev_num == 1: dp[i] = max(dp[i-1], dp[i-2] + points[curr_num]) else: dp[i] = dp[i-1] + points[curr_num] return dp[-1]
|
Python解法说明
这个实现按照原来的思路,做了以下优化:
- 使用字典而不是数组来存储点数,节省空间
- 只考虑实际存在的数字,避免处理空隙
- 明确区分了相邻和不相邻数字的情况
- 特殊情况的处理更加完善
优点:
- 实现更直观,符合题目的原始思路
- 空间效率更高,只存储实际存在的数字
- 时间复杂度保持O(n),但实际运行更快
方法一:使用Counter简化统计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| from collections import Counter
class Solution: def deleteAndEarn(self, nums: List[int]) -> int: points = Counter(nums) nums = sorted(points.keys()) earn1, earn2 = 0, 0 prev = -1 for num in nums: curr_earn = num * points[num] if num - 1 != prev: earn2, earn1 = max(earn1, earn2) + curr_earn, earn2 else: earn2, earn1 = max(earn1, earn2 + curr_earn), earn2 prev = num return max(earn1, earn2)
|
方法二:空间优化版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Solution: def deleteAndEarn(self, nums: List[int]) -> int: if not nums: return 0 prev = curr = future = 0 count = [0] * (max(nums) + 1) for num in nums: count[num] += num for i in range(len(count)): future = max(curr, prev + count[i]) prev, curr = curr, future return curr
|
Python解法说明
新的实现提供了两种优化方案:
Counter版本的优点:
- 使用内置的Counter类简化统计过程
- 只遍历实际存在的数字,减少无效计算
- 空间复杂度优化为O(k),k为不同数字的个数
空间优化版本的优点:
- 只使用三个变量维护状态,空间复杂度为O(1)
- 代码更加简洁
- 通过滚动数组思想优化空间使用
这两个版本都保持了相同的时间复杂度O(n),但在空间使用和代码简洁性上有所改进。
复杂度分析
- 时间复杂度:O(n),其中n为nums数组中的最大值
- 空间复杂度:O(n),需要额外的数组来存储sum和dp值
总结
这是一道典型的动态规划问题,关键在于将原问题转化为类似打家劫舍的问题模型。通过合理定义状态转移方程,可以高效地解决这个问题。