2个非连续相等子阵列之间的最小绝对差

时间:2016-08-05 13:53:12

标签: arrays algorithm dynamic-programming

注意:我知道这里已经提出了这个问题,但我没有正确理解解决方案,而且我没有足够的评论来澄清我的查询。 (我是SO的初学者)

问题:给定一个大小为n的数组,将数组分成2个大小为n / 2&的非连续子阵列。 n / 2(如果n是偶数),和(n-1)/ 2& (n + 1)/ 2,(如果n为奇数),使得2个子阵列的总和之间的绝对差值最小。

示例:

4 5 3 55 -3 23 3 20 100 90

答案:0。 说明:{100, 20, 23, 4, 3}{5, 55, -3, 3, 90},两者总和为150。

我知道贪婪的方法对此不起作用,并认为这涉及动态编程。但是,我无法建模确保所考虑的子阵列大小相同的解决方案,我的解决方案生成任意大小的最小差异子阵列,这是一般分区问题。

我也不确定制作一张桌子是不是一个好主意,因为数字可能很大。 (虽然确定所有输入都在int的范围内。)

任何人都可以提供我可以应用的算法吗?

以下是已经提出(并已回答)问题的链接:live query

3 个答案:

答案 0 :(得分:1)

递归实现(Java):

private static long minimalDiff(int[] nums, int sumA, int sumB, int indexA, int indexB) {
    int index = indexA + indexB + 2;
    if (index == nums.length) {
        return Math.abs(sumA - sumB);
    } else if (Math.max(indexA, indexB) * 2 > nums.length - 1) {
        return Integer.MAX_VALUE;
    } else if (Math.abs(sumA + nums[index] - sumB) < Math.abs(sumB + nums[index] - sumA)){
        long result = minimalDiff(nums, sumA + nums[index], sumB, indexA + 1, indexB);
        if (result > 0) {
            result = Math.min(result, minimalDiff(nums, sumB + nums[index], sumA, indexB + 1, indexA));
        }
        return result;
    } else {
        long result = minimalDiff(nums, sumB + nums[index], sumA, indexB + 1, indexA);
        if (result > 0) {
            result = Math.min(result, minimalDiff(nums, sumA + nums[index], sumB, indexA + 1, indexB));
        }
        return result;
    }
}

public static long minimalDiff(int[] num) {
    if (num == null || num.length < 2){
        throw new IllegalArgumentException("num");
    }
    return minimalDiff(num, 0, 0, -1, -1);
}

public static void main(String[] args) {
    int [] test= {4, 5, 3, 55, -3, 23, 3, 20, 100, 90};
    System.out.println("Answer: "+minimalDiff(test));
}

打印:

Answer: 0

答案 1 :(得分:0)

这是使用递归的问题的c ++实现。

#include<bits/stdc++.h>
using namespace std;
void solve(int ele,int currSum,int index,int maxe,int * arr,int & answer,int sum,int n){
//      cout<<index<<" "<<ele<<" "<<currSum;
        if(ele==maxe){
            int ssum=sum-currSum;
            if(abs(currSum-ssum)<answer)
                answer=abs(currSum-ssum);
            return;
        }
        if(index>=n){
            return;
        }
        solve(ele+1,currSum+arr[index],index+1,maxe,arr,answer,sum,n);
        solve(ele,currSum,index+1,maxe,arr,answer,sum,n);
}
int FindMinimumDifference(int *arr,int n){
    int sum=0;
    for(int i=0;i<n;i++){
        sum+=arr[i];
    }
    int answer=INT_MAX;
    solve(0,0,0,n/2,arr,answer,sum,n);
    return answer;
}
int main(){
    int n,x;
    cin>>n;
    int * arr=new int[n];
    for(int i=0;i<n;i++){
        cin>>x;
        arr[i]=x;
    }
    cout<<FindMinimumDifference(arr,n);
    return 0;
}

答案 2 :(得分:0)

如果形成了一个半尺寸的子集,则其余元素形成另一个子集。我们将当前集合初始化为空并一一构建它。每个元素有两种可能性,要么是当前集合的一部分,要么是剩余元素(其他子集)的一部分。我们考虑每个元素的两种可能性。当当前集合的大小变为 n/2 时,我们检查该解决方案是否优于目前可用的最佳解决方案。如果是,那么我们更新最佳解决方案。