leetcode困难2163删除元素后和的最小差值

Posted qq_40707462

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode困难2163删除元素后和的最小差值相关的知识,希望对你有一定的参考价值。

给你一个下标从 0 开始的整数数组 nums ,它包含 3 * n 个元素。

你可以从 nums 中删除 恰好 n 个元素,剩下的 2 * n 个元素将会被分成两个 相同大小 的部分。

前面 n 个元素属于第一部分,它们的和记为 sumfirst 。
后面 n 个元素属于第二部分,它们的和记为 sumsecond 。
两部分和的 差值 记为 sumfirst - sumsecond

比方说,sumfirst = 3 且 sumsecond = 2 ,它们的差值为 1 。
再比方,sumfirst = 2 且 sumsecond = 3 ,它们的差值为 -1 。
请你返回删除 n 个元素之后,剩下两部分和的 差值的最小值 是多少。

示例 1:

输入:nums = [3,1,2]
输出:-1
解释:nums 有 3 个元素,所以 n = 1 。
所以我们需要从 nums 中删除 1 个元素,并将剩下的元素分成两部分。
- 如果我们删除 nums[0] = 3 ,数组变为 [1,2] 。两部分和的差值为 1 - 2 = -1- 如果我们删除 nums[1] = 1 ,数组变为 [3,2] 。两部分和的差值为 3 - 2 = 1- 如果我们删除 nums[2] = 2 ,数组变为 [3,1] 。两部分和的差值为 3 - 1 = 2 。
两部分和的最小差值为 min(-1,1,2) = -1

注意:是第一部分-第二部分的差值,而不是差的绝对值
思路:

  • 在 [n, 2n]中选择一个正整数 k;(保证每一部分都至少有 n 个元素)
    数组 nums 的前 k 个数属于第一部分,但只能保留 n 个;
    数组nums 的后 3n−k 个数属于第二部分,但只能保留 n 个;
    需要最小化第一部分和与第二部分和的差值。
  • 第一部分的和尽可能小,第二部分的和尽可能大,也就是说:
    我们需要在第一部分中选择 n 个最小的元素,第二部分中选择 n 个最大的元素。
  • 两个优先队列,反别大根堆和小根堆,都维持大小为n,同时用dp分别记录此时的和
  • 最后遍历求差最小
class Solution 
    public long minimumDifference(int[] nums) 
        int n = nums.length / 3;
        // min[i] 表示 nums[0] ~ nums[i] 个元素中选择 n 个元素和最小
        long[] min = new long[3 * n];

        // max[i] 表示 nums[i] ~ nums[3*n-1] 个元素中选择 n 个元素和最大
        long[] max = new long[3 * n];

        // 升序队列、 降序队列
        PriorityQueue<Integer> asc = new PriorityQueue<>();
        PriorityQueue<Integer> desc = new PriorityQueue<>((a, b) -> b - a);
        
        long sum_first = 0, sum_second = 0;
        for (int i = 0; i < 3 * n; i++) //以i为分界线,分前一部分和后一部分
            int l = i, r = 3 * n - 1 - i;
            int left = nums[l], right = nums[r];
            sum_first += left;
            desc.add(left);

            sum_second += right;
            asc.add(right);

            if (i >= n) //队列的大小维持n,留下的就是n个最大的或最小的
                sum_first -= desc.poll();
                sum_second -= asc.poll();
            
            min[l] = sum_first;
            max[r] = sum_second;
        

        // 遍历所有情况找到最小差值
        long minAns = Long.MAX_VALUE;
        for (int i = n - 1; i < 2 * n; i++) 
            minAns = Math.min(minAns, min[i] - max[i + 1]);
        
        return minAns;
    

以上是关于leetcode困难2163删除元素后和的最小差值的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 908. 最小差值 I / 1305. 两棵二叉搜索树中的所有元素 / 591. 标签验证器

(双指针二分Binary Search) leetcode 658. Find K closest Elements

LeetCode 2016 增量元素之间的最大差值[贪心] HERODING的LeetCode之路

LeetCode 2035. 将数组分成两个数组并最小化数组和的差

LeetCode 1049 最后一块石头的重量[动态规划] HERODING的LeetCode之路

leetcode 2035. 将数组分成两个数组并最小化数组和的差