package com.interview.books.question300;
import com.interview.utils.ArrayUtil;
/**
* Created by stefanie on 1/21/15.
*/
public class TQ56_ArrayDivision {
public boolean[] division(int[] array){
int sum = ArrayUtil.sum(array, 0, array.length - 1);
return find(array, sum / 2);
}
//state: sums[i][j] is the sum of subset of (0~ith element) closest to j.
//initialize: sum[0][*] = 0;
//function: sum[i][j] =
// Math.max(sum[i-1][j], sum[i-1][j-array[i]] + array[i]) if j >= array[i]
// sun[i-1][j] if j > array[i]
//result: sum[n-1][target]
//backtracing: if(( i > 0 && sums[i][k] > sums[i-1][k]) || (i == 0 && k == array[i])) mark[i] = true and k -= array[i]
private boolean[] find(int[] array, int target){
int len = array.length;
boolean[] mark = new boolean[len];
//if target equals or larger than sum, return all the set
int total = 0;
for (int i = 0; i < len; i++) total += array[i];
if(total <= target) {
for(int i = 0; i < len; i++) mark[i] = true;
return mark;
}
//opt[i][j] saves 0~i element sum closest to j.
int[][] sums = new int[len][target + 1];
for(int i = 0; i <= target; i++) sums[0][i] = 0;
for (int i = 1; i < len; i++) {
for(int j = 0; j < target + 1; j++){
if(j >= array[i]){ //i-th element is smaller than j
//find a more close solution
sums[i][j] = Math.max(sums[i-1][j], sums[i-1][j-array[i]] + array[i]);
} else
sums[i][j] = sums[i-1][j];
}
}
//backtrace the solution
int k = target;
int i = len - 1;
while(i >= 0 && k > 0){
//when not the first and opt[i][j] > opt[i-1][j] means i-th element is selected.
//when is the first element, if j = array[i], means i-th element is selected
if(( i > 0 && sums[i][k] > sums[i-1][k]) || (i == 0 && k == array[i])){
mark[i] = true;
k -= array[i];
}
i--;
}
return mark;
}
}