---
# System prepended metadata

title: 2163. Minimum Difference in Sums After Removal of Elements
tags: [Leetcode, Dynamic Programming, Hard, Three Pass, Greedy]

---

# 2163. Minimum Difference in Sums After Removal of Elements
###### tags: `Leetcode` `Hard` `Dynamic Programming` `Greedy` `Three Pass`
Link: https://leetcode.com/problems/minimum-difference-in-sums-after-removal-of-elements/description/
## 思路
因为删除```n```个元素之后，剩余的```2n```个元素会自然地分成前后两个部分，所以我们很自然地会考察这两个部分的分界点在哪里。假设分界点在位置```k```，那么sum_first怎么选？自然就是```nums[0:k]```里面和最小的```n```个元素；sum_second怎么选？自然就是```nums[k+1:n-1]```里面和最大的```n```个元素。

于是问题转化为，如何高效地在前```k```个元素里找和最小的```n```个元素？显然我们就找最小的```n```个元素即可。从做往右遍历的时候，用一个优先队列始终保存```n```个最小的元素，就可以得到```k```左边最小(包含```k```)的```n```个元素的和，记做```left[k]```。同理我们可以用NlogN的时候，从右往左遍历，得到```rightMax[k]```，表示```k```右边最大(不包含```k```)的```n```个元素的和。

本题的答案就是找一个全局最小的```left[k]-right[k]```
## Code
```java=
class Solution {
    public long minimumDifference(int[] nums) {
        int n = nums.length;
        long[] left = new long[n];
        long[] right = new long[n];
        long sum = 0;
        Queue<Integer> pq = new PriorityQueue(Collections.reverseOrder());
        for(int i=0; i<n; i++){
            int num = nums[i];
            pq.add(num);
            sum += num;
            if(pq.size()>n/3){
                sum -= pq.poll();
            }
            left[i] = sum;
        }
        sum = 0;
        pq = new PriorityQueue<>();
        for(int i=n-1; i>=0; i--){
            right[i] = sum;
            int num = nums[i];
            pq.add(num);
            sum += num;
            if(pq.size()>n/3){
                sum -= pq.poll();
            }
        }
        long ans = (long)Double.MAX_VALUE;
        for(int i=n/3-1; i<2*(n/3); i++){
            if(ans>left[i]-right[i]) ans = left[i]-right[i];
        }
        return ans;
    }
}
```