I am a fresh student in computer science and currently we study Java recursion. Unfortunately, the academy only explains the following regarding this topic:
What recursion means.
There are 2 types of cases when using a recursive algorithm: base cases and recursive cases and their purpose.
An example of factorial and Fibonacci implementation using recursion.
Now I got the following exercise:
Two integer numbers will be called "strangers" if their greatest common divisor (aka GTC) is ONLY 1". For example, the numbers 8 and 9 are "strangers" because their GTC is 1. However, 8 and 9 are not "strangers" because their GTC is 2.
Please implement a recursive method which receives an array of integers, and returns "true" if every pair numbers in this array are strangers, and "false" otherwise.
Method signature must be as follows:
public boolean checkGCD(int[] values)
For example:
{3, 5, 7, 11} -> method will returns true.
{4, 7, 8, 9} -> method will returns false because 4 and 8 are not strangers.
For assistance, you can use the following method for finding GTC (Euclidean algorithm):
private static int gcd(int n, int m){
if (m==0)
return n;
return gcd(m,n % m);
}
In addition, the method checkGCD(int[] values) should be overloaded...
Loops cannot be used!
The above can be done very easily with a nested loop, but I must use recursion!
I understand that I need to use an overloaded method which gets the array, lo index and hi index.
So this is what I came up in mind:
######
Base case: if there is at least one pair of numbers in the array which are not strangers, method returns false (no need to continue the comparison...).
######
Comparison will be done in the following way: lo index points to the 1st cell -> hi index points to the 2nd cell -> comparing -> hi index is incremented by 1 until it reaches the last cell of the array.
Then, lo index is incremented by 1, and then repeating the above.
So bottom line, I should compare the first cell to all consecutive cells, compare the 2nd to all consecutive cells, the 3rd etc...
########
If all pairs of numbers are strangers, I need something else to stop recursion. Therefore, if all pairs are strangers, it means that lo index and hi index will eventually point to the last cell (cause both lo and hi index has incremented gradually, and they reach the last array cell after all comparisons turned out to be OK i.e strangers).
The following is the overloaded function:
private static boolean checkGCD(int[] values, int lo, int hi)
{
if ( (gcd(values[lo], values[hi]) )!= 1 )
return false;
else if (lo < values.length-1 && hi < values.length-1)
return checkGCD(values, lo, hi+1);
else if (lo < values.length-2 && hi == values.length-1)
return checkGCD (values, lo+1, lo+2);
if (lo == values.length-1 && hi == values.length-1)
return true;
} -> Compiler says "missing return statement"**
The following is the method the exercise requires to have, and it basically just calls the overloaded method which does everything recursively.
public static boolean checkGCD(int[] values)
{
return checkGCD(values, 0, 1);
}
When I try to compile, I get "missing return statement" which points to the close bracket in the overloaded function
But I do use "return" in the overloaded function.
Please clarify how to fix. I am sure after compilation error, the above overloaded function is still not OK.
You get the compiler error because, if every if fails, the method does not return anything. The solution is add the appropriate return statement when the final if fails.
Not to give the answer away, but here's a strong hint: the base case is an array with two elements. All larger arrays are recursive cases.
There's a general pattern for going through a list with a recursion (pseudocode):
Result f(List f) {
if(f is an empty list) {
return Result for an empty list;
} else {
return (Result for head of list) merged with f(tail of list)
}
}
Since you're using arrays, rather than a type with convenient head() and tail() methods, you could pass in an index to say how much of the array you want to process. When index == array.length you are processing an "empty list".
boolean allMembersPositive(int[] array, int index) {
if(index == array.length) {
return true;
} else {
return (array[index] >=0) && (allMembersPositive(index + 1));
}
}
It's a small step to adapt this to consume two array items per recursive call.
I can guarantee you that when you understand recursion clearly you are going to level up your programming skills.
I recommend reading these URLs:
http://howtoprogramwithjava.com/java-recursion/
http://danzig.jct.ac.il/java_class/recursion.html
Now, lets move back to your questions. I think that is one possible way to implement it:
public class Test {
public static void main(String[] arguments) {
int[] strangers = { 3, 5, 7, 11 };
int[] acquaintances = { 4, 7, 8, 9};
boolean verifyStrangers = checkGCD(strangers);
boolean verifyAcquaintances = checkGCD(acquaintances);
System.out.println(verifyStrangers);
System.out.println(verifyAcquaintances);
}
public static boolean checkGCD(int[] values) {
return checkGCD(values, 0, 1);
}
/*
* I'm really not sure why your professor wants this method signature: "checkGCD(int[] values, int i, int j)"
* I'm coding what I understood from the problem.
*/
private static boolean checkGCD(int[] values, int i, int j) {
boolean result = true;
if (gcd(values[i], values[j]) != 1){
result = false;
}
j++;
if (j < values.length ) {
result = result && checkGCD(values, i, j);
}
return result;
}
private static int gcd(int n, int m) {
if (m == 0)
return n;
return gcd(m, n % m);
}
}
I managed to solve the exercise.
public static int gcd(int n, int m)
{
if (m==0)
return n;
return gcd(m,n % m);
}
private static boolean checkGCD(int[] values, int lo, int hi)
{
// System.out.println("lo is " + lo + " hi is " + hi);
// System.out.println("");
// System.out.println("[lo] is " + values [lo] + " [hi] is " + values[hi]);
// System.out.println("");
if ( (gcd(values[lo], values[hi]) )!= 1 )
return false;
if (lo < values.length-1 && hi < values.length-1)
return checkGCD(values, lo, hi+1);
if (lo < values.length-2 && hi == values.length-1)
return checkGCD(values, lo+1, lo+2);
if (lo == values.length-2 && hi == values.length-1)
return true;
return true;
}
public static boolean checkGCD(int[] values)
{
return checkGCD(values, 0, 1);
}
:-)
Related
I'm trying to find the average of all even numbers in an array using recursion and I'm stuck.
I realize that n will have to be decremented for each odd number so I divide by the correct value, but I can't wrap my mind around how to do so with recursion.
I don't understand how to keep track of n as I go, considering it will just revert when I return.
Is there a way I'm missing to keep track of n, or am I looking at this the wrong way entirely?
EDIT: I should have specified, I need to use recursion specifically. It's an assignment.
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
In order to keep track of the number of even numbers you have encountered so far, just pass an extra parameter.
Moreover, you can also pass an extra parameter for the sum of even numbers and when you hit the base case you can return the average, that is, sum of even numbers divided by their count.
One more thing, your code has two base cases for the first as well as last element which is unneeded.
You can either go decrementing n ( start from size of array and go till the first element ), or
You can go incrementing i starting from 0 till you reach size of array, that is, n.
Here, is something I tried.
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
You can call the function like this getEvenAvg(a, size_of_array - 1, 0, 0);
Example
When dealing with recursive operations, it's often useful to start with the terminating conditions. So what are our terminating conditions here?
There are no more elements to process:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
... okay, now how do we reduce the number of elements to process? We should probably increment index?
index++;
... oh, but only when going to the next level:
getEvenAverage(elements, index++, sum, count);
Well, we're also going to have to add to sum and count, right?
sum += a[index];
count++;
.... except, only if the element is even:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
... and that's about it:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
... although you likely want a wrapper function to make calling it prettier:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
Java is not a good language for this kind of thing but here we go:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
You pass the current average and the number of even elements so far to each the recursive call. The new average is calculated by multiplying the average again with the number of elements so far, add the new single value and divide it by the new number of elements before passing it to the next recursive call.
The way of recreating new arrays for each recursive call is the part that is not that good with Java. There are other languages that have syntax for splitting head and tail of an array which comes with a much smaller memory footprint as well (each recursive call leads to the creation of a new int-array with n-1 elements). But the way I implemented that is the classical way of functional programming (at least how I learned it in 1994 when I had similar assignments with the programming language Gofer ;-)
Explanation
The difficulties here are that you need to memorize two values:
the amount of even numbers and
the total value accumulated by the even numbers.
And you need to return a final value for an average.
This means that you need to memorize three values at once while only being able to return one element.
Outline
For a clean design you need some kind of container that holds those intermediate results, for example a class like this:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
Of course you could also use something like an int[] with two entries.
After that the recursion is very simple. You just need to recursively traverse the array, like:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
And while doing so, update the container with the current values.
Collecting backwards
When collecting backwards you need to store all information in the return value.
As you have multiple things to remember, you should use a container as return type (Results or a 2-entry int[]). Then simply traverse to the end, collect and return.
Here is how it could look like:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
Collecting forwards
The advantage of this method is that the caller does not need to call results.getAverage() by himself. You store the information in the parameters and thus be able to freely choose the return type.
We get our current value and update the container. Then we call the next element and pass him the current container.
After the last element was called, the information saved in the container is final. We now simply need to end the recursion and return to the first element. When again visiting the first element, it will compute the final output based on the information in the container and return.
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
Usage by end-user
The backward method is used like:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
Whereas the forward method is used like:
double average = getEvenAverage(values, 0, null);
Of course you can hide that from the user using a helper method:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
Then, for the end-user, it is just this call:
double average = computeEvenAverageBackward(values);
Here's another variant, which uses a (moderately) well known recurrence relationship for averages:
avg0 = 0
avgn = avgn-1 + (xn - avgn-1) / n
where avgn refers to the average of n observations, and xn is the nth observation.
This leads to:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
which can be invoked using the following front-end method to protect users from needing to know about the parameter initialization:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
And now for a completely different approach.
This one draws on the fact that if you have two averages, avg1 based on n1 observations and avg2 based on n2 observations, you can combine them to produce a pooled average:
avgpooled = (n1 * avg1 + n2 * avg2) / (n1 + n2).
The only issue here is that the recursive function should return two values, the average and the number of observations on which that average is based. In many other languages, that's not a problem. In Java, it requires some hackery in the form of a trivial, albeit slightly annoying, helper class:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
Applying a divide and conquer strategy yields the following recursion:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
We can deal with empty arrays, protect the end-user from having to know about the book-keeping arguments, and return just the average by using the following public front-end:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
This solution has the benefit of O(log n) stack growth for an array of n items, versus O(n) for the various other solutions that have been proposed. As a result, it can deal with much larger arrays without fear of a stack overflow.
How would you solve the following task:
Write a recursive method which gets passed an array, filters all odd numbers and store them into an array. The returned array has to be sorted by each elements order.
You are not allowed to use any provided methods by java classes like Arrays.sort, Lists, etc. Furthermore loops are disallowed and generic well known sort algorithm applied to the result as well.
The part of filtering is easy, but I don't know how to put each element at its right place. At the moment my method only returns an unsorted array with all odd numbers.
public static int[] filterOdd(int[] m){
return filterOdd(m, 0, 0);
}
private static int[] filterOdd(int[] m, int idx, int idxToPlace){
if(idx <= m.length -1){
if(m[idx] % 2 == 0){
return filterOdd(m, idx + 1, idxToPlace);
}else{
int[] buffer = filterOdd(m, idx + 1, idxToPlace + 1);
buffer[idxToPlace] = m[idx];
return buffer;
}
}else{
return new int[numberOfOddIntegers(m)];
}
}
Is there any way to insert the odd number at its right place recursively?
At the place where you do buffer[idxToPlace] = m[idx]; you have to call another method that will return the sorted array with the current processing number added to it.
That new method can be recursive too: you know at that moment that the array you have in your hands is ordered. You just recursively traverse (for example from the end to the begin) and from the moment your element fits in (e.g. is smaller than the previous element) you can insert it and return the sorted array. If there is only 1 element (base case) you can just return it.
That way, at the end of your algorithm, the list will be sorted.
I'm not allowed to use System.arraycopy
This means that you need to figure out how many odd numbers you are going to have, in order to size your result properly:
public static int[] filterOdd(int[] m){
int[] res = new int[countOdd(m, 0)];
filterOdd(m, 0, 0, res);
return res;
}
private static int countOdd(int[] m, int i) {
if (i == m.length) {
return 0;
}
int isOdd = m[i] % 2 != 0 ? 1 : 0;
return isOdd + countOdd(m, i+1);
}
private static void filterOdd(int[] m, int src, int dest, int[] res){
if(src == m.length) {
return;
}
if (m[src] % 2 != 0) {
res[dest++] = m[src];
}
filterOdd(m, src+1, dest, res);
}
This is what I have so far, but I'm confused on how to keep track of the index. I would change the parameters of the method, but I'm not allowed.
I can only use a loop to make another array. Those are the restrictions.
public class RecursiveFinder {
static int checkedIndex = 0;
static int largest = 0;
public static int largestElement(int[] start){
int length = start.length;
if(start[length-1] > largest){
largest = start[length-1];
int[] newArray = Arrays.copyOf(start, length-1);
largestElement(newArray);
}
else{
return largest;
}
}
/**
* #param args
*/
public static void main(String[] args) {
int[] array1 = {0,3,3643,25,252,25232,3534,25,25235,2523,2426548,765836,7475,35,547,636,367,364,355,2,5,5,5,535};
System.out.println(largestElement(array1));
int[] array2 = {1,2,3,4,5,6,7,8,9};
System.out.println(largestElement(array2));
}
}
Recursive method doesn't need to keep the largest value inside.
2 parameters method
Start to call with:
largestElement(array, array.length-1)
Here is the method:
public static int largestElement(int[] start, int index) {
if (index>0) {
return Math.max(start[index], largestElement(start, index-1))
} else {
return start[0];
}
}
The 3rd line of method is the hardest one to understand. It returns one of two elements, larges of the one of current index and of remaining elements to be checked recursively.
The condition if (index>0) is similar to while-loop. The function is called as long as the index remains positive (reaches elements in the array).
1 parameter method
This one is a bit tricky, because you have to pass the smaller array than in the previous iteration.
public static int largestElement(int[] start) {
if (start.length == 1) {
return start[0];
}
int max = largestElement(Arrays.copyOfRange(start, 1, start.length));
return start[0] > max ? start[0] : max;
}
I hope you do this for the study purposes, actually noone has a need do this in Java.
Try that for the upper class, leave the main method it's is correct.
public class dammm {
public static int largestElement(int[] start){
int largest = start[0];
for(int i = 0; i<start.length; i++) {
if(start[i] > largest){
largest = start[i];
}
}return largest;
}
If your goal is to achieve this by using recursion, this is the code that you need. It is not the most efficient and it is not the best way to deal with the problem but it is probably what you need.
public static int largestElement(int[] start){
int length = start.length;
if (start.lenght == 1){
return start[0];
} else {
int x = largestElement(Arrays.copyOf(start, length-1))
if (x > start[length-1]){
return x;
} else {
return start[length-1];
}
}
}
Imagine that you have a set of numbers you just have to compare one number with the rest of them.
For example, given the set {1,8,5} we just have to check if 5 is larger than the largest of {1,8}. In the same way you have to check if 8 is larger than the largest of {1}. In the next iteration, when the set one have one value, you know that that value is the bigger of the set.
So, you go back to the previous level and check if the returned value (1) is larger than 8. The result (8) is returned to the previous level and is checked against 5. The conclusion is that 8 is the larger value
One parameter, no copying. Tricky thing is, we need to pass a smaller array to the same method. So a global variable is required.
// Number of elements checked so far.
private static int current = -1;
// returns the largest element.
// current should be -1 when user calls this method.
public static int largestElement(int[] array) {
if (array.length > 0) {
boolean resetCurrent = false;
if (current == -1) {
// Initialization
current = 0;
resetCurrent = true;
} else if (current >= array.length - 1) {
// Base case
return array[array.length - 1];
}
try {
int i = current++;
return Math.max(array[i], largestElement(array));
} finally {
if (resetCurrent) {
current = -1;
}
}
}
throw new IllegalArgumentException("Input array is empty.");
}
If you can create another method, everything would be much simpler.
private static int recursiveFindLargest(int [] array, int i) {
if (i > 0) {
return Math.max(array[i], recursiveFindLargest(array, i-1));
} else {
return array[0];
}
}
public static int largestElement(int [] array) {
// For empty array, we cannot return a value to indicate this situation,
//all integer values are possible for non-empty arrays.
if (array.length == 0) throw new IllegalArgumentException();
return recursiveFindLargest(array, array.length - 1);
}
For this problem you really need to think about working with the base case. Take a look at some of the simple cases you would have to deal with:
If the array is length 1, then you return the only value
If the array is length 2, then you return the maximum of the two values
If the array is length 3, then ?
From the above we can get an idea of the structure of the problem:
if array.length == 1 then
return array[0]
else
return the maximum of the values
In the above if we have only one element, it is the maximum value in the list. If we have two values, then we have to find the maximum of those values. From this, we can then use the idea that if we have three values, we can find the maximum of two of them, then compare the maximum with the third value. Expanding this into pseudo code, we can get something like:
if array.length == 1 then
return array[0]
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
return maximum(array[0], largestElement(new array))
To explain the above a little better, think of execution like a chain (example for {1, 2, 3}).
Array: {1, 2, 3}, maximum(array[0] = 1, largestElement(new array = {2, 3}))
Array: {2, 3}, maximum(array[0] = 2, largestElement(new array = {3}))
Array: {3}, array[0] = 3 => length is 1 so return 3
The above then rolls back up the 'tree' structure where we get:
maximum (1, maximum(2, (return 3)))
Once you have the maximum value, you can use the sample principle as above to find the index with a separate method:
indexOf(array, maximum)
if array[0] == maximum then
return 0
else if array.length == 1 then
return -1
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
result = indexOf(new array, maximum)
return (result == -1) ? result : result + 1
For looking into this more, I would read this from the Racket language. In essence it shows the idea of array made purely from pairs and how you can use recursion to do iteration on it.
If you are interested, Racket is a pretty good resource for understanding recursion. You can check out University of Waterloo tutorial on Racket. It can give you a brief introduction to recursion in an easy to understand way, as well as walking you through some examples to understand it better.
You don't need to keep a largest variable outside your method - that's generally not a good practice with recursion which should return all context of the results.
When you think about recursion try to think in terms of a simple base case where the answer is obvious and then, for all other cases how to break it down into a simpler case.
So in pseduo-code your algorithm should be something like:
func largest(int[] array)
if array has 1 element
return that element
else
return the larger of the first element and the result of calling largest(remaining elements)
You could use Math.max for the 'larger' calculation.
It's unfortunate that you can't change the arguments as it would be easier if you could pass the index to start at or use lists and sublists. But your copying method should work fine (assuming efficiency isn't a concern).
An alternative to the algorithm above is to make an empty array the base case. This has the advantage of coping with empty arrays (by return Integer.MIN_VALUE):
int largest(int[] array) {
return array.length == 0
? Integer.MIN_VALUE
: Math.max(array[0], largest(Arrays.copyOfRange(array, 1, array.length)));
}
Here is working example of code with one method param
public int max(int[] list) {
if (list.length == 2) return Math.max(list[0], list[1]);
int max = max(Arrays.copyOfRange(list, 1, list.length));
return list[0] < max ? max : list[0];
}
private static int maxNumber(int[] arr,int n,int max){
if(n<0){
return max;
}
max = Math.max(arr[n],max);
return maxNumber(arr,n-1,max);
}
I am told to write a recursive function that takes a start index, array of integers,and a target sum, your goal is to find whether a subset of of the array of integers adds up to the target sum.
The example I am given is groupSum(0, {2, 4, 8}, 10) should return true because 2 and 8 add up to the target, 10. All I've been able to do so far are the base cases.
public boolean groupSum(int start, int[] nums, int target) {
if (nums.length == 0)
{
return false;
}
else if (start == nums.length - 1)
{
return nums[start] == target;
}
else
{
?????
}
}
I have no idea where I should go with the actual recursive call. Since I can't pass a collective sum between calls, I don't see how I can add a number in each recursive call until I reach the target. Also, like shown in the example, I have no idea how I could have my code realize when a number won't work and just skip it, like the example did with 4. I'm thinking along the lines of that I should subtract numbers one at a time from int target and then recursively call the method with a new starting point and the new value for target, but I have no idea how I could use that to see if there is a valid subset.
I would appreciate any help that can help me understand how to do this problem so that I can finish it. Thanks!
As you point out you can change the target rather than passing a collective sum. Once the target is zero you know that you've got a solution (by selecting no members of the remaining items).
So, in psueduo code:
hasMembersThatSumTo(list, total):
if total == 0
return true
else if total < 0 or list is empty
return false
else
int first = list.pop
return hasMembersThatSumTo(list, total - first)
or hasMembersThatSumTo(list, total)
The two cases in the 'or' statement are looking for this situation in which the current element is either in or not in the sum.
Here is a working version. See comments in the code for explanation.
public static boolean recursiveSumCheck(int target, int[] set) {
//base case 1: if the set is only one element, check if element = target
if (set.length == 1) {
return (set[0] == target);
}
//base case 2: if the last item equals the target return true
int lastItem = set[set.length - 1];
if (lastItem == target) {
return true;
}
//make a new set by removing the last item
int[] newSet = new int[set.length - 1];
for (int newSetIndex = 0; newSetIndex < newSet.length; newSetIndex++) {
newSet[newSetIndex] = set[newSetIndex];
}
//recursive case: return true if the subset adds up to the target
// OR if the subset adds up to (target - removed number)
return (recursiveSumCheck(target, newSet) || recursiveSumCheck(target - lastItem, newSet));
}
dynamic programming. Maybe this will help you.
This should work according to the given conditions.
Initially the value of start = 0
boolean subsetSum(int start, int[] nums, int target) {
// target is the sum you want to find in the nums array
if (target == 0) return true;
if (start > nums.length-1 || nums.length == 0)
return false;
if (nums[start] > target)
return subsetSum(start+1, nums, target);
return subsetSum(start+1, nums, target) || subsetSum(start+1, nums, target - nums[start]);
}
This one is making my head spin. Just when I think I got it, I realize something's not right. I have to use recursion for this assignment. Any hints?
/**
* Uses recursion to find index of the shortest string.
* Null strings are treated as infinitely long.
* Implementation notes:
* The base case if lo == hi.
* Use safeStringLength(paths[xxx]) to determine the string length.
* Invoke recursion to test the remaining paths (lo +1)
*/
static int findShortestString(String[] paths, int lo, int hi) {
int min=lo;
if (lo==hi)
return min;
if (safeStringLength(paths[lo]) < safeStringLength(paths[lo+1])){
min=lo;
return Math.min(min, findShortestString(paths, lo+1, hi));
}
else{
min=lo+1;
return Math.min(min, findShortestString(paths, lo+1, hi));
}
}
I think got something here:
static int findShortestString(String[] paths, int lo, int hi)
{
if (lo==hi)
return lo;
int ShortestIndexSoFar = findShortestString(paths, lo+1, hi);
if(safeStringLength(paths[ShortestIndexSoFar]) < safeStringLength(paths[lo]))
return ShortestIndexSoFar;
else
return lo;
}
static int safeStringLength(String str)
{
if(str == null)
return Integer.MAX_VALUE;
return str.length();
}
Explaining why this works:
Here's a sample:
[0] ab
[1] abcd
[2] a
[3] abc
[4] ab
Obviously, index 2 is the shortest one.
Think bottoms up. Read the following starting from the bottom, upwards.
I make it sound like each function is talking to the function above it in the chain.
And each line is lead by the function parameters that were passed.
"[0] ab (paths, 0, 4): return 2, coz he's shorter than me or anyone before us"
"[1] abcd (paths, 1, 4): return 2, coz he's shorter than me or anyone before us"
"[2] a (paths, 2, 4): return 2, I'm shorter than anyone before me"
"[3] abc (paths, 3, 4): return 4, coz he's shorter than me or anyone before us"
"[4] ab (paths, 4, 4): return 4, I'm the shortest; I don't know any better"
So in the code, you see that exactly happening.
When we define ShortestIndexSoFar, this is where each function will know the shortest of all the paths beyond it.
And right after it is where the function itself checks if its index has a shorter path than the shortest of all the ones below.
Keep trickling the shortest one upward, and the final guy will return the shortest index.
That makes sense?
Since this is homework, here's a hint to help you learn:
The signature of the findShortestString method suggests that you should be using a binary search. Why would I say that? Why would it be a good idea to do that? All of the other solutions suffer from a practical problem in Java ... what would that be?
To people other than the OP ... PLEASE DON'T GIVE THE ANSWERS AWAY ... e.g. by correcting your answers!
Why not just get the length of each element and sort the returned length to get the ordering? Like this.
int[] intArray = {10, 17, 8, 99, 1}; // length of each element of string array
Arrays.sort(intArray);
one solution will be like this
public static final int findShortestString(final String[] arr, final int index, final int minIndex) {
if(index >= arr.length - 1 ) {
return minIndex;
}
if(-1 == safeStringLength(arr[index])) {
return index;
}
int currentMinIncex = minIndex;
if(safeStringLength(arr[minIndex]) > safeStringLength(arr[index+1])){
currentMinIncex = index + 1;
}
return findShortestString(arr, index + 1, currentMinIncex);
}
public static final int safeStringLength(final String string) {
if( null == string) return -1;
return string.length();
}
A simple solution:
/**
* Uses recursion to find index of the shortest string.
* Null strings are treated as infinitely long.
* Implementation notes:
* The base case if lo == hi.
* Use safeStringLength(paths[xxx]) to determine the string length.
* Invoke recursion to test the remaining paths (lo +1)
*/
static int findShortestString(String[] paths, int lo, int hi) {
if (lo==hi)
return lo;
if (paths[lo] == null)
return findShortestString(paths, lo+1, hi);
int bestIndex = findShortestString(paths, lo+1, hi);
if (safeStringLength[lo] < safeStringLength[bestIndex])
return lo;
return bestIndex;
}
Calculating min on the result of running findShortestString isn't meaningful. The best way to start this kind of problem is to consider just a single recursive step, you can do this by considering what happens with an array of only two strings to compare.
What you want to do is check the length of the first string against the length of the second. The real trick, though, is that you want to test the length of the second by calling the function recursively. This is straight forward enough, but requires determining the end-case of your recursion. You did this successfully, it's when lo == hi. That is, when lo == hi the shortest known string is lo (it's the only known string!).
Ok, so back to comparing just two strings. Given that you know that you want to compare the length of two strings stored in paths, you might do something like this (without recursion):
if(safeStringLength(paths[0]) < safeStringLength(paths[1])){
return 0; // paths[0] is shorter
}else{
return 1; // paths[1] is shorter
}
But you want to recurse -- and in the recurse step you need to somehow generate that 1 of paths[1]. We already figured out how to do that, when lo == hi, we return lo. Thus the recursion step is "compare the current lowest known string length to the string length of the best known index" -- wait, we have a function for that! it's findShortestString. Thus we can modify what's written above to be slightly more concise, and add in the base case to get:
static int findShortestString(String[] paths, int lo, int hi) {
// base case, no comparisons, the only known string is the shortest one
if(lo == hi){
return lo;
}
int bestIndex = findShortestString(paths, lo+1, hi);
return safeStringLength(paths[lo]) < safeStringLength(paths[bestIndex]) ?
lo : bestIndex;
}
static int findShortestString(String[] paths, int lo, int hi)
{
if (lo==hi)
return lo;
int ShortestIndexDown = findShortestString(paths, lo, (hi + lo)/2);
int ShortestIndexUp = findShortestString(paths, (lo+hi)/2+1, hi);
return SafeStringLength(paths[ShortestIndexDown]) < SafeStringLength(paths[ShortestIndexUp])?ShortestIndexDown:ShortestIndexUp;
}
static int safeStringLength(String str)
{
if(str == null)
return Integer.MAX_VALUE;
return str.length();
}