LeetCode 2542. Maximum Subsequence Score
雙周賽96。和上題的輸入一樣都是nums1和nums2配上k,還以為我精神錯亂。
題目
輸入兩個長度為N的整數陣列nums1和nums2,以及整數k。你必須選擇k個nums1的索引來組成子序列。
若你選擇了數個索引i0, i1, … , ik-1,則分數為:
- 所有選到的nums1[i]的總和,乘上所有選到的nums2[i]中的最小值
- 也就是(nums1[i0] + nums1[i1] +…+ nums1[ik-1]) * min(nums2[i0] + nums2[i1] +…+ nums2[ik-1])
求最大的可能分數為多少。
解法
陣列長度N高達10^5,要窮舉出所有子序列肯定不現實,直接不考慮。
我們要找的是子序列,代表只在乎每個索引i選或者不選,並不在乎被選中的次數,必要時甚至可以將陣列重排序。
根據上述,試想能不能依照某個順序遍歷陣列,以達到目標?
既然是要乘以nums2選中的最小值,所以nums2中只要是大於最小值的索引全部都可以選擇。窮舉,盡可能找到nums1[i]較大,且nums2[i]>=最小值的索引i。
所以可以以nums2[i]的值作為key,將nums1[i]加入對應的雜湊表中。由大到小窮舉nums[i]中出現過的數當作最小值,逐漸將可用的nums1[i]加入,並選擇最大的k個nums1[i]求總和,乘上nums2[i]最小值即為分數,最後以分數更新答案。
現在問題只剩下要找k個最大的值。這時候使用min heap,順便維護總和,在窮舉nums2最小值的nums1[i]加入heap,若heap中超過k個值,則不斷彈出最小值。
時間瓶頸在於nums2中出現的key值排序,若nums2中所有元素都不同,排序需要O(N log N)。雜湊表分類的時間為O(N),heap的時間為O(N log k)。 整體時間複雜度O(N log N)。空間複雜度O(N)。
class Solution:
def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int:
d=defaultdict(list)
for a,b in zip(nums1,nums2):
d[b].append(a)
ans=0
h=[]
sm=0
for mn in sorted(d.keys(),reverse=True):
for x in d[mn]:
heappush(h,x)
sm+=x
while len(h)>k:
sm-=heappop(h)
if len(h)==k:
ans=max(ans,sm*mn)
return ans
也可以直接把nums1和nums2綁定成數對pair,依nums2[i]的值遞減排序,直接遍歷排序好的pair,依序加入heap中。
class Solution:
def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int:
pair=sorted(zip(nums1,nums2),key=lambda x:-x[1])
ans=0
h=[]
sm=0
for val,mn in pair:
heappush(h,val)
sm+=val
if len(h)>k:
sm-=heappop(h)
if len(h)==k:
ans=max(ans,sm*mn)
return ans