package com.interview.algorithms.dp;
/**
* Created by chenting on 2014/6/26.
*
* Given a string of digits, find the minimum number of additions required for the string to equal some target number.
* Each addition is the equivalent of inserting a plus sign somewhere into the string of digits. After all plus signs are inserted,
* evaluate the sum as usual. For example, consider the string "12" (quotes for clarity). With zero additions, we can achieve the number 12.
* If we insert one plus sign into the string, we get "1+2", which evaluates to 3. So, in that case, given "12", a minimum of 1 addition is required to
* get the number 3. As another example, consider "303" and a target sum of 6. The best strategy is not "3+0+3", but "3+03".
* You can do this because leading zeros do not change the result.
* Write a class QuickSums that contains the method minSums, which takes a String numbers and an int sum. The method should calculate and return the
* minimum number of additions required to create an expression from numbers that evaluates to sum. If this is impossible, return -1.
*/
public class C12_14_QuickSums {
public final static int BRUTE_FORCE = 0;
public final static int RECURSIVE = 1;
public final static int DYNAMIC_PROGRAMING = 2;
public int type = BRUTE_FORCE;
public int count = 0;
public C12_14_QuickSums(int type) {
this.type = type;
}
public int minSums(String numbers, int sum){
int[] intNumbers = new int[numbers.length()];
for(int i = 0; i < numbers.length(); i++ ){
intNumbers[i] = numbers.charAt(i) - '0';
}
switch(type){
case BRUTE_FORCE: return minSumsByBF(intNumbers, sum);
case RECURSIVE: return minSumsByRecursive(numbers.length(), intNumbers, sum);
case DYNAMIC_PROGRAMING: return minSumsByDP(intNumbers, sum);
default: return -1;
}
}
/**
* use Binary number increase to simulate the Brute Force search process.
* @param numbers
* @param sum
* @return
*/
private int minSumsByBF(int[] numbers, int sum){
int min = Integer.MAX_VALUE;
int N = numbers.length - 1;
int[] additions = new int[N];
for(int i = 0; i < N; i++) additions[i] = 0;
while(additions[N-1] != 2){
count++;
additions[0]++;
for(int i = 0; i < N - 1; i++){
if(additions[i] == 2){
additions[i] = 0;
additions[i+1]++;
}
}
long realSum = 0;
long current = numbers[0];
int count = 0;
for(int i = 1; i <= N; i++){
if(additions[i-1] == 0) current = current * 10 + numbers[i];
else {
realSum += current;
current = numbers[i];
count++;
}
}
realSum += current;
if(realSum == sum && count < min){
min = count;
}
}
return min < Integer.MAX_VALUE? min : -1;
}
private int minSumsByDP(int[] numbers, int sum){
return -1;
}
private int minSumsByRecursive(int n, int[] numbers, int sum){
count++;
if (n == 0) {
if (sum == 0) return 0;
else return -1;
} else if (n == 1) {
if (sum == numbers[0]) return 0;
else return -1;
}
int deg = 1;
int current = 0;
int min = Integer.MAX_VALUE;
int split = -1;
for (int i=0; i<n;i++) {
current += numbers[n-i-1] * deg;
if(current <= sum) {
int t = minSumsByRecursive(n - i - 1, numbers, sum - current);
if (t != -1 && t <= min) {
min = t;
split = i;
}
}
deg = deg*10;
}
if (min == Integer.MAX_VALUE) return -1;
else if (split == n-1) return min;
else return min + 1;
}
}