Let's say n = 4. With recursion I want to return:
1 1 1 1
1 1 2
1 3
2 1 1
2 2
3 1
4
Basically I want to take number n and with by combining numbers 1,2,3 and 4 create all possible variations when the number of sum == n.
This was my first idea, but it gives me
Exception in thread "main" java.lang.StackOverflowError
public static void test_2(String path, int sum, int n){
if(sum == n){
System.out.println(path);
} else {
test_2(path+"1 ", sum + 1, n);
test_2(path+"2 ", sum + 2, n);
test_2(path+"3 ", sum + 1, n);
test_2(path+"4 ", sum + 2, n);
}
}
The main problem is that you are always recursing when sum != n. When the sum gets bigger than n, you never stop, hence the StackOverflowError This means we need to add a check and terminate when the sum gets bigger:
public static void test_2(String path, int sum, int n) {
if (sum == n) {
System.out.println(path);
} else if (sum < n) { // <-- only recurse if the sum is less than the target
test_2(path+"1 ", sum + 1, n);
test_2(path+"2 ", sum + 2, n);
test_2(path+"3 ", sum + 3, n);
test_2(path+"4 ", sum + 4, n);
}
}
As a side-note, in your 2 last calls, you wrote 1 and 2 instead of 3 and 4, but that was probably just a typo.
Output from calling test_2("", 0, 4):
1 1 1 1
1 1 2
1 2 1
1 3
2 1 1
2 2
3 1
4
But do note that your current code is not very dynamic: it wouldn't work if you were to give values greater than 4 for n. I would suggest refactoring it a little.
Related
This question already has answers here:
Differences between System.out.println() and return in Java
(4 answers)
Closed 3 years ago.
I have to write a method int sumBeyond(int k) to find the least n such that the sum of the natural numbers smaller than n exceeds k.
However, when I try to test the method it doesn't return any value.
public static int sumBeyond(int k){
int i=1;
int sum=0;
while(i<k){
sum=sum+i;
i=i+1;
}
return sum;
}
I tried calling the function this way, in the main method:
sumBeyond(100);
int sum100 = sumBeyond(100);
System.out.println("Sum is " + sum100);
Then small improvements:
public static int sumBeyond(int k) {
int i = 1;
int sum = 0;
while (i < k) {
sum += i;
++i;
}
return sum;
}
public static int sumBeyond(int k) {
int sum = 0;
for (int i = 1; i < k; ++i) {
sum += i;
}
return sum;
}
public static int sumBeyond(int k) {
// return (k - 1) * (1 + k - 1) / 2;
return (k - 1) * k / 2;
}
To solve the problem stated:
Find n such that sum upto n-1 >= k' where k' is k - 1.
Sum upto n-1 is (n - 1) * n / 2 >= k'
So we get:
x² - x - 2k'
------------ >= 0
2
Solution for = 0:
a = 1/2
b = -1/2
c = -2k'
_________
-b +/- V b² - 4ac
x = ------------------
2a
x = 1/2 +/- sqrt(1/4 + 4k'/4) =
= 1/2 +/- 1/2 . sqrt(1 + 4k')
Positive x
x = 1/2 + 1/2 . sqrt(4k' + 1)
public static int sumBeyond(int k) {
double x = (Math.sqrt(4 * (k-1) + 1) + 1) / 2;
return (int) Math.ceil(x);
}
The solution should be given the math as comment.
If I got your question right, you want to find the least n such that the sum of the natural numbers smaller than n exceeds k and thus, you shouldn't return the sum itself, because it is not n but needs to be calculated in order to find the smallest n.
You can do it the following way:
public static int sumBeyond(int k) {
int n = 0;
int sum = 0;
for (int i = 0; i < k; i++) {
// provide an intermediate sum (the one before this step) for logging purpose
int intermediateSum = sum;
// sum up
sum += i;
// set the return value to the current "natural number"
n = i;
// print some detailed debug log
System.out.println("sum:\t" + sum +
" (" + intermediateSum + " + " + i + ")\t——>\tn = " + n);
// exit the loop if the sum is greater than k
if (sum >= k) {
break;
}
}
return n + 1;
}
Calling it in a main like this
public static void main(String[] args) {
int k = 100;
System.out.println("The least n" +
+ "such that the sum of the natural numbers smaller than n exceeds "
+ k + " is " + sumBeyond(k));
}
will print
sum: 0 (0 + 0) ——> n = 0
sum: 1 (0 + 1) ——> n = 1
sum: 3 (1 + 2) ——> n = 2
sum: 6 (3 + 3) ——> n = 3
sum: 10 (6 + 4) ——> n = 4
sum: 15 (10 + 5) ——> n = 5
sum: 21 (15 + 6) ——> n = 6
sum: 28 (21 + 7) ——> n = 7
sum: 36 (28 + 8) ——> n = 8
sum: 45 (36 + 9) ——> n = 9
sum: 55 (45 + 10) ——> n = 10
sum: 66 (55 + 11) ——> n = 11
sum: 78 (66 + 12) ——> n = 12
sum: 91 (78 + 13) ——> n = 13
sum: 105 (91 + 14) ——> n = 14
The least n such that the sum of the natural numbers smaller than n exceeds 100 is 15
I really hope I got this right, still not sure...
Oh, and if 0 is not a natural number, start iterating at 1.
So as has been noted above, the issue was not that your method was not returning something, but that you were doing nothing with what was returned. Also, as noted above, you were focused on finding the sum, but that is not actually what the question asked.
I am sympathetic to your use of a while loop here since it may not execute at all and since you don't know a priori how many times it will run. So I rewrote it to check the right things and adapted the main from deHaar to exercise it. That allowed me to hand check the answers, because some of the cases of equality and need for "numbers less than" rather than "numbers less than or equal to" were subtle.
The math teacher in me really likes the quadratic formula approach from Joop Eggen; it's just harder to get right (and indeed, if I were going to do it, I would end up testing that it's consistent with what I have here).
public class ShadesOfLittleGauss {
public static int sumBeyond(int k) {
int i = 1; //have summed (trivially) all natural numbers less than 1 so far
int sum = 0;
while (sum <= k) { //needs to exceed, so <=
sum = sum + i;
i = i + 1;
}
return i;
}
public static void main(String[] args) {
for (int k = -1; k < 10; k++) {
System.out.println("The least number " +
"such that the sum of the natural numbers smaller than n exceeds " +
k + " is " + sumBeyond(k));
}
}
}
output (you can hand check these are correct as stated):
The least number such that the sum of the natural numbers smaller than n exceeds -1 is 1
The least number such that the sum of the natural numbers smaller than n exceeds 0 is 2
The least number such that the sum of the natural numbers smaller than n exceeds 1 is 3
The least number such that the sum of the natural numbers smaller than n exceeds 2 is 3
The least number such that the sum of the natural numbers smaller than n exceeds 3 is 4
The least number such that the sum of the natural numbers smaller than n exceeds 4 is 4
The least number such that the sum of the natural numbers smaller than n exceeds 5 is 4
The least number such that the sum of the natural numbers smaller than n exceeds 6 is 5
The least number such that the sum of the natural numbers smaller than n exceeds 7 is 5
The least number such that the sum of the natural numbers smaller than n exceeds 8 is 5
The least number such that the sum of the natural numbers smaller than n exceeds 9 is 5
UPDATE: I did solve the quadratic and came up with the following which agrees with the simpler approach.
public static int sumBeyond2(int k) {
if (k < 0) { //do not take squareroots of negatives
return 1;
}
double x = -1.0 / 2 + Math.sqrt(1 + 8 * k) / 2; //from solving quadratic inequality n(n+1)/2.0 > k
if (Math.abs(Math.round(x) - x) < 0.0000001) { //special case, it is an integer, so ceil won't reliably add 1
return 1 + 1 + (int) Math.round(x);
}
return 1 + (int) Math.ceil(x); //adding 1 because of wording, integers less than, ceil because needs to exceed k
}
I want to create a recursion function that returns the minimum options to create a certain number using numbers 1, 5 and 7 (Fixed predetermined numbers). It is important that this is done only by recursion without loops at all.
For example:
if n = 10 then it is given to the scheme by 5 + 5 which is 2 numbers, so this is the minimum and this is what we will get (as opposed to 7 + 1 + 1 + 1 or 5 + 1 + 1 + 1 + 1 + 1 that is 4 or 6 Options that are longer).
If n = 6 then we get a result of 2 (because it is given as a sum of 1 + 5).
If n = 5 (or 7 or 1) then we get a result of 1 (because it is given by the number only).
class TEST {
static int countMin( int S[], int m, int n ,int min)
{
if (n == 0)
return 1;
if (n < 0)
return 0;
if (m <=0 && n >= 1)
return 0;
return Math.min(min,countMin( S, m - 1, n ,min-1) + countMin( S, m, n-S[m-1],min-1 ));
}
public static int f(int n) {
int arr[] = {1, 5, 7};
return countMin(arr, arr.length, n,n);
}
public static void main(String[] args)
{
int n = 10;
System.out.println("The number "+n+ " - " + f(n) + " minimum options to create");
int n2 = 7;
System.out.println("The number "+n2+ " - " + f(n2) + " minimum options to create");
int n3 = 6;
System.out.println("The number "+n3+ " - " + f(n3) + " minimum options to create");
}
}
I get for n = 10 and n = 5 for the correct result but not for n = 6 which should return 2.
*I've used this link: https://www.geeksforgeeks.org/coin-change-dp-7/
Think of a tree where each node has a value and has 3 children with its value decremented respectively by 7, 5, and 1
So node with total 15 would have children with values 8, 10, 14
We can start with first node having your total, and calculate each level and stop when we find a child worth 0. We also stop looking at a child if its value is less than 0.
For 10 for example:
10
/ | \
3 5 9
/ | \ / | \ / | \
-4 -2 2 -2 0 4 2 4 1
We find zero at depth 2
private static int calculate(int total, int depth) {
if (total == 0)
return depth;
else {
int i = total - 7 >= 0 ? calculate(total - 7, depth+1) : Integer.MAX_VALUE;
int j = total - 5 >= 0 ? calculate(total - 5, depth+1) : Integer.MAX_VALUE;
int k = total - 1 >= 0 ? calculate(total - 1, depth+1) : Integer.MAX_VALUE;
return Collections.min(Arrays.asList(i, j, k));
}
}
This
int n = 10;
System.out.println("The number "+n+ " - " + calculate(n, 0) + " minimum options to create");
n = 7;
System.out.println("The number "+n+ " - " + calculate(n, 0) + " minimum options to create");
n = 6;
System.out.println("The number "+n+ " - " + calculate(n, 0) + " minimum options to create");
n = 18;
System.out.println("The number "+n+ " - " + calculate(n, 0) + " minimum options to create");
Outputs this
The number 10 - 2 minimum options to create
The number 7 - 1 minimum options to create
The number 6 - 2 minimum options to create
The number 18 - 4 minimum options to create
EDIT:
The same in a funky lambda style:
private static int calculate(int total, int depth) {
return total == 0 ?
depth :
Stream.of(7, 5, 1)
.map(i -> total - i >= 0 ? calculate(total - i, depth+1) : Integer.MAX_VALUE)
.min(Integer::compare)
.get();
}
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.
Here is example of my input data:
5 // Number of 1D arrays, in this case we'll have array[5][3]
1 2 3 // Values of array[i][0..2]
1 1 1
1 0 0
1 1 0
2 1 0
And output is:
12 // Maximum sum ({1 2 3} + {1 1 1} + {2 1 0} = {4 4 4} = 12) - END SUM VALUES MUST BE EQUAL(4 4 4).
3 // Number of arrays used to get this sum
The problem is to find maximum sum using n arrays, and secod condition is to use minimum number of arrays. Also if sum > 300 we stop algorithm. (300 is maximum). Here is my code, it's I get good answers but it's time complexity is O(2^n-1). I'm thinking that it's possible to save results in some way and don't calculate same things many times, but I don't know how yet.
public static int[] fuel(int start, int[] sum, int counter) {
int[] val = { sum[0] + crystal[start][0], sum[1] + crystal[start][1], sum[2] + crystal[start][2] };
int newSum = val[0] + val[1] + val[2];
if(newSum > 300)
return null;
if(val[0] == val[1] && val[1] == val[2]) { // All 3 values have to be equal!
if(newSum > result[0]) {
result[0] = newSum;
result[1] = counter;
} else if(newSum == result[0] && result[1] > counter) {
result[1] = counter;
}
}
if(start + 1 < crystalNumber) {
fuel(start + 1, val, counter + 1);
fuel(start + 1, sum, counter);
}
return result;
}
This may not be the best algorithm to solve this but it should be quicker than O(2^N).
The idea is to record all reachable sums as you loop through the input array. You can use a dictionary whose key is a unique hash of the possible sums, for the sake of simplicity let's just assume the key is a string which concatenates the three sums, for example, the sums [3,5,4] we'll use the key "003005004" , the value of the dictionary will be the minimum numbers of arrays to reach that sum.
So in your case:
1 2 3 => [001002003] =1
1 1 1 => [001001001] =1, [002003004]=2 (itself and use [001002003] from above)
1 0 0 => [001000000] =1, [002002003] =2, [002001001] =2, [003003004] =3
1 1 0 ...
2 1 0 ...
In the end, you will find [004004004] =3 and that's your answer.
This may seems going through all combinations as well so why it's quicker, it's because the maximum sum is 300 for each number, so in the very worst case, we may have 301^3 keys filled and have to update their values for each new input array. This is however still O(n) and despite of the large constant, it should still run much faster than O(2^n). (If you solve 300^3*n = 2^n, n is around 30-ish)
A simple hash function would be a*301*301+b*301+c
I think the problem is given m 1-D arrays and a number n, find the maximum sum using n arrays from m;
The solution looks straight forward. keep sum of each 1-D array in a separate array, say sum[]
1 2 3 = 6
1 1 1 = 3
1 0 0 = 1
1 1 0 = 2
2 1 0 = 3
Sort this array sum
6,3,3,2,1
and return the sum of first n elements of this array.
import java.util.ArrayList;
public class Euler4{
public static void main(String [] args){
int size = 0;
int product = 0;
for(int i = 102; i > 100; i--){
for(int j = 102; j > 100; j--){
ArrayList<Integer> digits = new ArrayList<Integer>();
product = i*j;
int index = 0;
while(product > 0){
digits.add(index,product%10);
product /= 10;
index++;
}
for(int element : digits)
System.out.println("digits :" + element);
size = digits.size() - 1;
if(test(0,size,digits)){
System.out.println("i and j " + i + " " + j);
break;
}
}
}
}
public static boolean test(int i, int size, ArrayList<Integer> digits){
if(digits.get(size).equals(digits.get(i))){
if(size == i || size - i == 1){
return true;
}else{
System.out.println("i: " + i + " size: " + size + " digits#i: " + digits.get(i) +" digits#size " + digits.get(i));
size--;
i++;
if(!test(i, size, digits))
return false;
}
}
return false;
}
}
Here's the output:
digits :4 index: 0
digits :0 index: 1
digits :4 index: 2
digits :0 index: 3
digits :1 index: 4
digits :2 index: 0
digits :0 index: 1
digits :3 index: 2
digits :0 index: 3
digits :1 index: 4
digits :2 index: 0
digits :0 index: 1
digits :3 index: 2
digits :0 index: 3
digits :1 index: 4
digits :1 index: 0
digits :0 index: 1
digits :2 index: 2
digits :0 index: 3
digits :1 index: 4
i: 0 size: 4 digits#i: 1 digits#size 1
i: 1 size: 3 digits#i: 0 digits#size 0
I think there's a problem with the while loop and a problem with the recursion. The values that get ran through the test() method is the last set of values that goes into the array and that is 10201 so then even though the while loop messed up, the recursive method should still have returned true. I don't know why it's not.
This is the problem:
http://projecteuler.net/problem=4
Thanks.
EDIT: I fixed it up to be a bit more efficient and to give the max palindrome instead of just listing palindromes. Here's the final if anyone is interested: http://pastebin.com/qJUpZVzK
Your third call to test is returning true, but your second call to test is not using that value. It's falling to the bottom of the method and returning false, when you actually want it to return true.
When you call test recursively, you want to return true (from test) if the recursive call returned true.
Change
if(!test(i, size, digits))
return false;
near the bottom, to
return test(i, size, digits);
Your loop will never reach 0, because the condition will always be satisfied.
while(product > 0){
digits.add(index,product%10);
product /= 10;
index++;
}
To be honest, I think the easiest way to check for palindromes is this:
public boolean palindrome (int n) {
return String.valueOf(n).equals(new StringBuilder(String.valueOf(n)).reverse().toString());
}
The problem lies here:
while(product > 0){
digits.add(index,product%10);
product /= 10;
index++;
}
product can never be reduced to a negative number, (less than 0), by dividing by 10; which means that you will never exit this while loop. Lets look at this further:
1- product is created and it's value is 102*102=10404. (The first time through the for loops.)
2- product is divided by 10 to get 1040.4
3- While loop is checked, 1040.4 > 0, enter again.
4- product is divided by 10 to get 104.04
5- While loop is checked, 104.04 > 0, enter again.
Repeat steps 4 and 5 infinitely, because even if you keep dividing below 1, it will always be above 0. (Eg. 0.0000000000000010404 > 0)