LeetCode 2035. 将数组分成两个数组并最小化数组和的差(状态压缩DP)

简介: LeetCode 2035. 将数组分成两个数组并最小化数组和的差(状态压缩DP)

文章目录

1. 题目

2. 解题

1. 题目

给你一个长度为 2 * n 的整数数组。

你需要将 nums 分成 两个 长度为 n 的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值 。

nums 中每个元素都需要放入两个数组之一。


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

示例 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:
输入: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
-10^7 <= nums[i] <= 10^7


2. 解题

数组折半,分别对一半进行状态枚举

枚举一边取的数的个数,将左右的满足二进制位个数的状态取出,排序,双指针求解最接近的

时间复杂度image.png

class Solution {
public:
    int minimumDifference(vector<int>& nums) {
        int n = nums.size()/2;
        int sum = accumulate(nums.begin(), nums.end(), 0);
        vector<int> a(nums.begin(),nums.begin()+n), b(nums.begin()+n,nums.end());
        vector<int> stateSum1 = getsum(a);//获取所有状态的和
        vector<int> stateSum2 = getsum(b);
        int dis = INT_MAX;
        for(int x = 0; x <= n; ++x)
        { // 第一个数组取x个数
            int y = n-x; // 第二个数组取y个数
            vector<int> s1, s2;//把两边取出来的和存储
            for(int state = 0; state < (1<<n); ++state)
            {
                if(count1(state)==x)
                    s1.push_back(stateSum1[state]);
            }
            for(int state = 0; state < (1<<n); ++state)
            {
                if(count1(state)==y)
                    s2.push_back(stateSum2[state]);
            }
            sort(s1.begin(), s1.end());//排序,双指针,求解最接近的
            sort(s2.begin(), s2.end());
            int len1 = s1.size(), len2 = s2.size();
            int i = 0, j = len2-1;
            while(i < len1 && j >= 0)
            {
                dis = min(dis, abs(sum-2*(s1[i]+s2[j])));
                if(s1[i]+s2[j] > sum-(s1[i]+s2[j]))
                    j--;
                else if(s1[i]+s2[j] < sum-(s1[i]+s2[j]))
                    i++;
                else
                    return 0;
            }
        }
        return dis;
    }
    vector<int> getsum(vector<int>& num)
    {
        int n = num.size();
        vector<int> ans(1<<n);
        for(int i = 0; i < n; ++i)
        {
            ans[1<<i] = num[i]; // 初始化
        }
        for(int state = 1; state < (1<<n); ++state)
        {
            int prevstate = state&(state-1);
            ans[state] = ans[state-prevstate] + ans[prevstate];
        }
        return ans;
    }
    int count1(int x)
    { // 计算二进制1的个数
        int ans = 0;
        while(x)
        {
            ans++;
            x = x&(x-1);
        }
        return ans;
    }
};

692 ms 76.4 MB C++

相关文章
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
43 0
|
4月前
|
算法
LeetCode第53题最大子数组和
LeetCode第53题"最大子数组和"的解题方法,利用动态规划思想,通过一次遍历数组,维护到当前元素为止的最大子数组和,有效避免了复杂度更高的暴力解法。
LeetCode第53题最大子数组和
|
4月前
|
存储 Java API
LeetCode------合并两个有序数组(4)【数组】
这篇文章介绍了LeetCode上的"合并两个有序数组"问题,并提供了三种解法:第一种是使用Java的Arrays.sort()方法直接对合并后的数组进行排序;第二种是使用辅助数组和双指针技术进行合并;第三种则是从后向前的双指针方法,避免了使用额外的辅助数组。
LeetCode------合并两个有序数组(4)【数组】
|
4月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
124 2
|
4月前
|
Python
【Leetcode刷题Python】剑指 Offer 03. 数组中重复的数字
解决剑指Offer题目 "数组中重复的数字" 的Python实现方法,通过使用字典来记录数组中每个数字的出现次数,快速找出重复的数字。
41 1
LeetCode------找到所有数组中消失的数字(6)【数组】
这篇文章介绍了LeetCode上的"找到所有数组中消失的数字"问题,提供了一种解法,通过两次遍历来找出所有未在数组中出现的数字:第一次遍历将数组中的每个数字对应位置的值增加数组长度,第二次遍历找出所有未被增加的数字,即缺失的数字。
|
4月前
|
前端开发
LeetCode------移动零(5)【数组】
这篇文章介绍了LeetCode上的"移动零"问题,提出了一种使用双指针的原地操作解法,该方法首先将非零元素移动到数组前端并保持相对顺序,然后填充后续位置为零,以达到题目要求。
|
2月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
23 4
|
2月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
24 0
Leetcode第三十三题(搜索旋转排序数组)
|
2月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
70 0