My program runs, but it always gives the incorrect answer. Here are some sample runs:
Enter heap elements: 15 1 14 2 13 3 12 4 11 5 10 6 9 7 8
Enter d: 3
Output: Heap (d= 3): 1 2 3 4 5 6 7 15 11 13 10 14 9 12 8
It should be:
Enter heap elements: 15 1 14 2 13 3 12 4 11 5 10 6 9 7 8
Enter d: 3
Output: Heap (d=3): 1 3 4 2 7 15 12 14 11 5 10 6 9 13 8
import java.util.Scanner;
import java.util.Arrays;
public class D_heap<AnyType extends Comparable<? super AnyType>>
{
private int d;
private final static int DEFAULT_CAPACITY = 10;
private int currentSize;
private AnyType [ ] array; //
/**
* Construct the binary heap.
*/
public D_heap( )
{
this(2, DEFAULT_CAPACITY );
}
/**
* Construct the binary heap.
* #param capacity the capacity of the binary heap.
*/
public D_heap(int numChild )
{
this(numChild, DEFAULT_CAPACITY);
}
public D_heap(int numChild, int cap )
{
currentSize = 0;
d = numChild;
array = (AnyType[]) new Comparable[ cap + 1 ];
}
/**
* Construct the binary heap given an array of items.
*/
//public D_heap( AnyType [ ] items )
//{
// currentSize = items.length;
// array = (AnyType[]) new Comparable[ ( currentSize + 2 ) * 11 / 10 ];
// int i = 1;
// for( AnyType item : items )
// array[ i++ ] = item;
// buildHeap( );
//}
/**
* Insert into the priority queue, maintaining heap order.
* Duplicates are allowed.
* #param x the item to insert.
*/
public void insert( AnyType x )
{
if( currentSize == array.length - 1 )
enlargeArray( array.length * 2 + 1 );
// Percolate up
int hole = ++currentSize;
for( ; hole > 1 && x.compareTo( array[ getParent(hole)] ) < 0; hole = getParent(hole) )
array[ hole ] = array[getParent(hole)];
array[ hole ] = x;
}
private void enlargeArray( int newSize )
{
AnyType [] old = array;
array = (AnyType []) new Comparable[ newSize ];
for( int i = 0; i < old.length; i++ )
array[ i ] = old[ i ];
}
/**
* Find the smallest item in the priority queue.
* #return the smallest item, or throw an UnderflowException if empty.
*/
public AnyType findMin( )
{
if( isEmpty( ) )
throw new UnderflowException(" ");
return array[ 1 ];
}
/**
* Remove the smallest item from the priority queue.
* #return the smallest item, or throw an UnderflowException if empty.
*/
public AnyType deleteMin( )
{
if( isEmpty( ) )
throw new UnderflowException(" ");
AnyType minItem = findMin( );
array[ 1 ] = array[ currentSize-- ];
percolateDown( 1 );
return minItem;
}
/**
* Establish heap order property from an arbitrary
* arrangement of items. Runs in linear time.
*/
private void buildHeap( )
{
for( int i = currentSize / 2; i > 0; i-- )
percolateDown( i );
}
/**
* Test if the priority queue is logically empty.
* #return true if empty, false otherwise.
*/
public boolean isEmpty( )
{
return currentSize == 0;
}
/**
* Make the priority queue logically empty.
*/
public void makeEmpty( )
{
currentSize = 0;
}
public void print( )
{
for( int i = 0; i < currentSize; i++ )
System.out.printf("%d ", array[i+1]);
System.out.println();
}
/**
* Internal method to percolate down in the heap.
* #param hole the index at which the percolate begins.
*/
private void percolateDown( int hole )
{
int child = getChild(hole);
int tempChild = getChild (hole);
AnyType tmp = array[ hole ];
for( ; getChild(hole) <= currentSize; hole = child) {
child = getChild(hole);
tempChild = getChild(hole);
for(int i = 0; i < d && tempChild != currentSize; i++, tempChild++){
if(array[tempChild + 1].compareTo(array[child]) < 0){
child = tempChild + 1;
}
}
if (array[child].compareTo(tmp) < 0)
array[hole] = array[child];
else
break;
}
array[ hole ] = tmp;
}
// Test program
public static void main( String [ ] args )
{
Scanner in = new Scanner(System.in);
D_heap<Integer> h = new D_heap<Integer>();
System.out.print ("How many numeric values do you want to enter? ");
int num = in.nextInt();
System.out.print ("Enter heap elements: ");
for (int i = 1; i <= num; i++){
h.insert (in.nextInt());
}
System.out.print ("Enter d: ");
int d = in.nextInt();
System.out.printf ("Output: Heap (d= %d): ", d);
h.buildHeap();
h.print();
// Create the array of Strings containing the main menu options (Quit - option 0)
// Create the mainMenu object
String opts[] = {"Exit program", "Insert", "deleteMin", "Pick new d value", };
Menu mainMenu = new Menu(opts);
int opt = 0;
do {
opt = mainMenu.runMenu();
switch (opt) {
case 1:
System.out.print ("Enter element to insert: ");
int x = in.nextInt();
h.insert(x);
h.print();
break;
case 2:
h.deleteMin();
h.print();
break;
case 3:
System.out.print ("Enter new d: ");
d = in.nextInt();
h.buildHeap();
h.print();
break;
default:
System.out.println ("Thank you - Have a nice day!");
}
} while (opt != 0);
}
public int getChild( int p){
return d * (p - 1) + 2;
}
public int getParent (int c){
return (c - 2)/d + 1;
}
}
Related
I am trying to find the farthest distance between two non -overlapping intervals represented as arraylist . Non-overlapping intervals are those in which the next start point does not lie between the starting point(inclusive) and ending point(exclusive) .
Example
Number of intervals 3
Interval 1 : 1 2
Interval 2: 3 5
Interval 3: 6 7
The pair of interval (1,2) and (6,7) is farthest as distance between these two is 6 -2 = 4
So output should be 4
My implementation
import java.util.*;
class Checker implements Comparator<ArrayList>{
public int compare(ArrayList a, ArrayList b){
int x = (Integer)a.get(0);
int y = (Integer)b.get(0);
return x-y;
}
}
class OverlappingIntervals {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
ArrayList<ArrayList<Integer>> intervals = new ArrayList<ArrayList<Integer>>(n);
for (int i = 0; i < n; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
intervals.add(new ArrayList<Integer>(Arrays.asList(x, y)));
}
int result = overlappingIntervals(n, intervals);
System.out.println(result);
}
static int overlappingIntervals(int n, ArrayList<ArrayList<Integer>> intervals) {
// System.out.println(intervals);
Checker check = new Checker();
Collections.sort(intervals, check);
int ans = -1;
for(int i = 0; i < n-1;i++){
for(int j = i+1; j < n;j++){
int x = (Integer)intervals.get(j).get(0)- intervals.get(i).get(1);
if(x >= 0){
if(x > ans)
ans = Math.max(x,ans);
}
}
}
return ans;
}
}
Any better optimization for the above so to handle the constraints
1<=N<=10^5
1<=l<=r<=10^6
l and r is the starting point and ending point of interval respectively.
Try this.
Scanner in = new Scanner("3 1 2 3 5 6 7");
int n = in.nextInt();
int minTo = Integer.MAX_VALUE;
int maxFrom = Integer.MIN_VALUE;
for (int i = 0; i < n; ++i) {
maxFrom = Math.max(maxFrom, in.nextInt());
minTo = Math.min(minTo, in.nextInt());
}
if (minTo < maxFrom)
System.out.println("max disntance = " + (maxFrom - minTo));
else
System.out.println("none");
output:
max disntance = 4
We can solve this easily using Stack in O(n) + O(n*log(n)) Time & O(n) Space complexity.
The idea here is to merge the intervals and then check the corresponding gaps between the consecutive Intervals.
Here is an easy and classic approach to your problem with an illustration:
import java.util.*;
class OverlappingIntervals
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
//int n = sc.nextInt();
ArrayList<Interval> intervals = new ArrayList<>();
intervals.add(new Interval(5, 14));intervals.add(new Interval(6, 9));
intervals.add(new Interval(8, 17));intervals.add(new Interval(23, 25));
intervals.add(new Interval(36, 56));intervals.add(new Interval(33, 45));
intervals.add(new Interval(42, 67));intervals.add(new Interval(50, 69));
intervals.add(new Interval(81, 95));intervals.add(new Interval(99, 111));
int result = overlappingIntervals(intervals);
System.out.println(result); // 82 b/w [5 , 17] & [99 , 111]
}
static int overlappingIntervals(ArrayList<Interval> intervals)
{
// Sorting all Intervals based on there `start` time
Collections.sort(intervals, Comparator.comparingInt(a -> a.begin));
int maxDistance = -1;
Stack<Interval> stack = new Stack<>();
for (Interval currInterval : intervals)
{
// Pushing a non-overlapping Interval
if (stack.empty() || stack.peek().end < currInterval.begin)
stack.push(currInterval);
// Merging an overlapping Interval
if (stack.peek().end < currInterval.end)
stack.peek().end = currInterval.end;
}
/* Now, Stack will have following merged Intervals:
[5 , 17] <6> [23 , 25] <8> [33 , 69] <12> [81 , 95] <4> [99 , 111] */
// Checking the gap b/w consecutive Merged-Intervals :
Interval rightEnd = stack.pop();
if (stack.empty()) return -1;
Interval leftEnd = rightEnd;
while (!stack.empty())
leftEnd = stack.pop();
maxDistance = rightEnd.begin - leftEnd.end;
return maxDistance;
}
}
class Interval
{
int begin, end;
Interval(int begin, int end)
{
this.begin = begin; this.end = end;
}
#Override
public String toString()
{ return "[" +begin+ " , " +end+ "]"; }
}
/** [5========17] [23=25] [33=================================69] [81===========95] [99======111]
* 5-------14 23---25 36-----------------56 81------------95
* 6---9 42----------------------67 99------111
* 8------17 33----------45 50----------------69 */
We can even do this without merging the intervals but I believe this approach is easier to understand.
Feel free to ask any doubts.
This is my solution though in C++ can be easily written in any language.
T.C - O(n + log(n))
S.C - O(1)
int overlappingIntervals(int n, vector<pair<int, int> >& intervals){
sort(intervals.begin(),intervals.end());
int mi = INT_MAX;
for(auto it: intervals){
mi = min(it.second,mi);
}
return (intervals[n-1].first < mi ? -1 : intervals[n-1].first - mi);
}
I don't know what it wrong with my code. Im supposed to put in an input file and sort the numbers from lowest to greatest. When i run the program it returns:Sorted array of 25 ints from P4input.txt after insertInOrder:
31 5 8 8 19 23 25 27 27 31 69 70 71 75 90 98 103 103 109 140 145 145 153 157 162
I don't know why the first number is out of order.
/* Project4.java InsertInOrder with bSearch optimization to compute insertion index */
import java.util.*;
import java.io.*;
public class Project4
{
static final int INITIAL_CAPACITY = 5;
public static void main( String args[] ) throws Exception
{
// ALWAYS TEST FIRST TO VERIFY USER PUT REQUIRED INPUT FILE NAME ON THE COMMAND LINE
if (args.length < 1 )
{
System.out.println("\nusage: C:\\> java Project4 <input filename>\n\n"); // i.e. C:\> java Project4 P4input.txt
System.exit(0);
}
// LOAD FILE INTO ARR USING INSERINORDER
Scanner infile = new Scanner( new File( args[0] ) );
int[] arr = new int[INITIAL_CAPACITY];
int count= 0;
while (infile.hasNextInt())
{
if ( count==arr.length )
arr = upSizeArr(arr);
insertInOrder( arr, count++, infile.nextInt() );
}
infile.close();
arr=trimArr(arr,count); // Now count == .length
System.out.println( "Sorted array of " + arr.length + " ints from " + args[0] + " after insertInOrder:" );
printArray( arr ); // we trimmed it thus count == length so we don't bother to pass in count
} // END MAIN
// ############################################################################################################
// USE AS IS - DO NOT MODIFY
static void printArray( int[] arr )
{
for( int i=0 ; i<arr.length ;++i )
System.out.print(arr[i] + " " );
System.out.println();
}
// USE AS IS - DO NOT MODIFY
static int[] upSizeArr( int[] fullArr )
{
int[] upSizedArr = new int[ fullArr.length * 2 ];
for ( int i=0; i<fullArr.length ; ++i )
upSizedArr[i] = fullArr[i];
return upSizedArr;
}
// USE AS IS - DO NOT MODIFY
static int[] trimArr( int[] oldArr, int count )
{
int[] trimmedArr = new int[ count ];
for ( int i=0; i<count ; ++i )
trimmedArr[i] = oldArr[i];
return trimmedArr;
}
// ############################################################################################################
static void insertInOrder( int[] arr, int count, int key )
{
int index=bSearch( arr, count, key ); // LEAVE THIS HERE
if (arr[arr.length - 1] == 0)
{
for (int i = count; i >= index + 1; i--)
{
arr[i] = arr[i - 1];
}
arr[index]=key; // LEAVE THIS HERE
}
}
static int bSearch(int[] a, int count, int key)
{
int hi = count-1;
int lo = 0;
int mid = 0;
if(hi == -1)
{
return lo;
}
else
{
mid = (hi+lo)/2;
}
while (lo <= hi)
{
if (key==a[mid])
{
return (mid+1);
}
else if (key < a[mid])
{
hi = mid-1;
mid = (hi+lo)/2;
}
else
{
lo = mid +1;
mid = (hi+lo)/2;
}
}
return (mid +1);
}
} // END PROJECT4
How do you loop through an array until you you reach the last 50 elements of your array then??
say I have this binary search code:
public class Binary
{
public static final int NOT_FOUND = -1;
public static <AnyType extends Comparable<? super AnyType>>
int binarySearch( AnyType [ ] a, AnyType x )
{
int low = 0;
int high = a.length - 1;
int mid;
while( low <= high )
{
mid = ( low + high ) / 2;
if( a[ mid ].compareTo( x ) < 0 )
low = mid + 1;
else if( a[ mid ].compareTo( x ) > 0 )
high = mid - 1;
else
return mid;
}
return NOT_FOUND; // NOT_FOUND = -1
}
// Test program
public static void main( String [ ] args )
{
int SIZE = 8;
Integer [ ] a = new Integer [ SIZE ];
for( int i = 0; i < SIZE; i++ )
a[ i ] = i * 2;
for( int i = 0; i < SIZE * 2; i++ )
System.out.println( "Found " + i + " at " +
binarySearch( a, i ) );
}
}
I would like to search the given array till I reach to the last 50 elements of this array, then the search is concluded with sequential look up of 50 elements.
My question is that how can I construct such a loop and how to jump to the method that does the linear search.
Before you calculate mid, do something like
if(high - low + 1 <= 50) return linearSearch(low, high, a, x);
Then your linearSearch just has to iterator from low to high to find x, or else return NOT_FOUND.
package x;
public class MaxHeap {
private Element[] heapArray;
private int maxSize;
private int currentSize;
public MaxHeap(int max) {
maxSize = max;
currentSize = 0;
heapArray = new Element[maxSize]; // create the heap
}
public boolean isEmpty() {
return currentSize == 0;
}
// Move an element up in the heap tree.
public void adjustHeap(int index) {
int parent = (index - 1) / 2;
Element bottom = heapArray[index];
while (index > 0 && heapArray[parent].getData() < bottom.getData()) {
heapArray[index] = heapArray[parent]; // move it down
index = parent;
parent = (parent - 1) / 2;
}
heapArray[index] = bottom;
}
public boolean insert(int key) {
if (currentSize == maxSize)
return false;
Element newElement = new Element(key);
heapArray[currentSize] = newElement;
adjustHeap(currentSize++);
return true;
}
public Element[] getMaxHeap() {
return heapArray;
}
public void printHeap() {
int i;
for (i = 0; i < maxSize; i++)
System.out.print(heapArray[i].getData() + " ");
System.out.println();
}
public void deleteMax() {
heapArray[0].setData(heapArray[maxSize - 1].getData());
currentSize--;
int i = 0;
while (i<=heapArray[maxSize - 1].getData()) {
int left = 2 * i + 1;
int right = 2 * i + 2;
if (heapArray[left].getData() <= heapArray[right].getData()) {
i = (2 * i + 1);
adjustHeap(right);
i++;
}
if (heapArray[left].getData() >= heapArray[right].getData()) {
i = (2 * i + 2);
adjustHeap(left);
i++;
}
}
}
}
package x;
class Element {
private int inData;
public Element(int data){
inData = data;
}
public int getData(){
return inData;
}
public void setData(int data){
inData = data;
}
}
package x;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
MaxHeap heap = new MaxHeap(13);
heap.insert(2);
heap.insert(20);
heap.insert(10);
heap.insert(5);
heap.insert(6);
heap.insert(15);
heap.insert(7);
heap.insert(8);
heap.insert(18);
heap.insert(11);
heap.insert(4);
heap.insert(3);
heap.insert(1);
heap.printHeap();
System.out.println("\n");
heap.deleteMax();
heap.printHeap();
}
}
My question is: Why is my while loop only executing one time? I want my deleteMax method to delete the max node (the root) then properly sort the heap so that it again is a max heap. the max heap is the following:
20 18 15 8 11 10 7 2 6 5 4 3 1
once deleteMax is called it should output:
18 11 15 8 5 10 7 2 6 1 3 4
but it instead outputs:
18 1 15 8 11 10 7 2 6 5 4 3 1
clearly it is deleting the max node, replacing it with the bottom most leaf, and swapping the new root with its largest child. It should then go on to swap 1 down the heap, but it stops before doing so.
I have tried lots of different logic for the while loop including:
while(Math.floor(i/2) <= 2*i+1 && Math.floor(i/2) <= 2*i+2)
and increasing i but nothing seems to work.
You're not rotating the root. Your loop body should look something like this.
if (heapArray[left].getData() < heapArray[i].getData()) {
temp = heapArray[i].getData();
heapArray[i].setData(heapArray[left].getData());
heapArray[left].setData(temp);
i = (2 * i + 1);
}
else if (heapArray[right].getData() > heapArray[i].getData()) {
temp = heapArray[i].getData();
heapArray[i].setData(heapArray[right].getData());
heapArray[right].setData(temp);
i = (2 * i + 2);
}
Your adjustHeap method might already be performing this swap, I couldn't be sure. The bottom line is that you need to rotate your root through the heap (rather than comparing branches), and you shouldn't have the i++ statement in there. It should also be < instead of <= and > instead of >=, but that's just a minor optimization.
The purpose of this was to brute force the Knights Tour by having it figure out which moves were legal before choosing one of the ones that are legal. I am new to Java but I feel like my error is in my inability to comprehend how to handle this problem:
import java.util.*;
public class KnightTour
{
public static void main( String[] args )
{
KnightTour kt = new KnightTour(8, 8);
int tries = 3;
int tryCount = 0;
while(tryCount < tries )
{
kt.makeMoves();
}
}
int rows = 0; //change to args later
int columns = 0; //change to args later
int tries = 0; //change to args later
String[][] saves;
int tryCount = 0;
int turnNr = 2;
int wait = 0;
Random rand = new Random();
int xCurrent = 1;
int yCurrent = 1;
int[] xMoves = { 1, 2, -1, -2, 1, 2, -1, -2 };
int[] yMoves = { 2, 1, 2, 1, -2, -1, -2, -1 };
public KnightTour( int x, int y)
{
rows = x;
columns = y;
saves = new String[y][x];
for (int i = 0; i < y; i++)
{
for (int j = 0; j < x; j++)
{
saves[i][j] = Integer.toString(0);
}
}
saves[0][0] = Integer.toString(1);
}
private void makeMoves()
{
int k = 0;
while( k < (rows * columns ) )
{
int[] d = { 0, 0, 0, 0, 0, 0, 0, 0 }; // holds move legality
int i = 0;
while( i < d.length ) // loop determines which moves are legal
{
if( xCurrent + xMoves[ i ] > 0 && xCurrent + xMoves[ i ] < rows )
{
if( xCurrent + yMoves[ i ] > 0 && yCurrent + yMoves[ i ] < rows )
d[ i ] = 1;
}
i++;
}
int t = 0;
int w = 0;
while( t < d.length ) // checks if no moves are legal
{
if( d[ t ] == 0 )
{
w++;
}
t++;
}
if( w == 8 )
{
writeFailures(); // fills the rest of the grid with "x"'s
k = (rows * columns); // breaks the loop
}
else
{
w = 0;
chooseMove( d );
}
k++;
}
printSolution();
}
private void chooseMove(int[] d) // chooses a move that was previously determined to be legal randomly and checks if it is available
{
System.out.println( "trace" );
Random rand = new Random();
int r = rand.nextInt(8);
switch( r )
{
case 0:
if( d[ 0 ] == 1 )
{
setX( xCurrent + xMoves[ 0 ] );
setY( yCurrent + yMoves[ 0 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 1:
if( d[ 1 ] == 1 )
{
setX( xCurrent + xMoves[ 1 ] );
setY( yCurrent + yMoves[ 1 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 2:
if( d[ 2 ] == 1 )
{
setX( xCurrent + xMoves[ 2 ] );
setY( yCurrent + yMoves[ 2 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 3:
if( d[ 3 ] == 1 )
{
setX( xCurrent + xMoves[ 3 ] );
setY( yCurrent + yMoves[ 3 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 4:
if( d[ 4 ] == 1 )
{
setX( xCurrent + xMoves[ 4 ] );
setY( yCurrent + yMoves[ 4 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr); // LINE 166
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 5:
if( d[ 5 ] == 1 )
{
setX( xCurrent + xMoves[ 5 ] );
setY( yCurrent + yMoves[ 5 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 6:
if( d[ 6 ] == 1 )
{
setX( xCurrent + xMoves[ 6 ] );
setY( yCurrent + yMoves[ 6 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
case 7:
if( d[ 7 ] == 1 )
{
setX( xCurrent + xMoves[ 7] );
setY( yCurrent + yMoves[ 7 ] );
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
turnNr++;
}
else
{
chooseMove(d);
}
break;
default:
System.out.println( "error" );
}
}
public int getX()
{
return xCurrent;
}
public void setX(int x)
{
xCurrent = x;
}
public int getY()
{
return yCurrent;
}
public void setY(int y)
{
yCurrent = y;
}
private void writeFailures() // writes an "x" to empty spots in the save array when no legal moves are found
{
for (int i = 0; i < saves.length; i++)
{
for (int j = 0; j < saves[i].length; j++)
{
if( saves[i][j] == "0");
saves[i][j] = "x";
}
}
}
private void printSolution()
{
for (int i = 0; i < saves.length; i++)
{
for (int j = 0; j < saves[i].length; j++)
{
System.out.print(saves[i][j] + " ");
}
System.out.println("");
}
System.out.println("");
}
}
The error I get is:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2
at KnightTour.chooseMove(KnightTour.java:166)
at KnightTour.makeMoves(KnightTour.java:91)
at KnightTour.main(KnightTour.java:14)
EDIT: Now the code line numbers are OK.
Array out of bounds errors generally mean that you are attempting to call a storage location in an array which exceeds the array's size. If you declared the array with a fixed size (say, 8 data points), you would ONLY be able to set and retrieve array values from array[0] to array[7].
By default, array counting starts at 0 rather than 1, which is the cause of most out-of-bounds errors, as people will try to access the last element which they assume is, in reference to my example above, array[8].
The easiest way to avoid out-of-bounds errors is to declare your array with a nil size, which will allow it to expand to the size needed. However, this risks memory leaks in the case of runaway code.
The issue comes up when you call this line (one of the similar ones)
setY( yCurrent + yMoves[ 4 ] );
When yCurrent<0. When this happens, yCurrent becomes -2 (since yMoves[4]=-2), and you then call this line of code:
saves[yCurrent][xCurrent] = Integer.toString(turnNr);
Since yCurrent<0, you're trying to access an array index that doesn't exist; hence the exception.
Now, this error could come up a number of times (and did in my testing); a similar effect could also happen when yCurrent (or xCurrent) becomes a value greater or equal to the array size, for the same reason.
I have examined your code and from that it seems like, saves[yCurrent][xCurrent] = Integer.toString(turnNr);
is throwing an exception. The logic which is changing yCurrent and xCurrent is improper.
So that even if you increase your saves array limit to saves[100][100], its behaving the same.
I suggest you to understand the code and flow first rather than directly working on exception.
The bug is in the "loop determines which moves are legal" near the top of makeMoves()
The line
if (xCurrent + yMoves[i] > 0 && yCurrent + yMoves[i] < rows)
should instead be
if (yCurrent + yMoves[i] > 0 && yCurrent + yMoves[i] < rows)