「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」
前言
这是 Biweekly Contest 71 比赛的第四题,难度 Hard ,考察的是对堆数据结构(或者优先队列)的使用。
描述
You are given a 0-indexed integer array nums consisting of 3 * n elements.
You are allowed to remove any subsequence of elements of size exactly n from nums. The remaining 2 * n elements will be divided into two equal parts:
- The first n elements belonging to the first part and their sum is sumfirst.
- The next n elements belonging to the second part and their sum is sumsecond.
The difference in sums of the two parts is denoted as sumfirst - sumsecond.
- For example, if sumfirst = 3 and sumsecond = 2, their difference is 1.
- Similarly, if sumfirst = 2 and sumsecond = 3, their difference is -1.
Return the minimum difference possible between the sums of the two parts after the removal of n elements.
Example 1:
Input: nums = [3,1,2]
Output: -1
Explanation: Here, nums has 3 elements, so n = 1.
Thus we have to remove 1 element from nums and divide the array into two equal parts.
- If we remove nums[0] = 3, the array will be [1,2]. The difference in sums of the two parts will be 1 - 2 = -1.
- If we remove nums[1] = 1, the array will be [3,2]. The difference in sums of the two parts will be 3 - 2 = 1.
- If we remove nums[2] = 2, the array will be [3,1]. The difference in sums of the two parts will be 3 - 1 = 2.
The minimum difference between sums of the two parts is min(-1,1,2) = -1.
Note:
nums.length == 3 * n
1 <= n <= 10^5
1 <= nums[i] <= 10^5
解析
根据题意,给定一个由 3 * n 个元素组成的 0 索引整数数组 nums。可以从 nums 中删除大小正好为 n 的元素的任何子序列。 剩下的 2 * n 个元素将被分成两等份:
- 属于第一部分的前 n 个元素,它们的和是 sumfirst。
- 接下来的 n 个元素属于第二部分,它们的和是 sumsecond。
两部分之和的差值表示为 sumfirst - sumsecond。例如,如果 sumfirst = 3 和 sumsecond = 2,则它们的差为 1。返回删除 n 个元素后两部分之和之间可能的最小差异。
我一开始没什么思路,看了大佬的解答过程,真的是简单易懂,内容简洁。我这里就再把大佬的思路理清一下。
这道题其实可以转化为另外一个问题,那就是要将 nums 分为前后两个部分,要想让最后的差值最小,那就让前面的部分的和最小,后面部分的和最大。
开始我们先找到 N = len(nums)//3 ,这里用到了堆数据结构,我们先在 nums[N-1:2*N] 范围内从左到右每个位置 i ,找出 nums[:i] 范围内的 N 个最小的数字之和,将其加入到 preMin 。同理我们用堆数据结构,再在 nums[N:2*N+1] 范围内从右到左每个位置 i ,找出 nums[i:] 范围内的 N 个最大的数字之和,将其加入到 sufMax ,在得到 sufMax 之后需要将 sufMax 进行反转。然后同时遍历 preMin 和 sufMax 相同位置的元素,计算 preMin-sufMax ,其实也就是在第 i 个位置时,nums[:i] 可以得到的最小值减 nums[i:] 可以得到的最大值,然后找出差值的最小值返回即可。
时间复杂度为 O(NlogN) ,刚刚好没有超时,空间复杂度为 O(N) 。
解答
class Solution(object):
def minimumDifference(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
N = len(nums)//3
# preMin
preMin = [sum(nums[:N])]
curMin = sum(nums[:N])
pre_hp = [-x for x in nums[:N]]
heapq.heapify(pre_hp)
for i in range(N, 2*N):
val = -heapq.heappop(pre_hp)
curMin -= val
tmp = min(val, nums[i])
curMin += tmp
preMin.append(curMin)
heapq.heappush(pre_hp, -tmp)
# sufMax
sufMax = [sum(nums[-N:])]
curMax = sum(nums[-N:])
suf_hp = [x for x in nums[2*N:]]
heapq.heapify(suf_hp)
for i in range(2*N-1, N-1, -1):
val = heapq.heappop(suf_hp)
curMax -= val
tmp = max(val, nums[i])
curMax += tmp
sufMax.append(curMax)
heapq.heappush(suf_hp, tmp)
# find min diff
sufMax = sufMax[::-1]
result = float('inf')
for a,b in zip(preMin, sufMax):
result = min(result, a-b)
return result
运行结果
109 / 109 test cases passed.
Status: Accepted
Runtime: 4865 ms
Memory Usage: 44.2 MB
原题链接
您的支持是我最大的动力