I'm thinking of several elegant ways of writing a simple Lisp-like recursive function in Java that does, let's say, a simple summation.
In Common Lisp it would be like this:
(defun summation(l)
(if l
(+ (car l) (summation (cdr l)))
0))
(summation '(1 2 3 4 5)) ==> 15
In Java the one of many possible solutions would be:
public int summation(int[] array, int n) {
return (n == 0)
? array[0]
: array[n] + summation(array, n - 1);
}
CALL:
summation(new int[]{1,2,3,4,5}, 4); //15
1) Is there any possible way NOT to use the index n?
2) Or leave your solution (non-iterational) which you see as interesting.
Thanks.
Using Java Collections - something like this should give you an idea of how to eliminate n and recurse in terms of the list size instead:
public int summation( List<Integer> list ) {
return list.isEmpty()
? 0
: list.get( list.size - 1 ) + summation( list.subList( 0 , list.size() - 1 ) );
}
Cheers,
Usually, I solve this kind of recursion with a public API that does not require the index parameter and a private API with any signature I#d like it to be. For this I would separate it this way:
public int summation(int[] numbers) {
return summation(numbers, numbers.length - 1);
}
private int summation(int[] numbers, int till) {
return (till < 0) ? 0 : numbers[till] + summation(numbers, till - 1);
}
Note that you must check till < 0 as this handles an empty array correctly.
Another way would be to not use an array, but any Iterable<Integer>:
public int summation(Iterable<Integer> numbers) {
return summation(numbers.iterator());
}
private int summation(Iterator<Integer> numbers) {
return (numbers.hasNext()) ? numbers.next() + summation(numbers) : 0;
}
Hint: The order of calls in numbers.next() + summation(numbers) is important, as the next() call must be done first.
If you use List.subList method, it may perform iteration, underneath. You can use Queue instead, to avoid iteration. For example:
public int sum(Queue queue) {
return queue.isEmpty() ? 0 : (queue.poll() + sum(queue));
}
public class HelloWorld{
static int sum=0;
static int c;
public static void main(String []args){
int[] y={1,2,3,4,5};
c=y.length;
System.out.println( summation(y)); //15
}
public static int summation(int[] array) {
c--;
if(c<0){
return sum;
}
else{
sum+=array[c];
return summation(array);
}
}
}
Here's a simple method that seems pretty close to what's being asked for.Basically, we are taking a recursive approach to performing summation ascontrasted with brute force from the bottom up.
public static int sumToN(int n) {
if( n == 0 ){
return 0;
}
return n + sumToN(n - 1);
}
Related
For a classic binarySearch on an array of java Strings (say String[] a), which is the correct way of calling the search method? is it
binarySearch(a,key,0,a.length)
or
binarySearch(a,key,0,a.length-1)
I tried both for the below implementation,and both seems to work.. Is there a usecase where either of these calls can fail?
class BS{
public static int binarySearch(String[] a,String key){
return binarySearch(a,key,0,a.length);
//return binarySearch(a,key,0,a.length-1);
}
public static int binarySearch(String[] a,String key,int lo,int hi) {
if(lo > hi){
return -1;
}
int mid = lo + (hi - lo)/2;
if(less(key,a[mid])){
return binarySearch(a,key,lo,mid-1);
}
else if(less(a[mid],key)){
return binarySearch(a,key,mid+1,hi);
}
else{
return mid;
}
}
private static boolean less(String x,String y){
return x.compareTo(y) < 0;
}
public static void main(String[] args) {
String[] a = {"D","E","F","M","K","I"};
Arrays.sort(a);
System.out.println(Arrays.toString(a));
int x = binarySearch(a,"M");
System.out.println("found at :"+x);
}
}
Consider the case where
a = [ "foo" ]
and you search key "zoo" with binarySearch(a,key,0,a.length);
The code will search for it in interval[0,1], see it should be right than that,
next recursion searches interval [1,1], causing an indexing of a[1] at line
if(less(key,a[mid])){
resulting in a array out of bounds error.
The second solution will work fine.
I think the second approach will be safe.
Consider this case - you have an array of 9 elements and the key is situated at the last index (8-th element). Then you might have a method call like this if you follow the first approach -
binarySearch(a, key, 9, 9);
Now, in that method execution, the integer division in the following line will result in 9 -
int mid = 9 + (9 - 9)/2;
and you will be indexing your array with 9 in the next line -
if( less(key,a[mid]) ) { // You'll face ArrayIndexOutOfBoundException
....
}
which will be invalid and cause ArrayIndexOutOfBoundException.
The second approach however will be just fine.
I have three integers, which are assigned to variables after being passed in as command line parameters. I want to validate that each of the integers are in the range 1-5. Is there a way to accomplish this in Java without using an if statement like the one below? I'd like to avoid doing this (note- pseudocode):
if ((a & b & c) > 0 && (a & b & c) < 6) {
//blah blah
}
Mainly, this wouldn't scale well if additional parameters were added in the future, etc. Is there a more elegant way to accomplish this?
The only improvement I think could be made (for readability) is this:
public boolean isInRange(int i) {
return i > 0 && i < 6;
}
Then call that function instead.
If a, b, and c are related, you may also consider using an array and looping through that. Something like:
public boolean allInRange(int[] arr) {
for (int i = 0; i < arr.length; i ++) {
if (!isInRange(arr[i])) return false;
}
return true;
}
How about something like this:
validate(int ... args) {
for (int arg : args) {
if (arg < 1 || arg > 5) {
throw IllegalArgumentException("Argument is not in valid range [1..5]: " + arg);
}
}
}
and then call this helper method
validate(a,b,c);
You could create a method to which you pass an integer, and the method can return a boolean depending whether or not it is in range.
Another way is to create a method that receives a list of integers List<Integer> myList or an array of integers, and checks each and every one if it is in range.
Here is a faster way to do that without using multiple &&s (for integers only):
private static boolean isInRange(int num, int min, int max) {
return (num - min - Integer.MIN_VALUE) <= (max - (1 - Integer.MIN_VALUE));
}
Usage:
public static void main(String[] args) {
System.out.println(isInRange(5,1,7)); // true
System.out.println(isInRange(5,1,3)); // false
}
I am doing this assignment and I am having trouble writing this method recursively.
I have this way to do it which is effective but not recursive:
public static <T extends Comparable< ? super T>> T getLargest(T [] a, int low,
int high)
{
if(low>high)
throw new IllegalArgumentException();
return Collections.max(Arrays.asList(Arrays.copyOfRange(a, low, high)));
So from there I went to this one, which kind of extends it but is not recursive either:
T[] arrCopy = (T[]) new Object[high-low];
for(int i=low;i<high;i++){
if(a[i].compareTo(a[i-1])>0)
arrCopy[i]=a[i];
else
arrCopy[i]=a[i+1];
}
return arrCopy[0];
And I've been working on it for hours and can't seem a way to make it recursive and make it work.
Any help and ideas are greatly appreciated!
Well, here is a template for turning a for-loop into a tail-recursive method:
//iterative version
public Object getIteratively(Object[] a) {
Object retVal = null;
for (int i = 0; i < a.length; a++ ) {
//do something
}
return retVal;
}
//recursive version
public Object getRecursively(Object[] a) {
doGetRecursively(a, 0, null);
}
private Object doGetRecursively(Object[] a, int i, Object retVal) {
if ( i == a.length ) {
return retVal;
}
//do something
return doGetRecursively(a, i+1, retVal);
}
Why you would ever want to do this in a non-functional language is beyond me though.
In this case //do something would be the same in both cases, e.g.:
if ( a[i].compareTo(retVal) > 0 ) {
retVal = a[i];
}
First, your method signature is incorrect. You do not need a 'low'. You should take an array/list as input and return the largest element. You may find however that you want a secondary method that requires extra arguments.
When approaching recursion and you're stuck, it's often best to identify your base case(s) first, then deal with your recursive case(s) next.
Your base case is the simplest case in which you know the answer. In this problem, you know what the largest element is right away if the size of your list is 1 - you just return the only element. You may want to think about the case where your list is empty as well.
Your recursive case then, is whenever your list has size greater than 1. In your recursive case, you want to try and 'break a piece off' and then send the rest to a recursive call. In this case, you can look at the first element in the list, and compare it to the result you get from a recursive call on the rest of the list.
This would be the right answer:
T tmp = a[low];
for(int i=0;i<=high;i++){
if(a[i].compareTo(tmp)>0){
tmp = a[i];
getLargest(a,i,high);
}
}
return tmp;
Okay before this gets out of hand, here's a simple iterative and the equivalent recursive solution to this - implemented with ints though so you have to change it a bit ;)
public static int getLargest(int[] vals) {
int max = vals[0];
for (int i = 1; i < vals.length; i++) {
max = Math.max(max, vals[i]);
}
return max;
}
public static int getLargestRec(int[] vals) {
return getLargestRec(vals, 0, vals.length);
}
private static int getLargestRec(int[] vals, int low, int high) {
if (low + 1 == high) {
return vals[low];
}
int middle = low + (high - low) / 2;
int left = getLargestRec(vals, low, middle);
int right = getLargestRec(vals, middle, high);
return Math.max(left, right);
}
public static void main(String[] args) {
int[] vals = {5, 23, 32, -5, 4, 6};
System.out.println(getLargestRec(vals));
System.out.println(getLargest(vals));
}
Note that as usual for recursive problems the lower bound is inclusive and the higher bound is exclusive. Also we could implement this differently as well, but the usual divide & conquer approach is rather useful and lends itself nicely to parallelization with a fork framework, so that's fine. (And yes for an empty array both versions will fail)
I am trying to write a recursive function in Java that prints the numbers one through n. (n being the parameter that you send the function.) An iterative solution is pretty straightforward:
public static void printNumbers(int n){
for(int i = 1; i <= n; i++){
System.out.println(i);
i++;
}
As a new programmer, I'm having troubles figuring out how a recursive version of this method would work.
You are using a for loop that is iterating from i=1 to n. As you want to do this with recursion and it is easier to pass n instead of i and n, we just reverse the whole thing, so we count down n to 1. To keep the order of the prints, we first call the recursive function and print the number after the execution:
public static void printNumbers ( int n )
{
if ( n > 0 )
{
printNumbers( n - 1 ); // n - 2, if the "i++" within the for loop is intended
System.out.println( n );
}
}
For simple iterative -> recursive conversions it is easy to change loops into a format like this:
public static void printNumbers ( int n )
{
int i = 1;
while ( i <= n )
{
System.out.println( i );
i++; // i += 2, if the "i++" within the for loop is intended
}
}
Now you can easily transform that into a recursive function:
public static void printNumbers ( int n, int i )
{
if ( i <= n )
{
System.out.println( i );
i++; // i += 2, if the "i++" within the for loop is intended
printNumbers( n, i );
}
}
Everything else is optimization.
The recursive version needs two arguments (n and i) so make it an auxiliary non-public method and just call it from the public method to start the recursion going:
static void auxPrintNumbers(int n, int i){
if(i <= n) {
System.out.println(i);
auxPrintNumbers(i + 1);
}
}
public static void printNumbers(int n){
auxPrintNumbers(n, 1);
}
Your iterative version has some problems: you are iterating i twice, in the for statement then again at the end of the loop; also you should let i < n be the ending condition of your loop.
To answer your question, obviously the recursive function will have to print out the current number and if the current number hasn't yet reached n, call itself again - so it must take the current number (which we're calling i in the iterative version) as a parameter - or the class needs to hold it as an instance variable, but I'd stick with the parameter.
According to your function that prints every odd number from 1 to n the recursive function should look something like this:
public static void printNumbersRecursive(int n)
{
if (n % 2 == 0) printNumbersRecursive(n - 1);
else if (n > 0)
printNumbersRecursive(n - 2);
System.out.println(n);
}
if it is an error and that you'd want to print EVERY number from 1 to n then:
public static void printNumbersRecursive(int n)
{
if (n > 0)
printNumbersRecursive(n - 1);
System.out.println(n);
}
A class version (just for fun):
class R {
private final int n;
public R (final int n) {
if (n <= 0) {
throw new IllegalArgumentException("n must be positive");
}
this.n = n;
}
#Override
public String toString () {
final StringBuilder sb = new StringBuilder();
if (this.n > 1) {
sb.append(new R(this.n - 1).toString());
}
sb.append(this.n).append(" ");
return sb.toString();
}
}
Used as:
System.out.println(new R(10));
public static void printNumbers(int n){
if( n > 1 ){
printNumbers(n - 1);
}
System.out.println(n);
}
This function calls itself recursively until it reaches n = 1. From this point all values are printed in correct order: 1, 2, 3, ...
Hi I'm doing the Collatz sequence problem in project Euler (problem 14). My code works with numbers below 100000 but with numbers bigger I get stack over-flow error.
Is there a way I can re-factor the code to use tail recursion, or prevent the stack overflow. The code is below:
import java.util.*;
public class v4
{
// use a HashMap to store computed number, and chain size
static HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
public static void main(String[] args)
{
hm.put(1, 1);
final int CEILING_MAX=Integer.parseInt(args[0]);
int len=1;
int max_count=1;
int max_seed=1;
for(int i=2; i<CEILING_MAX; i++)
{
len = seqCount(i);
if(len > max_count)
{
max_count = len;
max_seed = i;
}
}
System.out.println(max_seed+"\t"+max_count);
}
// find the size of the hailstone sequence for N
public static int seqCount(int n)
{
if(hm.get(n) != null)
{
return hm.get(n);
}
if(n ==1)
{
return 1;
}
else
{
int length = 1 + seqCount(nextSeq(n));
hm.put(n, length);
return length;
}
}
// Find the next element in the sequence
public static int nextSeq(int n)
{
if(n%2 == 0)
{
return n/2;
}
else
{
return n*3+1;
}
}
}
Your problem is not with the size of the stack (you're already memoizing the values), but with
the size of some of the numbers in the sequences, and
the upper limits of a 32-bit integer.
Hint:
public static int seqCount(int n)
{
if(hm.get(n) != null) {
return hm.get(n);
}
if (n < 1) {
// this should never happen, right? ;)
} ...
...
That should hopefully be enough :)
P.S. you'll run into a need for BigNums in a lot of project euler problems...
If you change from integer to long it will give you enough room to solve the problem.
Here was the code that I used to answer this one:
for(int i=1;i<=1000000;i+=2)
{
steps=1;
int n=i;
long current=i;
while(current!=1)
{
if(current%2==0)
{
current=current/2;
}else{
current=(current*3)+1;
}
steps++;
}
if(steps>best)
{
best=steps;
answer=n;
}
}
Brute forcing it, takes about 9 seconds to run
Side note (as it seems that you don't actually need tail call optimization for this problem): tail call optimization is not available in Java, and as far as I have heard, it is not even supported by the JVM bytecode. This means that any deep recursion is not possible, and you have to refactor it to use some other loop construct.
If you are counting the size of the Collatz sequence for numbers upto 1,000,000
you should re-consider using Integer type. I suggest using BigInteger or possible a long.
This should alleviate the problems encountered, but be warned you may still run out of heap-space depending on your JVM.
I think you need these 2 hints :
Don't use Integer because at some starting number, the sequence will fly into some numbers greater than Integer.Max_VALUE which is 2147483647. Use Long instead.
Try not to use recursion to solve this problem, even with memoization. As i mentioned earlier some numbers will fly high and produce a great deal of stacks which will lead into stack overflow. Try using "regular" iteration like do-while or for. Of course you can still use some ingredient like memoization in "regular" loop.
Oh i forget something. Perhaps the stack overflow occurs because of arithmetic overflow. Since you use Integer, maybe Java "change" those "flying numbers" into a negative number when arithmetic overflow occurs. And as seen in method seqCount(int), you don't check invariant n > 0.
You can solve this problem not only with recursion but also with a single loop. there is overflow if you write int. because it generates long while chaning and the recursion never ends because never equal to 1 and you probably get stackoverflow error
Here is my solution with loop and recursion:
public class Collatz {
public int getChainLength(long i) {
int count = 1;
while (i != 1) {
count++;
if (i % 2 == 0) {
i /= 2;
} else {
i = 3 * i + 1;
}
}
return count;
}
public static int getChainLength(long i, int count) {
if (i == 1) {
return count;
} else if (i % 2 == 0) {
return getChainLength(i / 2, count + 1);
} else {
return getChainLength(3 * i + 1, count + 1);
}
}
public int getLongestChain(int number) {
int longestChain[] = { 0, 0 };
for (int i = 1; i < number; i++) {
int chain = getChainLength(i);
if (longestChain[1] < chain) {
longestChain[0] = i;
longestChain[1] = chain;
}
}
return longestChain[0];
}
/**
* #param args
*/
public static void main(String[] args) {
System.out.println(new Collatz().getLongestChain(1000000));
}
}
Here you can have a look at my recursive implementation of problem 14:
http://chmu.bplaced.net/?p=265
import java .util.*;
public class file
{
public static void main(String [] args)
{
long largest=0;
long number=0;
for( long i=106239;i<1000000;i=i+2)
{
long k=1;
long z=i;
while(z!=1)
{
if(z%2==0)
{
k++;
z=z/2;
} else{
k++;
z=3*z+1;
}
}
if(k>largest)
{
number=i;
largest=k;
System.out.println(number+" "+largest);
}
}//for loop
}//main
}