[Leetcode]2035 将数组分成两个数组并最小化数组和的差

这篇博客介绍了一个利用哈希表和二分查找算法来解决数组分割问题的方法。在给定长度为2n的整数数组中,需要将数组分成两个长度为n的子数组,目标是最小化两个子数组和的差值的绝对值。博主通过状态压缩和二分查找技巧,实现了高效的解决方案,避免了暴力递归导致的时间复杂度过高。博客详细解释了算法思路,包括如何构建哈希表存储前半部分数组的组合和差,以及如何在后半部分数组遍历中通过二分查找找到最佳匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

262周赛补题T4

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

给你一个长度为 2 * n 的整数数组。你需要将 nums 分成 两个 长度为 n 的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值nums 中每个元素都需要放入两个数组之一。

请你返回 最小 的数组和之差。

示例 1:

example-1

输入:nums = [3,9,7,3]
输出:2
解释:最优分组方案是分成 [3,9] 和 [7,3] 。
数组和之差的绝对值为 abs((3 + 9) - (7 + 3)) = 2 。

示例 2:

输入:nums = [-36,36]
输出:72
解释:最优分组方案是分成 [-36] 和 [36] 。
数组和之差的绝对值为 abs((-36) - (36)) = 72 。

示例 3:

example-3

输入:nums = [2,-1,0,4,-2,-9]
输出:0
解释:最优分组方案是分成 [2,4,-9] 和 [-1,0,-2] 。
数组和之差的绝对值为 abs((2 + 4 + -9) - (-1 + 0 + -2)) = 0 。

提示:

  • 1 <= n <= 15
  • nums.length == 2 * n
  • -107 <= nums[i] <= 107
class Solution {
public:
    int minimumDifference(vector<int>& nums) {
        int nn = nums.size(), n = nn / 2;
        unordered_map<int, set<int>> mps;
        for(int i = 0; i < 1 << n; ++ i){
            int s = 0, now = 0;
            for(int j = 0; j < n; ++ j){
                if(i & (1 << j)){
                    s ++;
                    now += nums[j];
                }else{
                    s --;
                    now -= nums[j];
                }
            }
            mps[s].insert(now);
        }
        int ans = INT_MAX;
        for(int i = 0; i < 1 << n; ++ i){
            int s = 0, now = 0;
            for(int j = 0; j < n; ++ j){
                if(i & (1 << j)){
                    s --;
                    now -= nums[j + n];
                }else{
                    s ++;
                    now += nums[j + n];
                }
            }
            if(mps.find(s) != mps.end()){
                auto it = mps[s].lower_bound(now);
                if(it != mps[s].end()){
                    ans = min(ans, abs(*it - now));
                }
                if(it != mps[s].begin()){
                    it --;
                    ans = min(ans, abs(*it - now));
                }
            }
        }
        return ans;
    }
};

算法思路

这题第一眼看到n<=15以为直接暴力dfs就可以,但事实上数据规模是2n,这样dfs肯定超时了。既然2n超时,n不超时,那我们可以把2n分成两半,然后用哈希存储第一次得到的值,第二次直接二分查找就能极大缩小时间复杂度。我们先对前n个数遍历,存储在mps中,mps是一个存储集合的哈希表,mps[i]表示前n个数中k+i个分到1组,k个分到2组的情况得到的两个数组的差,这里用状态压缩存储各种情况,举个例子

n = 3, 2n =6
110则表示nums[2]、nums[1]分到1组,nums[0]分到2组
两个数组的个数差为1
则mps[1]插入nums[2]+nums[1]-nums[0]

我们对所有情况(1<<n个)进行遍历后,对mps进行了初始化。然后对后n个数的所有情况进行遍历,也是1<<n个情况,遍历后n个数的结果则不用存入mps,只需要在mps中找到最合适的数就可以,举个例子

n = 3, 2n = 6
100则表示nums[2 + 3]分到1组,nums[1 + 3]、nums[0 + 3]分到2组
两个数组的个数差为-1,数组和差now = nums[5]-nums[4]-nums[3]
则要到mps[1]中找最合适的数
这个最合适的数就是最接近-now的数,而这里用lower_bound就能很快找到

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值