Compose the sum - java

Given two numbers, s (sum)
and n (posit number, ii), there are several ways in which I can express and,
as a sum of n whole numbers, strictly positive.
for s = 7, n = 3; 7 = 4 + 2 + 1 and
7 = 1 + 4 + 2 are not considered distinct.
I have to calculate i th solution.
Example for input:
11
6
5
example for output:
11=3+2+2+2+1+1 (5th mode to compose the sum)
I tried to use backtraking to compose these sums but the algorithm does not produce all the solutions.
static boolean checkSum(int sum, int remPos, int elem) {
if (sum < remPos)
return false;
if (sum > remPos * elem)
return false;
return true;
}
private ArrayList<Integer> back(ArrayList<Integer> sol, int crtPos,
int sum, ArrayList<Integer> ans) {
//the solution was found
if (index == i) {
ans.addAll(sol);
return sol;
} else if (index > i) {
return null;
}
if (crtPos == k + 1) {
crtPos = 1;
index++;
}
for (int j = sol.get(crtPos - 1); j > 0; j--) {
//add to solution
sol.add(crtPos, j);
//decreases from the remaining sum
sum -= j;
//check
if (checkSum(sum, k - crtPos, j)) {
sol = back(sol, crtPos + 1, sum, ans);
}
//remove from solution
sol.remove(crtPos);
sum += j;
}
return sol;
}

Don't know what is wrong with your code, but let me give you an alternate algorithm that doesn't use recursion, and doesn't require boxing the values.
First, you said that order of values doesn't matter, e.g. 7 = 4 + 2 + 1 and 7 = 1 + 4 + 2 is the same solution. In the algorithm below, we ensure that by stating that values must be in ascending order, e.g. 7 = 1 + 2 + 4.
Let me illustrate algorithm using example of s=10, n=5, which for reference gives the following solutions:
10 = 1 + 1 + 1 + 1 + 6
10 = 1 + 1 + 1 + 2 + 5
10 = 1 + 1 + 1 + 3 + 4
10 = 1 + 1 + 2 + 2 + 4
10 = 1 + 1 + 2 + 3 + 3
10 = 1 + 2 + 2 + 2 + 3
10 = 2 + 2 + 2 + 2 + 2
First, build an int[] and fill it with 1's, except the last value is s - (n-1), aka s - n + 1 (where n-1 is the sum of the 1's):
[1, 1, 1, 1, 6]
That is your first solution.
Now we "increment" that to the next solution, where the last value is always calculated, i.e. the next solution is:
[1, 1, 1, 2, x] where x = s - (1+1+1+2) = 5
[1, 1, 1, 2, 5]
We continue that as long as last value >= second last value:
[1, 1, 1, 3, 4]
Next one would have been [1, 1, 1, 4, 3] but that violates our constraint, so be walk backwards to previous value, and increment that. Since values must be ascending, we will fill the following positions with the same value (represented as = below), except we calculate the last value (x):
[1, 1, 2, =, x] where x = s - (1+1+2+2) = 4
[1, 1, 2, 2, 4]
Next one is easy:
[1, 1, 2, 3, 3]
Now we can't increment the 3rd position from 2 to 3, because that would give us [1, 1, 3, 3, 2] so we walk back one more position:
[1, 2, =, =, x] where x = s - (1+2+2+2) = 3
[1, 2, 2, 2, 3]
Now we have to walk back one more time:
[2, =, =, =, x] where x = s - (2+2+2+2) = 2
[2, 2, 2, 2, 2]
And we're done, because we can't walk any further back.
Here is code in compact form:
public static void compose(int s, int n) {
if (s < n || n < 1)
throw new IllegalArgumentException();
int[] values = new int[n];
Arrays.fill(values, 1);
values[n - 1] = s - n + 1;
for (;;) {
printSolution(s, values);
int i = n - 1, remain = values[i];
for (; --i >= 0; remain += values[i])
if (--remain >= ++values[i] * (n - i - 1))
break;
if (i < 0)
break;
Arrays.fill(values, i + 1, n, values[i]);
values[n - 1] = remain - values[i] * (n - i - 2);
}
}
public static void printSolution(int s, int[] values) {
System.out.print(s + " = " + values[0]);
for (int i = 1; i < values.length; i++)
System.out.print(" + " + values[i]);
System.out.println();
}
Output from compose(7, 3)
7 = 1 + 1 + 5
7 = 1 + 2 + 4
7 = 1 + 3 + 3
7 = 2 + 2 + 3
Output from compose(10, 5) is already shown earlier.
If you just need the i'th solution, remove the printSolution call, change the forever loop to loop i-1 times, and return the values array.

Related

Need to find even sums of digits in the array

I need to find even sum of digits from an array in Java.
Array: int [] cars = {3, 4, 6, 5};
Output: 8 10
Process:
3 + 4 == 7 --> not even
3 + 6 == 9 --> not even
3 + 5 == 8 --> even (so print it)
4 + 6 == 10 --> even (so print it)
4 + 5 == 9 --> not even
6 + 5 == 11 --> not even
If this is to check two value combination, you can use something like the below,
int[] arr = {1, 2, 3, 4, 5, 6};
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if ((arr[i] + arr[j]) % 2 == 0) {
System.out.println("" + arr[i] + "+" + arr[j] + "=even");
} else {
System.out.println("" + arr[i] + "+" + arr[j] + "=odd");
}
}
}
and the output will look like this
1+2=odd
1+3=even
1+4=odd
1+5=even
1+6=odd
2+3=odd
2+4=even
2+5=odd
2+6=even
3+4=odd
3+5=even
3+6=odd
4+5=odd
4+6=even
5+6=odd
filter the array into two lists, one for odd numbers and another for even numbers, then loop over each list summing each element with all the others and checking the results, at the end of the loop, remove that element.
the benefit of filtering the array to odd and even numbers is that odd + even is always odd, so, eliminating this case saves you some time.

How can I efficiently compute the sum of parts of an array of sizes in an arithmetic sequence?

I am trying to find the sum of parts of a given array with a length that is the sum of the first N positive integers for some whole number N. The size of each part for which I am to find the sum are the numbers in said arithmetic sequence. For instance, for an array of length 10, I need to find the sum of the first number, the next two numbers, and so on, until the next N numbers.
Example Input:
[1,4,5,2,6,7,9,8,7,10]
Example Output:
[1,9,15,34]//1, 4+5, 2+6+7, 9+8+7+10
Explanation:
The first sum is 1, the first element (index 0). The sum of the next two numbers is 4 + 5 = 9 (index 1 and 2). The sum of the next three numbers is 2 + 6 + 7 = 15 (index 3, 4, and 5). The sum of the last four numbers is 9 + 8 + 7 + 10 = 34 (index 6, 7, 8, 9).
You can compute the size of the result array using the formula for the sum of an arithmetic sequence, i.e. n(n + 1) / 2.
A prefix sum array can be applied here so so that any range sum can be computed in O(1) time with O(n) precomputation time and space (which is also the overall complexity of this algorithm).
final int[] input = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
// size * (size + 1) / 2 = input.length
final int size = (-1 + (int) Math.sqrt(1 + 8 * input.length)) / 2;
// derived by quadratic formula
final int[] result = new int[size];
final int[] sum = new int[input.length + 1];
for (int i = 1; i <= input.length; i++) {
sum[i] = sum[i - 1] + input[i - 1];
}
for (int i = 1, j = 0; i <= input.length; i += ++j) {
result[j] = sum[i + j] - sum[i - 1];
}
System.out.println(Arrays.toString(result));
Ideone Demo
The following algorithm is very efficient and does not rely on the summation formula to work (as you had asked about) other than to compute the length of the result array. This should not be a problem since it is basic algebra. If you use a List implementation you would not have to do that.
It also only sums only to the max allowed by the given array. So if you provide an array like
1 2 3 4 5 6 7 8 9 10 11 12 13
It will silently ignore 11 12 and 13 since they don't comprise enough values to continue.
Here is the algorithm with your original data set and the output.
int[] arr = { 1, 4, 5, 2, 6, 7, 9, 8, 7, 10 };
int start = 0; // start of group
int end = 0; // end of group
int[] sol = new int[(int)(-.5 + Math.sqrt(2*arr.length + .25))];
for (int i = 1; i <= sol.length; i++) {
// initialize the sum
int sum = 0;
// compute next end
end += i;
// and sum from start to end
for (int k = start; k < end; k++) {
sum += arr[k];
}
// old end becomes next start
start = end;
sol[i-1] = sum;
}
Prints
[1, 9, 15, 34]

How to get all the sets of consecutive numbers that add up to form a number?

I wanna create a program that generates sets of consecutive numbers that add up to form a number. For example. if the input number is 15, it should give -
7, 8
4, 5, 6
1, 2, 3, 4, 5
Some formula/algorithm/loop that can do something that fits in. It could generate an array or print it. This may seem a math problem or silly question but I can't actually figure out how to do that programmatically in Java.
Please try to give exact code that can do the thing.
Say your input is N. You know each set of k consecutive numbers will be centered around N/k. A solution exists for even k if N/k ends with 0.5, and odd k if N/k is an integer. The solution, if one exists, is the k integers centered around N/k.
k=1: 15/1 = 15, so 15 (trivial; may want to omit)
k=2: 15/2 = 7.5, so 7,8
k=3: 15/3 = 5, so 4,5,6
k=4: 15/4 = 3.75, so no solution
k=5: 15/5 = 3, so 1,2,3,4,5
k=6: 15/6 = 2.5, so 0,1,2,3,4,5
etc...
k=15: 15/15 = 1, so -6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8
You can easily modify this to limit to positive or nonnegative solutions.
I'll expand on #MBo's answer as it conveys a very clean algorithm. Wiki provides a good intro on arithmetic progressions, copied below for your convenience.
Sum
Derivation
The sum of a sequence starting with number a and consisting of n consecutive numbers:
S = (n/2) * [2 * a + (n-1) * d]
For consecutive numbers the step d is 1.
S = (n/2) * [2 * a + (n-1)]
Here we can transition to #MBo's post.
P = 2 * S = n * [2 * a + (n-1)]
We can iterate all possible counts of consecutive numbers n and check if the resulting a is valid (i.e. a is an integer).
Let's factor out a.
Say P = n * q => q = 2 * a + (n-1) => 2 * a = q - n + 1 => a = (q - n + 1) / 2
Filters
1) we mentioned we could iterate all possible counts of consecutive numbers n, but given p = n * q it's safe to say n needs to be a divisor of p.
p % n == 0
nMax = (int)Math.sqrt(p)
2) a is an integer and a = (q - n + 1) / 2 => (q - n + 1) is even => q - n is odd.
((q - n) & 1) == 1
Implementation
import java.util.*;
import java.lang.Math;
import java.util.stream.IntStream;
import static java.util.stream.Collectors.toList;
public class Progressions
{
public static void main(String[] args)
{
List<List<Integer>> list = Calculate(15);
System.out.print(list);
}
public static List<List<Integer>> Calculate(int s)
{
List<List<Integer>> list = new ArrayList<>();
int p = 2*s;
int nMax = (int)Math.sqrt(p);
for (int n=2; n<=nMax; n++) {
if(p % n == 0) {
int q = p / n;
if(((q - n) & 1) == 1) {
int a = (q - n + 1) / 2;
list.add(range(a,n));
}
}
}
return list;
}
public static List<Integer> range(int a, int n) {
return IntStream.range(a, a+n)
.boxed()
.collect(toList());
}
}
Consecutive numbers form arithmetic progression. If it starts from number a and has n members, it's sum is
S = n * (2 * b + (n-1)) / 2
so
P = 2 * S = n * (2 * b + (n-1))
So for given input S we can factorize 2*S into all possible pairs of integer factors P = n * q where n<=q, then get starting number
a = (q - n + 1) / 2
If a is integer (oddity of q and n differs) then pair (a, n) represents valid sequence starting from a with n members
Example for S = 15, 2S = 30:
30 = 2 * 15 => n = 2, a = 7 => (7,8)
30 = 3 * 10 => n = 3, a = 4 => (4,5,6)
30 = 5 * 6 => n = 5, a = 1 => (1,2,3,4,5)
Simple Python example:
import math
def getseqs(s):
print(s)
p = 2 * s
for n in range(2, math.ceil(math.sqrt(p))):
if (p % n == 0):
q = p // n
if (((q - n) & 1) == 1): #compare parity
a = (q - n + 1) // 2
seq = list(range(a, a+n))
print(seq, sum(seq))
getseqs(17)
getseqs(15)
getseqs(72)
17
[8, 9] 17
15
[7, 8] 15
[4, 5, 6] 15
[1, 2, 3, 4, 5] 15
72
[23, 24, 25] 72
[4, 5, 6, 7, 8, 9, 10, 11, 12] 72
Consider the int input is your input number (ex. 15) and List<int[]> list as a storage of the result consecutive numbers, here you go:
List<int[]> list = new ArrayList<>();
int lower = 1; // Start searching from 1
int upper = (int) Math.floor(input + 1 / 2); // Up to the half of input (8+9 > 15)
while (lower < upper) { // Iterate between the bounds
int sum = 0;
for (int i = lower; i <= upper; i++) { // Iterate and sum the numbers
sum += i;
if (sum == input) { // If it matches the input
// Add the range to the List
// You have to loop them by one and add to the
// List before version Java-8
list.add(IntStream
.range(lower, i + 1)
.toArray());
break; // Found, no reason to continue
}
if (sum > input) { // Terminate the loop if the sum overlaps
break;
}
lower++; // Increment and try the sums from
// a higher starting number
sum = 0; // Reset the sum
}
The result for the input 15 is a List of these arrays:
[1, 2, 3, 4, 5]
[4, 5, 6]
[7, 8]
Here's a suggestion:
For an input number N:
you only have to consider numbers between 1 and N.
you can maintain an interval that represents the current subset of [1,...,N]. Maintain the sum of the current interval. The first interval will be [1,1], and its sum is 1.
As long as the sum < N, increase the right end of the interval by one (for example, you start with the interval [1,1]. Since 1 < N, you extend it to [1,2].
If the sum of the current interval is equal to N, you add that interval to the output, remove the left end of the interval (also removing it from the current sum), and continue.
If the sum exceeds N, you also remove the left end of the interval (also removing it from the current sum), and continue.
You finish when the interval becomes [N,N] (which is the final interval you should add to the output).
For the input 15, here's how the interval will change over time:
Interval Sum
[1] 1
[1,2] 3
[1,2,3] 6
[1,2,3,4] 10
[1,2,3,4,5] 15 -> output [1,2,3,4,5]
[2,3,4,5] 14
[2,3,4,5,6] 20
[3,4,5,6] 18
[4,5,6] 15 -> output [4,5,6]
[5,6] 11
[5,6,7] 18
[6,7] 13
[6,7,8] 21
[7,8] 15 -> output [7,8]
[8] 8
[8,9] 17
[9] 9
[9,10] 19
[10]
...
[15] 15 -> output 15
You can probably make some optimization once the sum of two consecutive numbers becomes higher than the target sum, at which point you can terminate the loop, and just add the final set (which contains just the target sum).
It used a Window Sliding Technique/Algorithm. You can also google sliding window algorithm sum.
I am writing Implementation of the #Dave solution.
Try to Solve before asking... That's how we learn. (only if we can't get then ask)
Scanner s = new Scanner(System.in);
int inputNumber = s.nextInt();
int k = 1;
while(inputNumber/k >= .5){
Float sequenceMid = (float) inputNumber/k;
if( k%2 == 0 && (sequenceMid *2 == Math.ceil(sequenceMid *2)) ){
for(int i = ((int)Math.floor(sequenceMid) - (k/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}else if( (k%2 == 1) && (sequenceMid == Math.ceil(sequenceMid))){
for(int i = (Math.round(sequenceMid) - ((k-1)/2)),count=0 ; count < k ; count++,i++ ){
System.out.print(i + " ");
}
System.out.println();
}
k++;
}
Here is an idea that is similar to Eran's solution.
Since we're dealing with consecutive numbers, a cummulative sum (cumsum) can usually help. The basic idea is that we want to find the difference between two cummulative sums that gives exactly K, where K is 15 in your example.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
differences:
15 - 0 = 15 -> [1, 2, 3, 4]
21 - 6 = 15 -> [4, 5, 6]
36 - 21 = 15 -> [7, 8]
The cummulative sum starts from 0 so we can do 15 - 0 subtraction. The number included as the solution will be left-exclusive and right-inclusive. That just means add 1 to the left index (index starts from 0). Hopefully the pattern is quite clear.
The next task is to create an algorithm that does some sliding window with varying width across the cummulative sum. The idea is to search for the difference with the exact value of K. We can start at the beginning where the left and right side of the window points to 0. While the difference is <= K, we want to increase the right side of the window, enlarging the window and the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (] -> 0 - 0 = 0
2nd: (---] -> 3 - 0 = 3
3rd: (------] -> 6 - 0 = 0
Once the algorithm hit 15, it will print out the first answer, and then it will increase it one more time. However, once we have the difference > K, we want to increase the left number, reducing the difference.
number: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
cumsum: 0, 1, 3, 6, 10, 15, 21, 28, 36, 45, 55
1st: (-----------------] -> 15 - 0 = 15 <print>
2nd: (---------------------] -> 21 - 0 = 21
3rd: (-----------------] -> 21 - 1 = 20
Notice that the left side is bounded to be < K/2 since K//2 + (K//2 + 1) >= K (where the equality is possible due to integer division denoted by //). So we can stop the loop early when the left side reaches K//2 (due to left-exclusive).
public static int cumsum(int index) {
return index * (index + 1) / 2;
}
public static String printRange(int left, int right) {
StringBuilder buffer = new StringBuilder();
buffer.append('[');
for (int i=left+1;i<=right;i++) {
buffer.append(i);
buffer.append(',');
}
buffer.deleteCharAt(buffer.length()-1);
buffer.append(']');
return buffer.toString();
}
public static void main(String[] args) {
int K = 15;
int K_ov_2 = K/2;
int left_index = 0;
int right_index = 0;
int diff;
while (left_index < K_ov_2) {
diff = cumsum(right_index) - cumsum(left_index);
System.out.println("diff = " + diff + ", left = " + left_index + ", right = " + right_index);
if (diff == K) {
System.out.println(printRange(left_index,right_index));
}
if (diff <= K) {
right_index++;
} else {
left_index++;
}
}
}
I added the debug line so the output can become more obvious.
diff = 0, left = 0, right = 0
diff = 1, left = 0, right = 1
diff = 3, left = 0, right = 2
diff = 6, left = 0, right = 3
diff = 10, left = 0, right = 4
diff = 15, left = 0, right = 5
[1,2,3,4,5]
diff = 21, left = 0, right = 6
diff = 20, left = 1, right = 6
diff = 18, left = 2, right = 6
diff = 15, left = 3, right = 6
[4,5,6]
diff = 22, left = 3, right = 7
diff = 18, left = 4, right = 7
diff = 13, left = 5, right = 7
diff = 21, left = 5, right = 8
diff = 15, left = 6, right = 8
[7,8]
diff = 24, left = 6, right = 9

Break a positive integer into the sum of at least two positive integers and return the maximum product

So this is a recent interview question, Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.
For example, given n = 2, return 1 (2 = 1 + 1); given n = 10, return
36 (10 = 3 + 3 + 4).
I'm trying to solve it recursively, The approach is
first split the number into two halves and find the max product and keep splitting each half till we get the maximum.
This is my code,
private int integerBreak(int n, int maxProduct){
int index = 0;
for(int i=0; i<n; i++){
if((i * (n-i)) >maxProduct) {
maxProduct = i*(n-i);
index = i;
}
}
return integerBreak(index, index) * integerBreak(n - index, n-index);
}
public int integerBreak(int n) {
int maxProduct = 0;
return integerBreak(n, maxProduct);
}
Now I'm a little lost with the base condition as to how to terminate recursion. I'd appreciate if someone can help me with my approach rather than coming up with the completely different solution.
I wrote a straightforward Java application to calculate the maximum product for the sum of integers of the numbers 2 through 20. The first number is the sum. The middle numbers are the factors of the sum. The final number is the product of the factors. Here are the results.
2 [1, 1] 1
3 [2, 1] 2
4 [2, 2] 4
5 [3, 2] 6
6 [3, 3] 9
7 [4, 3] 12
8 [3, 3, 2] 18
9 [3, 3, 3] 27
10 [4, 3, 3] 36
11 [3, 3, 3, 2] 54
12 [3, 3, 3, 3] 81
13 [4, 3, 3, 3] 108
14 [3, 3, 3, 3, 2] 162
15 [3, 3, 3, 3, 3] 243
16 [4, 3, 3, 3, 3] 324
17 [3, 3, 3, 3, 3, 2] 486
18 [3, 3, 3, 3, 3, 3] 729
19 [4, 3, 3, 3, 3, 3] 972
20 [3, 3, 3, 3, 3, 3, 2] 1458
The calculateMaximumFactors method calculates the factors with the maximum product. The factor method generates the factors of the sum. The product method calculates the product of the factors. Here's the code:
package com.ggl.testing;
import java.util.Arrays;
public class MaximumProduct {
public static void main(String[] args) {
for (int sum = 2; sum <= 20; sum++) {
System.out.print(sum + " ");
System.out.println(calculateMaximumFactors(sum));
}
}
private static String calculateMaximumFactors(int sum) {
int[] previousFactors = new int[0];
int maxProduct = 0;
for (int i = 2; i <= sum; i++) {
int[] factors = factor(sum, i);
int product = product(factors);
if (product > maxProduct) {
maxProduct = product;
previousFactors = Arrays.copyOf(factors, factors.length);
}
}
return Arrays.toString(previousFactors) + " " + maxProduct;
}
private static int[] factor(int sum, int divisor) {
if (sum < divisor) {
return new int[0];
}
int num = sum / divisor;
int remainder = sum % divisor;
int[] result = new int[divisor];
for (int i = 0; i < divisor; i++) {
result[i] = num;
if (remainder > 0) {
result[i]++;
remainder--;
}
}
return result;
}
private static int product(int[] factors) {
int product = 1;
for (int i = 0; i < factors.length; i++) {
product *= factors[i];
}
return product;
}
}
Here's my solution to the problem : (Idea : It is optimal to break integer into multiple of 3)
public int integerBreak(int n) {
// base case :
if (n == 2 || n == 3){
return (n-1);
}
int maxProduct = 1;
while (n > 4){
n -= 3;
maxProduct *= 3; // Keep multiplying 3.
}
return (n * maxProduct); // multiply with left over n.
}
This is simple O(N) solution. Hope this helps someone !
The idea is to break the number into multiples of 2 or 3. If you write the breaking results for couple of numbers like 7 to 10 you should get the idea. Assuming the max number is 60, there is a simple dynamic solution:
int dp[60];
public:
int integerBreak(int n)
{
dp[1]=1,dp[2]=1,dp[3]=2,dp[4]=4,dp[5]=6,dp[6]=9;
for(int i=7;i<=n;i++)
dp[i]=max(dp[i-3]*3,dp[i-2]*2);
return dp[n];
}
};
As I wrote in the comment above, we have to break the number into 3s. If we derive the maxima, we get the e (base of the logarithm) to be 2 < e < 3. But the thing is 6= 33 and 6=22*2 so every triplet of 2 can be replaced with a tuple of 3 for the maximum product.
So here is the code I wrote. It is in Python so I hope you don't mind -
def maximize_product(num):
product = 1
if num == 2 or num == 3:
return num - 1
else:
while num > 4:
product = product * 3
num -= 3
return num * product
If you make a loop trying to find the number then is going to get complicated and not as efficient (the greater the number, the longest will take you to find it, you need to consider indexes, etc etc)
The best and fastest algorithm is the middle point algorithm, i.e divide the given number by 2, calculate deviation if number is odd, finally calculate the product
Example:
static int func(int number) {
int result = 0;
if (number < 0) {
System.err.println("no negative allowed");
System.exit(0);
}
int a = 0;
int b = 0;
a = number / 2;
b = number / 2;
a += number - (a + b);
result = a * b;
System.out.println(" this is a " + a);
System.out.println(" this is b " + b);
return result;
}
if you execute it like
public static void main(String[] args) {
int number = 9;
int result = func(number);
System.out.println(result);
}
will get the results correctly...

Find minimum total server downtime

You have an array that represents a line of servers by their "Down-time cost". You can only access servers at either end of the line (i.e You can only get the first server or the last server).
The order at which a server is picked is multiplied with it's downtime and added to a "total downtime cost".
Design a program to find the least total downtime cost.
For example, for the array:
[5, 3, 6, 2, 1, 4]
the least total downtime is:
5*1 + 4*2 + 3*3 + 6*4 + 2*5 + 1*6 = 62
This is the code that I use for getting this result:
public static void main(String[] args){
int[] serverDowntimes = {5, 3, 6, 2, 1, 4};
int start = 0;
int end = serverDowntimes.length - 1;
long totalCost = 0;
int serverNumber = 1;
while(start <= end){
if(serverDowntimes[start] >= serverDowntimes[end]){
totalCost += serverNumber * serverDowntimes[start];
start++; //Increment start (i.e. First server in line was recovered)
}else{
totalCost += serverNumber * serverDowntimes[end];
end--; //Decrement end (i.e. Last server in line was recovered)
}
serverNumber++;
}
System.out.println(totalCost);
}
However my code fails when I have this array:
[5, 3, 1, 8, 2, 4]
For this array my code outputs:
76 (5*1 + 4*2 + 3*3 + 2*4 + 8*5 + 1*6)
However the better answer should be:
73 (4*1 + 2*2 + 8*3 + 5*4 + 3*5 + 1*6)
How do I modify my code so that it also works with the arrays similar to:
[5, 3, 1, 8, 2, 4]
I wrote brute-force algorithm that tests every possible solution and picks the best.
For following problem set:
[5, 3, 1, 8, 2, 4]
It generates solution of:
lowest cost: 72, with combination: [5, 4, 2, 8, 3, 1]
Which we can prove by calculating:
5*1 + 4*2 + 2*3 + 8*4 + 3*5 + 1*6 = 72
Here's the solver:
import java.util.*;
class ServersProblemSolver {
public static void main(String[] args) {
int[] serverDowntimes = {5, 3, 1, 8, 2, 4};
int totalCost = Integer.MAX_VALUE;
List<Integer> bestCombination = new ArrayList<>();
for (int i = 0; i < Math.pow(2, serverDowntimes.length); i++) {
int temporaryCost = 0;
int combination = i;
int start = 0;
int end = serverDowntimes.length - 1;
List<Integer> temporaryCombination = new ArrayList<>();
for (int k = 0; k < serverDowntimes.length; k++) {
if (combination % 2 == 1) {
temporaryCost += (k + 1) * serverDowntimes[start];
temporaryCombination.add(serverDowntimes[start]);
start++;
} else {
temporaryCost += (k + 1) * serverDowntimes[end];
temporaryCombination.add(serverDowntimes[end]);
end--;
}
combination /= 2;
}
System.out.println("combination " + i + ": " + temporaryCombination + ", cost : " + temporaryCost);
if (temporaryCost < totalCost) {
totalCost = temporaryCost;
bestCombination = temporaryCombination;
} else {
temporaryCombination.clear();
}
}
System.out.println("lowest cost: " + totalCost + ", with combination: " + bestCombination);
}
}
How does it work?
Take every binary combination between 0 and 2 ^ N, where N is the size of your array.
Pick a server from start or end according to succesive binary digit (whether it's 0 or 1)
101 will take start, end, start
000 will take end, end, end
110 will take end, start, start
etc.
After calculating the result of current combination, check if it's better than the previous best, and if so, save it.

Categories

Resources