题目:
给你一个下标从 0 开始的整数数组 nums
和一个整数 k
。你的 起始分数 为 0
。
在一步 操作 中:
- 选出一个满足
0 <= i < nums.length
的下标i
, - 将你的 分数 增加
nums[i]
,并且 - 将
nums[i]
替换为ceil(nums[i] / 3)
。
返回在 恰好 执行 k
次操作后,你可能获得的最大分数。
向上取整函数 ceil(val)
的结果是大于或等于 val
的最小整数。
暴力模拟(失败):
在看到这题,我先尝试暴力解法,利用用python的max函数来解:
class Solution:
def maxKelements(self, nums: List[int], k: int) -> int:
result = 0
for i in range(k):
max_ = max(nums)
index_ = nums.index(max_)
result += max_
nums[index_] = math.ceil(nums[index_] / 3)
return result
然而很可惜:超时了,只过了32个例子,因此尝试用其它算法。
优化改进:
通过题意,这个相当于在k次循环中,每次找到当前数组最大值,然后加入结果,并将该值进行ceil(n / 3)处理,因此可以想到一种数据结构:堆。这里我们选择大根堆,每次将堆顶元素拿出来就行,然后处理放进堆中
最终解法——大根堆:
class Solution:
def maxKelements(self, nums: List[int], k: int) -> int:
result = 0
nums = [-i for i in nums]
heapq.heapify(nums)
for i in range(k):
top = heapq.heappop(nums)
result -= top
heapq.heappush(nums, -math.ceil(-top / 3))
return result
首先,我们将数组转为它的相反数数组,这是因为python的heapq库中构造堆为小根堆,而要达到大根堆的效果只能这样。
然后,我们用for循环来找到每次的堆顶,它就是堆中最小的那个元素(数组最大的),用result减去这个负数,然后将它处理加入到堆中,这里注意:每次处理后加的新元素是它的相反数而不是它本身。。