给定一个数组N个正整数,给每个数一个符号,正或者负使得所有数的的和的绝对值尽可能大。也就是使得这个
val(A, S) = |sum{ A[i]*S[i] for i = 0..N−1 }尽可能大s[i] = +1或者-1。
通过分析可以发现元素的正负不影响结果,问题转化为将数分成两堆,两堆只差最小。首先将元素全部转成正数顺便做了个count sort. 发现这个问题转化为多重背包问题。
DP背包参考http://wenku.baidu.com/view/cf9f0f8ecc22bcd126ff0c73.html
最开始只是将多重背包的代码原样copy过来,将每组数看作重量为i,value为i的物品,背包大小为sum/2。但是时间复杂度为N*N*A不满足要求。原因是背包里没有装东西,参考http://blog.youkuaiyun.com/caopengcs/article/details/10028269
将背包中装入达到重量j时剩余i的数量,如果无法达到为-1.
https://codility.com/demo/results/demoH2FANU-T7J/
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int[] hash = new int[101];
int max = 0;
int sum = 0;
for(int i=0; i<A.length; i++){
int a=Math.abs(A[i]);
hash[a]++;
sum+=a;
max = Math.max(max,a);
}
//
int half = sum/2+1;
int[] dp = new int[half];
for(int i=0; i<dp.length; i++){
dp[i]=-1;
}
dp[0]=0;
int can=0;
// dp save the left number of item i to achive the sum j
// -1 means sum 0-i < j
for(int i=1; i<=max; i++){
if(hash[i]>0){
for(int j=0; j<dp.length; j++){
if(dp[j]>=0){
dp[j]=hash[i];
if(j>can){
can = j;
}
}
else{
if(j-i>=0 && dp[j-i]>0){
dp[j] = dp[j-i]-1;
if(j>can){
can = j;
}
}
}
}
}
if(can>=half) break;
}
return Math.abs(sum-(can<<1));
}
}