I'm learning algorithms and data structures and I'm now on the part of time and space complexity.
I have to solve a problem and them tell (based on my code) the time and spatial complexity.
This is the code:
public class B {
public static int minSum = -1;
public static void main(String[] args) {
int objects, sumA = 0, sumB = 0;
Scanner readInput = new Scanner(System.in);
objects = readInput.nextInt();
int[] trunk = new int[objects];
if (objects == 0) {
System.out.print(0 + "\n");
} else if (objects == 1) {
trunk[0] = readInput.nextInt();
System.out.print(trunk[0] + "\n");
} else {
for (int i = 0; i < objects; i++) {
trunk[i] = readInput.nextInt();
}
bruteforce(trunk, sumA, sumB, 0);
System.out.println(minSum);
}
}
public static void bruteforce(int[] trunk, int sumA, int sumB, int index) {
int partialDiff;
if (minSum == 0) {
System.out.println(minSum);
System.exit(0);
} else if (index == trunk.length) {
partialDiff = Math.abs(sumA - sumB);
if (partialDiff < minSum || minSum == -1) {
minSum = partialDiff;
}
} else {
bruteforce(trunk, sumA + trunk[index], sumB, index + 1);
bruteforce(trunk, sumA, sumB + trunk[index], index + 1);
}
}
}
Basically the user first inputs a number of objects and then inputs, for each object, its value. The algorithm will distribute the objects by two bags and must calculate the min difference that can be calculated when distributing the objects by the two bags.
I believe that it takes exponential time but I'm struggling with an estimative for the spatial complexity. Can you point me In some direction?
The space complexity is linear - O(n).
You calculate this by multiplying the amount of memory used in each function call by the max recursion depth.
There is a constant amount of memory being used in each function call - just partialDiff and stack information.
To determine the max recursion depth, you can basically just look at index (since this is the variable that decides when it stops recursing deeper).
You call the function with index = 0.
At each recursive call, index increases by one.
As soon as index reaches the size of the array, it stops.
Note that function calls are depth-first, meaning it will completely evaluate the first call to bruteforce before the second call, thus only one will take up memory at a time.
So, for an array of length 2, it goes something like this: (Call 1 is the first function call, Call 2 the second)
Call with index 0
Call 1 with index 1
Call 1 with index 2
Call 2 with index 2
Call 2 with index 1
Call 1 with index 2
Call 2 with index 2
So the max depth (and thus space complexity) is 3, one more than the number of items in the array.
So it's memory used in each function call * max depth = constant * linear = linear.
Related
Suppose we have the following algorithm for finding min/max in an array using divide an conquer (Courtesy to Source):
// A Pair class to wrap immutable primitive ints
class Pair
{
public int max, min;
public Pair(int max, int min)
{
this.max = max;
this.min = min;
}
}
class Main
{
// Divide and conquer solution to find the minimum and maximum number in an array
public static void findMinAndMax(int[] A, int left, int right, Pair p)
{
// if the array contains only one element
if (left == right) // common comparison
{
if (p.max < A[left]) { // comparison 1
p.max = A[left];
}
if (p.min > A[right]) { // comparison 2
p.min = A[right];
}
return;
}
// if the array contains only two elements
if (right - left == 1) // common comparison
{
if (A[left] < A[right]) // comparison 1
{
if (p.min > A[left]) { // comparison 2
p.min = A[left];
}
if (p.max < A[right]) { // comparison 3
p.max = A[right];
}
}
else {
if (p.min > A[right]) { // comparison 2
p.min = A[right];
}
if (p.max < A[left]) { // comparison 3
p.max = A[left];
}
}
return;
}
// find the middle element
int mid = (left + right) / 2;
// recur for the left subarray
findMinAndMax(A, left, mid, p);
// recur for the right subarray
findMinAndMax(A, mid + 1, right, p);
}
public static void main(String[] args)
{
int[] A = { 7, 2, 9, 3, 1, 6, 7, 8, 4 };
// initialize the minimum element by `INFINITY` and the
// maximum element by `-INFINITY`
Pair p = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
findMinAndMax(A, 0, A.length - 1, p);
System.out.println("The minimum array element is " + p.min);
System.out.println("The maximum array element is " + p.max);
}
}
Question: Each time we return from recursion to the caller method from previous step. Will Pair object saves it's values min, max when returns, given that we delete the method that finishes execution during recursion from the stack please?
Methods are loaded in Stack Memory while Objects are loaded in Heap Memory. So completing the method has no impact on the Objects those are created by method. Of that objects is being referred by some current running thread (directly or indirectly) that will stay alive and won't be collected by Garbage Collector.
So answer to your question is Yes. As Pair is being referred so it will stay. And so min and max are still be referred by Pair so that will also stay.
Continuing to that, that is also how PassByReference works. Where you pass an Object from a method to another method (Objects is not immutable and it's not reinitialized and it's not primitive) all the updated in the called method will get reflected in calling method.
As in your case Pair is created inside main method and being passed to another methods, so till the time main is not finishing it's execution it will stay in heap memory and won't get garbage collected.
No, it will not. There is only one instance of Pair: the one created in method main. The values of min and max are overwritten as required.
I am working on trying to write a program where a user will enter 6 strings and then it will sort the array in reverse alphabetical order using a recursive method. This is one concept I do not understand despite multiple videos, readings and attempts. Any support and insight is greatly appreciated. Thank you.
import java.util.Arrays;
import java.util.Scanner;
public class SRecusion {
public static void sort2 (String[] sort2) {
int i;
int min = 0;
int max;
for (i = 0; i <sort2.length -1; i++) {
if (sort2[i].charAt(0)> sort2[i=1].charAt(0)) {
sort2[i] = sort2[min];
}
else {
min = (sort2(sort2[i-1]));
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String [] test = new String[6];
Scanner scnr = new Scanner(System.in);
String userEntry = "";
for(int i = 0; i <= test.length - 1; i++) {
System.out.println("Please enter a word:");
test[i] = scnr.nextLine();
}
sort2(test);
System.out.println("your list is" + Arrays.asList(test));
System.out.println();
}
}
Sorting is a pretty broad topic as there are many different sorting methods (quicksort, merge sort, etc.) However, a pretty basic and simple sorting method is bubble sort. Although it isn't the fastest one, it's pretty easy to understand and code using recursion.
Essentially, bubble sort with iterate through the elements in pairs of 2 and swap the two elements if they're in the wrong order.
For example, let's sort (3, 2, 5, 4, 1) using bubble sort.
(2, 3, 5, 4, 1) First, it'll look at the first two elements swap them if needed. Since 3 is greater than 2, it'll swap them.
(2, 3, 5, 4, 1) Next, it'll look at 3 and 5. Since 3 is less than 5, there is no need to swap
(2, 3, 4, 5, 1) It now looks at 5 and 4 and swaps them.
(2, 3, 4, 1, 5) Finally, it looks at 5 and 1 and swaps them.
Now start from the beginning and repeat the whole process. The sorting ends if exactly 0 swaps are made during an iteration.
If you're still a bit confused, try watching a tutorial on bubble sort or visit this link.
So from what I was asking above as to why you need a recursive sorting algorithm Here it goes I will try to explain how recursive sorting works. It took my some time to figure it out as I am sure it does for most people who first come in contact with it.
public static void Qsort(int[] array, int start, int end)
{
//find the current center of the whole or parital array part I am working on.
int center = (start+end)/2;
///System.out.println("\n This is the center : " + center);
int pivot, i, pivotplace;
i = 0;
pivot = 0;
pivotplace = 0;
//if start = end then we are at a single element. just return to the previous iterative call.
if(start == end)
{
// System.out.println("\n Inside base case return :");
return;
}
//find the pivot value we are using. using a 3 prong selection we are assured to at least get some type of median value and avoid the N^2 worst case.
pivot = getpivot(array[start], array[center], array[end]); //gets median value of start, center and end values in the array.
// System.out.println("\n pivotvalue is : " + pivot);
//find where the current pivot is located and swap it with the last element in the current portion of the array.
if(array[start] == pivot)
{
//System.out.print("\n Inside pivot at start");
swap(array, start, end);
}
else
{
if(array[center] == pivot)
{
//System.out.print("\n Inside pivot at center");
swap(array, center, end);
}
}
//due to iteration the pivot place needs to start at the passed in value of 'start' and not 0.
pivotplace = start;
//due to iteration the loop needs to go from the passed in value of start and not 0 and needs to go
//until it reaches the end value passed in.
for(i = start; i < end; i++)
{
//if the current slot of the array is less than then pivot swap it with the current pivotplace holder
//since the pivotplace keeps getting iterated up be each swap the final place of pivot place
//is where the pivot will actually be swapped back to after the loop cpompletes.
if(array[i] < pivot)
{
//System.out.print("\n Swapping");
swap(array, i, pivotplace);
pivotplace++;
}
}
//loop is finished, swap the pivot into the spot it belongs in.
swap(array, pivotplace, end);
//there are 2 cases for recursive iteration.
//The first is from the start to the slot before the pivot
if(start < pivotplace){Qsort(array, start, pivotplace-1);}
//the second is from the slot after the pivot to the end.
if(pivotplace+1 < end){Qsort(array, pivotplace+1, end);}
}
public static int getpivot(int a, int b, int c)
{
if((a > b) && (a < c))
{
return a;
}
if((b > a) && (b < c))
{
return b;
}
return c;
}
public static void swap(int[] array, int posa, int posb)
{
int temp;
temp = array[posa];
array[posa] = array[posb];
array[posb] = temp;
}
This is a basic Quick Sort or recursive sort I wrote this while in programming classes. You will probably not need to use the getpivot code as you are dealing with a small set of strings, but if you do some research you will see using a possible sample of 3 drastically speeds up the recursion due to balanced work load of the recursion tree.
Sort Array using recursion in kotlin
fun main() {
print(sortArray(arrayListOf(1,3,2,6,8,3)))
}
fun sortArray(arr: MutableList<Int>): MutableList<Int>{
if(arr.size==1) {
return arr
}
val lastValue = arr.last()
arr.removeLast()
sortArray(arr)
insert(arr, lastValue)
return arr
}
fun insert (arr: MutableList<Int>, value: Int): MutableList<Int> {
if(arr.size == 0 || arr.last() < value) {
arr.add(value)
return arr
}
val lastValue = arr.last()
arr.removeLast()
insert(arr, value)
arr.add(lastValue)
return arr
}
I need to get a number of all possible ways to divide array into small sub-arrays. We can divide array verticaly and horizontaly. My algorithm works very good, but time complexity is too bad. Can you have a look how to improve it?
Parameters
nStart - first row of sub-array
nEnd - last row of sub-array
mStart, mEnd - are for second dimension (columns).
check() - functions checking end condition
return - numbers of different ways to divide array. We divide while function check return true.
public static long divide(int nStart, int nEnd, int mStart, int mEnd) {
long result = 0;
for(int i = 1; i < nEnd - nStart; i++) {
if(check(nStart, nStart + i, mStart, mEnd) && check(nStart + i, nEnd, mStart, mEnd))
result += divide(nStart, nStart + i, mStart, mEnd) * divide(nStart + i, nEnd, mStart, mEnd);
}
for(int i = 1; i < mEnd - mStart; i++) {
if(check(nStart, nEnd, mStart, mStart + i) && check(nStart, nEnd, mStart + i, mEnd))
result += divide(nStart, nEnd, mStart, mStart + i) * divide(nStart, nEnd, mStart + i, mEnd);
}
return (result == 0 ? 1 : result) % 1000000000;
}
Example
Input
2 2
10
01
Output 2
Input
3 2
101
010
Output 5
I think you need to know how check() function works. We stop dividing when next subarray have only ones or only zeros. Here is code:
public static boolean check(int nStart, int nEnd, int mStart, int mEnd) {
if((nEnd - nStart) + (mEnd - mStart) == 2)
return false;
for(int i = mStart; i < mEnd; i++) {
for(int j = nStart; j < nEnd; j++) {
if(bar[i][j] != bar[mStart][nStart])
return true;
}
}
return false;
}
By looking at your code I can see that in each step of the recursion you divide your two-dimensional array into two arrays with a single horizontal or vertical cut. Then you verify that both of these parts fulfil some condition of yours defined by the check-method and, if so, then you put these two parts into a recursion. When the recursion can no longer be continued, you return 1. Below I assume that your algorithm always produces the result you want.
I'm afraid that an effective optimization of this algorithm is highly dependent on what the check-condition does. In the trivial case it would always retuns true, when the problem collapsed into a straightforward mathematical problem that propably has a general non-recursive solution. A bit more complex, but still effectively solvable would be a scenario where the condition would only check the shape of the array, meaning that e.g. check(1,5,1,4) would return the same result as check(3,7,5,8).
The most complex is of course a general solution, where the check-condition can be anything. In this case there is not much that can be done to optimize your brute force solution, but one thing that comes to my mind is adding a memory to you algorithm. You could use the java.awt.Rectangle class (or create your own class) that would hold the dimensions of a sub-array and then have a java.util.HashMap to store the results of the executions of the divide-method for furure reference, if the method is called again with the same parameters. This would prevent duplicate work that will propaply occur.
So you define the haspmap as a static variable in you class:
static HashMap<Rectangle,Long> map = new HashMap<Rectangle,Long>();
then in the beginning of the divide-method you add the following code:
Rectangle r = new Rectangle(nStart,mStart,nEnd,mEnd);
Long storedRes = map.get(r);
if (storedRes != null) {
return storedRes;
}
and then you change the ending of the method into form:
result = (result == 0 ? 1 : result) % 1000000000;
map.put(r, result);
return result;
This should give a performance-boost for your algorithm.
To return to my earlier tought, if the check-condition is simple enough, this same optimization can be done even more effectively. For example, if your check-condition only checks the shape of the array, you will only need to have its width and height as a key to the map, which will decrease the size of the map and multiple the number of positive hits in it.
Ok I'm trying to write an algorithm for sorting an array, in this case an array of random integers. I know QuickSort or similar would obviously more efficient, but for this assignment I have to basically make a modified version of the inefficient Bubble Sort algorithm.
The idea is to compare integers across a gap. After each pass, the gap is supposed to be cut in half. If value on left is greater than value on right, they are swapped. Execution is supposed to continue until no swaps occurs or gap is 1. I'm usually pretty descent at this sort of thing but it seems that I'm missing something. For some reason the algorithm isn't sorting my arrays.
Here is my code. Maybe someone can see what I'm missing:
public class ShellArray
{
private int capacity;
private int [] randArray;
private static final int RANGE = 200; //Range set to 200 for possible integers.
public ShellArray(int capacity)
{
this.capacity = capacity;
randArray = new int[capacity];
populate(randArray, RANGE, capacity);
}
/**************************************************************************************************************************************************
//
//Populates array with random integers within given range.
//
***************************************************************************************************************************************************/
private static void populate(int [] myArray, int numRange, int extent)
{
Random r = new Random();
for (int i = 0; i < extent; i++)
myArray[i] = (r.nextInt(numRange)+1);
}
/**************************************************************************************************************************************************
//
//The first version of shellSort calls the second version with min value as 0 and max as length of randArray-1. Takes no parameters.
//
***************************************************************************************************************************************************/
public void shellSort()
{
shellSort(0, randArray.length-1);
}
/**************************************************************************************************************************************************
//
// shellSort which takes min and max parameters. Calculates gap at center, across which values are compared. Passes continue until gap size is 1
// and array is sorted.
// Uses boolean sorted to indicate when array is sorted so passes don't continue needelessly after array is sorted. Essentially, if no values
// are swapped after a pass, we know array is sorted and sorted is not set to false.
//
// Outer for loop controls position of final value. Since largest value is bubbled to end, position decreases by 1 after each pass.
// After each pass, size of gap is cut in half, as long as gap is 2 or greater. Otherwise gap would become too small.
// Inner for loop controls the index values to be compared.
// Uses swap method to swap values which are not in the correct order.
// Array is printed after each pass.
//
***************************************************************************************************************************************************/
public void shellSort(int min, int max)
{
String result;
int gap;
int j = 0;
int size = randArray.length-1;
boolean swapped;
for(gap = size/2; gap <= 0; gap = gap/2)
{
swapped = true;
while (swapped)
{
swapped = false;
int comp;
for(comp = 0; comp+gap <= size; comp++)
{
if (randArray[comp] > randArray[comp+gap])
{
swap(comp, comp+gap);
swapped = true; //swapped set to true if any element is swapped with another.
}
else
swapped = false;
}
}
result = "";
for(int y = 0; y < randArray.length; y++)
{
result += randArray[y] + " ";
j++;
}
System.out.println("Pass " +j+": " +result+"\n");
}
}
/**************************************************************************************************************************************************
//
// Swaps two values in the array.
//
***************************************************************************************************************************************************/
private void swap(int index1, int index2)
{
int temp = randArray[index1];
randArray[index1] = randArray[index2];
randArray[index2] = temp;
}
public String toString()
{
String result = "";
for(int y = 0; y < randArray.length; y++)
result += randArray[y] +" ";
return result;
}
}
You haven't provided the details of your assignment, but the idea of a sort along these lines is that the final stage (i.e. with gap == 1) is a bona fide standard sort all on its own -- in this case, I guess a bubble sort -- and the prior stages pre-treat the input so that the efficiency of that final sort is much better than for random input. At least for gap == 1, then, you must repeat the sort loop until there are no swaps.
There are two main variations possible here, and you haven't given us the information to know which you want:
The first variation shrinks the gap after each iteration of the sort loop until it reaches 1, then repeats with that gap until there are no more swaps.
The second variation repeats the sort loop with the same gap until there are no swaps, then shrinks the gap and repeats.
My guess would be that you want the second, as that's the one that is actually a shell sort (of an unusual flavor). Even though it might sound like it would be less efficient than the other, there's a good chance that it's more efficient, because devoting a small amount of additional effort when the gap is large accomplishes larger element movements in fewer steps.
we got a matrix size of NxN which is represented by a multidimentional array, the matrix contains integer numbers, we assume that N=2^K.
We can also say that the matrix is ordered by cutting the matrix to 4 quarters (image below), every element in the first quarter is smaller or equal to the element in the second quarter, every element in the second quarter is smaller or equal to the third quarter, and every element in the third quarter is smaller or equal to every element in the forth quarter. (and so on recursivly)
like this:
1 2
3 4
Example of sorted matrix:
We need to write a function that returns true if the num exist in the matrix.
and to make it as most efficient as possible.
I've wrote the following function:
public static boolean isExist(int[][] mat, int num)
{
int start_rows = 0;
int start_columns = 0;
// If more then 4 elements
// Loop log(base 4)n
for (int elements_size = mat.length * mat[0].length, table_size, quarter_size,
quarter1, quarter2, quarter3, quarter4;
(elements_size > 4);
elements_size /= 4)
{
table_size = (int)(Math.sqrt(elements_size));
quarter1 = mat[start_rows+(table_size/2)-1][start_columns+(table_size/2)-1];
quarter2 = mat[start_rows+(table_size/2)-1][start_columns+table_size-1];
quarter3 = mat[start_rows+table_size-1][start_columns+(table_size/2)-1];
quarter4 = mat[start_rows+table_size-1][start_columns+table_size-1];
if (num == quarter1 || num == quarter2 || num == quarter3 || num == quarter4) {
return true;
}
// Decrease elements_size
quarter_size = (int)Math.sqrt(elements_size/4);
if (quarter1 > num) {
// Dont do anything
} else if (quarter2 > num) {
start_columns += quarter_size; // Increase columns
} else if (quarter3 > num) {
start_rows += quarter_size; // Increase rows
} else if (quarter4 > num) {
start_rows += quarter_size; // Increase rows
start_columns += quarter_size; // Increase columns
} else {
return false; // bigger then quarter, fail.
}
}
return (mat[start_rows][start_columns] == num || mat[start_rows+1][start_columns] == num ||
mat[start_rows][start_columns+1] == num || mat[start_rows+1][start_columns+1] == num);
}
Is that the most efficient way to do so?
Also its time complexity is O(logn). (am I correct?)
well, that is a good approach!
if i understood you right, you want to find out if the array includes a specific int-value;
well, i would use the following methode (but you have to match this to a int [][] array):
HashSet<Integer> test= new HashSet<Integer>(Arrays.asList(intArray));
test.contains(intValue)
this approach is pretty fastest because the hashcode-mechanism has the complexity O(1) but i think through the asList()- it leads to arraylist complexity O(n)... not sure about this!!
It can be done in time complexity O(n). I am not sure if the post is still active. But below is my solution to do it in O(n).
public class NumberInMatrix {
public static void main(String args[]){
int matrix[][] = {{-4,-2,5,9},
{2,5,12,13},
{13,20,25,25},
{22,24,49,57},};
System.out.println(isExist(matrix, 1));
}
private static String isExist(int[][] matrix, int numberToBeSearched) {
int rowCounter = 0, colCounter = matrix[0].length - 1;
while(rowCounter < matrix.length && colCounter >= 0){
if(numberToBeSearched == matrix[rowCounter][colCounter]){
return "Number exist";
}else{
if(numberToBeSearched > matrix[rowCounter][colCounter]){
rowCounter++;
}else{
colCounter--;
}
}
}
return "Number does not exist";
}
}