快速通道
前言
有些题目比较隐晦,拿到题目毫无头绪,又不像刷举一反三系列一样,由易到难,本文主要记录解题的思路。
740. 删除并获得点数
给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除每个等于 nums[i] - 1 或
nums[i] + 1 的元素。开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
来源:力扣(LeetCode)
解题
拿到该题,再结合示例,发现就是我要取某个数,然后邻近的数都需要全部删除,并且求最大值,这种题目一般不可能枚举,一定有某种规律,而且求最大最小值,一般涉及贪心算法。
比如【1,1,2,2,2,3,3】,我如果取了一个2,就会把 1和3 全部删除,最后剩下 2,也就是说如果选择了2,最终结果是把2全部相加,邻近的1和3不能加,那也就是说我最终的结果其实是取某些特定数的总和,就比如以上序列,分别映射的的点数分别是 2,6,6,然后我要取求最大点数,到这里发现该题跟打家劫舍非常相似。
唯一的不同点便是打家劫舍是连续的数组,而这个显然不是,而本题非连续数字是可以相加的,那我只需要判断上一个数是不是比当前数少1 不就行了嘛。
步骤:
st1:计算每个数的点数总和(数的个数 * 点数)
st2:需要一个去重过的递增的序列,就像打家劫舍的索引序列一样
st3:先用动态规划做,创建一个dp数组,长度为 n 或者 n+1,我这里用的n,主要是这样子方便一点。
st4:然后遍历,需要分情况讨论,如果有序序列的上一个数 跟当前数不是连续的,那就直接加,要不然就分两种情况 取max。
st5:最后取出dp的最后一个位置的数,即为最终的结果。
class Solution:
def deleteAndEarn(self, nums: List[int]) -> int:
# 该题跟打家劫舍有点像
numdict = dict()
numlist = []
for num in nums:
if num in numdict.keys():
numdict[num] += num
else:
numdict[num] = num
numlist.append(num)
# 然后用动态规划
n = len(numlist)
sortnuml = sorted(numlist)
dp = [0] * (n + 1)
dp[1] = numdict[sortnuml[0]]
for i in range(1,n):
# 如果上一个不是连续的
if sortnuml[i] != sortnuml[i-1] + 1:
dp[i+1] = dp[i] + numdict[sortnuml[i]]
else:
dp[i+1] = max(dp[i], dp[i-1] + numdict[sortnuml[i]])
return dp[n]
总结
该题的关键是把相同数的点数相加,为什么要把相同数点数相加,有时候没有思路的时候可以试着举例找找规律。