Stackoverflow Error while finding min and max in an array? - java

I am working on a problem to find Minimum and Maximum value in an array. I have my below program, whenever I run it, I am seeing java.lang.StackOverflowError:
public class MinMaxInArray {
public static void main(String[] args) {
int a1[] = { 3, 4, 2, 6, 8, 1, 9, 12, 15, 11 };
Pair result = getMinMax(a1, 0, a1.length - 1);
System.out.println("Min: " + result.min);
System.out.println("Max: " + result.max);
}
public static Pair getMinMax(int[] arr, int low, int high) {
Pair result = new Pair();
Pair left = new Pair();
Pair right = new Pair();
// if there is only one element arr= {1}
if (low == high) {
result.min = arr[low];
result.max = arr[high];
}
// if there are two element arr={1,2}
if (high == low + 1) {
if (arr[low] > arr[high]) {
result.max = arr[low];
result.min = arr[high];
} else {
result.max = arr[high];
result.min = arr[low];
}
return result;
}
// if there are more than 2 elements
int mid = (low + high) / 2;
left = getMinMax(arr, low, mid);
right = getMinMax(arr, mid + 1, high);
if (left.min < right.min) {
result.min = left.min;
} else {
result.min = right.min;
}
if (left.max > right.max) {
result.max = left.max;
} else {
result.max = right.max;
}
return result;
}
static class Pair {
int min;
int max;
}
}
Why this error is being thrown and what does it mean? How can I fix this?

You forgot the return result; in this piece of code:
// if there is only one element arr= {1}
if (low == high) {
result.min = arr[low];
result.max = arr[high];
return result;
}

I don't think recursion makes sense for this task. This code works well:
int a1[] = { 3, 4, 2, 6, 8, 1, 9, 12, 15, 11 };
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int a : a1) {
if (a < min) {
min = a;
}
if (a > max) {
max = a;
}
}
System.out.println("Min: " + min);
System.out.println("Max: " + max);

Unless you want to make it recursively, easiest solution is using a stream:
IntSummaryStatistics stats = Arrays.stream(a1).summaryStatistics();
int max = stats.getMax();
int min = stats.getMin();
// or:
int max = Arrays.stream(a1).max();
int min = Arrays.stream(a1).min();
Other way is using for-loop and simply checking every number:
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i : a1) {
if (i > max) {
max = i;
}
if (i < min) {
min = i;
}
}

Related

Java Find Closest Pair Based on Sum is ArrayIndexOutOfBoundsException [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 2 years ago.
Am trying to find the closest pair based on sum but am getting a
java.lang.ArrayIndexOutOfBoundsException: -1
Find a pair in array whose sum is closest to sum.
e.g.
Input: arr[] = {10, 22, 28, 29, 30, 40}, sum = 54
Output: 22 and 30
My solution:
import java.util.Arrays;
public class ArrayUtils {
public static int[] closestPairBasedOnSum(int[] arr, int sum) {
if (arr == null) {
return null;
}
if (sum < 1) {
return null;
}
int[] closestPair = new int[2];
int left = 0;
int right = arr.length - 1;
int diff = Integer.MAX_VALUE;
while (right > left) {
// this if is throwing the ArrayIndexOutOfBoundsException
if (Math.abs(arr[left] + arr[right] - sum) < diff) {
closestPair[0] = arr[left];
closestPair[1] = arr[right];
diff = Math.abs(arr[left] + arr[right] - sum);
}
if (arr[left] + arr[right] > sum) {
right--;
}
else {
left--;
}
}
System.out.println(Arrays.toString(closestPair));
return closestPair;
}
public static void main(String[] args) {
int [] arr = new int[] {10, 22, 28, 29, 30, 40};
int[] closestPair = ArrayUtils.closestPairBasedOnSum(arr, 54);
System.out.println(Arrays.toString(closestPair));
}
}
Outputs:
java.lang.ArrayIndexOutOfBoundsException: -1
Why is it not returning [22, 30]?
Figured out the solution:
public static int[] closestPairBasedOnSum(int[] arr, int sum) {
if (arr == null) {
return null;
}
if (sum < 1) {
return null;
}
int[] closestPair = new int[2];
int left = 0;
int right = arr.length - 1;
int diff = Integer.MAX_VALUE;
while (right > left) {
if (Math.abs(arr[left] + arr[right] - sum) < diff) {
closestPair[0] = arr[left];
closestPair[1] = arr[right];
diff = Math.abs(arr[left] + arr[right] - sum);
}
if (arr[left] + arr[right] > sum) {
right--;
}
else {
left++;
}
}
System.out.println(Arrays.toString(closestPair));
return closestPair;
}

Java - Recursion to find the 2 smallest nums in array

So I have this problem of finding the 2 smallest numbers in array but I have to use recursion (the recursion part is a part of this exercise).
I start thinking how to do it and 'the plan' that I trying to do is like this, first of all find the smallest in the array, then mark where I found it and then to split the array in to 2 groups and search in this 2 group an eventuality take the minimum from them..
this is the code that I got this far:
public static int MinRecu2(int[] a) {
if (a.length == 1)
return a[0];
int min = a[0];
int min2;
int mark = 0;
// Find first min
for (int i = 1; i < a.length; i++) {
if (a[i] < min) {
min = a[i];
mark = i;
}
}
int [] help1= new int [mark+1];
int [] help2= new int [a.length-mark];
help1=Arrays.copyOfRange(a, 0, mark);
help2=Arrays.copyOfRange(a, mark+1, a.length-1);
// Find second min
min2 = Math.min(MinRecu2(help1), MinRecu2(help2));
return min;
}
I know the code not working and that the 'recursion' I was trying to do is bad, but that how I was trying to make my thinking to code
This is an approach to your question.
public static int[] twoSmallest(int[] arr, int s, int e) {
int[] list;
if (e - s <= 3) { // maybe 2 or 3
list = new int[e - s];
for (int i = s; i < e; i++)
list[i - s] = arr[i];
} else {
int[] left = twoSmallest(arr, s, (s + e) / 2);
int[] right = twoSmallest(arr, (s + e) / 2, e);
list = new int[4];
list[0] = left[0];
list[1] = left[1];
list[2] = right[0];
list[3] = right[1];
}
Arrays.sort(list);
return new int[] {list[0], list[1]};
}
This function means find two smallest numbers in arr in [s, e). You can call like this:
int[] result = twoSmallest(arr, 0, arr.length);
private static int findMinFromArray(int[] iArray, int index, int min) {
if(index <= (iArray.length - 1)){
if(iArray[index] < min){
min = iArray[index];
}
System.out.println("Before: " + "Index = " + index + " | Min = " + min);
findMinFromArray(iArray, index + 1, min);
}
System.out.println("After: " + "Index = " + index + " | Min = " + min);
return min;
}
I'm not sure how to get the program to stop, rather than going back again like it's doing.This finds only smallest.

sorting using heapsort in java

import java.util.Arrays;
public class Test{
//main method
public static void main(String... args){
int[] a = new int[]{16,14,10,8,7,9,3,2,4,1};
System.out.println("unsorted array " + Arrays.toString(a));
heap_sort(a);
System.out.println("Sorted array " + Arrays.toString(a));
}
//returns left child index of given index
private static int left_child(int i){
return (i * 2 + 1);
}
//returns right child index of the given index
private static int right_child(int i){
return (i * 2 + 2);
}
public static void max_heapify(int[] array , int index , int heap_size){
int largest = index;
int left = left_child(index);
int right = right_child(index);
if(left < heap_size && array[left] > array[index]){
largest = left;
}
else largest = index;
if (right < heap_size && array[right] > array[largest]){
largest = right;
}
if(largest != index){
//exchange array[index] with array[largest]
int a = array[index];
array[index] = array[largest];
array[largest] = a;
max_heapify(array,largest,heap_size);
}
}
public static void build_max_heap(int[] array){
int heap_size = array.length - 1;
for (int i = ((array.length - 1) / 2) ; i >= 0 ; i--){
max_heapify(array, i, heap_size);
}
}
//main heap sort function
public static void heap_sort(int[] array){
int heap_size = array.length - 1;
build_max_heap(array);
for(int i = (array.length - 1) ; i > 0 ; i--){
//exchange array[0] with array[i]
int a = array[0];
array[0] = array[i];
array[i] = a;
heap_size = heap_size - 1;
max_heapify(array , 1 , heap_size);
}
}
}
I have tried almost every possibility but it doesn't works fine .Could u find out where i am wrong.
Output of my code is :
unsorted array [16, 14, 10, 8, 7, 9, 3, 2, 4, 1]
Sorted array [14, 10, 8, 7, 9, 3, 2, 4, 1, 16]
There are some problems:
- Left and right child are modified because you loose the first element in the array.
- In max_heapify function, the loops are <=
- In heap_sort function you must pass 0 instead of 1 to the max_heapify function.
//returns left child index of given index
private static int left_child(int i)
{
return (i * 2);
}
//returns right child index of the given index
private static int right_child(int i)
{
return (i * 2 + 1);
}
public static void max_heapify(int[] array, int index, int heap_size)
{
int largest = index;
int left = left_child(index);
int right = right_child(index);
if (left <= heap_size && array[left] > array[index])
{
largest = left;
}
if (right <= heap_size && array[right] > array[largest])
{
largest = right;
}
if (largest != index)
{
//exchange array[index] with array[largest]
int a = array[index];
array[index] = array[largest];
array[largest] = a;
max_heapify(array, largest, heap_size);
}
}
public static void build_max_heap(int[] array)
{
int heap_size = array.length - 1;
for (int i = ((array.length - 1) / 2); i >= 0; i--)
{
max_heapify(array, i, heap_size);
}
}
//main heap sort function
public static void heap_sort(int[] array)
{
int heap_size = array.Length - 1;
build_max_heap(array);
for (int i = (array.Length - 1); i > 0; i--)
{
//exchange array[0] with array[i]
int a = array[0];
array[0] = array[i];
array[i] = a;
heap_size = heap_size - 1;
max_heapify(array, 0, heap_size);
}
}
The problem is that you loose items because the left and right child must be:
//returns left child index of given index
private static int left_child(int i){
return (i * 2);
}
//returns right child index of the given index
private static int right_child(int i){
return (i * 2 + 1);
}

Palindrome Partitioning DP complexity issue on memorization step

I have the following problem:
Given a string s, partition s such that every substring of the
partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
I got the correct solution but I am missing an optimization step, more particularly the memorization step needed in DP.
public int minCut(String a) {
if (isValidPal(a)) {
return 0;
}
return minCut(a, 0, 0);
}
int min = Integer.MAX_VALUE;
private int minCut(String a, int cut, int index) {
// too many cuts already
if(cut >= min) return min;
// out of index
if (index >= a.length()) {
// what is left is a pal
if (isValidPal(a)) {
min = Math.min(min, cut);
return cut;
}
return Integer.MAX_VALUE;
}
int newCut = Integer.MAX_VALUE;
if (isValidPal(a.substring(0, index + 1))) {
// then cut
newCut = minCut(a.substring(index + 1), cut + 1, 0);
}
// continue either way
newCut = Math.min(minCut(a, cut, index + 1), newCut);
return newCut;
}
HashMap<String, Boolean> memo = new HashMap<>();
private boolean isValidPal(String s) {
if(memo.containsKey(s)) {
return memo.get(s);
}
boolean result = true;
for (int i = 0; i < s.length() / 2; i++) {
if (s.charAt(i) != s.charAt(s.length() - i - 1)) {
result = false;
break;
}
}
memo.put(s, result);
return result;
}
Try adding a memo to store the results of your computations , assuming your algorithm is correct this should do the optimization
Map<String, Integer> dp = new HashMap<>();
private int minCut(String a, int cut, int index) {
// too many cuts already
if(cut >= min) return min;
String key = cut + " " + index;
//test if the memo contains the answer if yes return it
if(dp.containsKey(key)) return dp.get(key);
// out of index
if (index >= a.length()) {
// what is left is a pal
if (isValidPal(a)) {
min = Math.min(min, cut);
return cut;
}
return Integer.MAX_VALUE;
}
int newCut = Integer.MAX_VALUE;
if (isValidPal(a.substring(0, index + 1))) {
// then cut
newCut = minCut(a.substring(index + 1), cut + 1, 0);
}
// continue either way
newCut = Math.min(minCut(a, cut, index + 1), newCut);
//put the computed answer in the memo table
dp.put(key, newCut);
return newCut;
}
i'm sorry but my answer was based on the fact that your code is correct , here is a working example of a min palindrom partitioning with memoization
import java.util.*;
class Main {
static HashMap<String, Integer> memo = new HashMap<>();
static String s;
static int f(int i, int j){
if(i == j) return 0;
if(isPalindrom(s.substring(i, j))) return 0;
String key = i + " " + j;
if(memo.containsKey(key)) return memo.get(key);
int ans = 999999;
for(int k = i; k < j; k++){
ans = Math.min(ans, f(i, k) + f(k + 1, j) + 1);
}
memo.put(key, ans);
return ans;
}
static boolean isPalindrom(String s){
return s.equals(new StringBuilder(s).reverse().toString());
}
public static void main(String[] args) {
s = "aaka";
System.out.println(f(0, s.length()));
}
}

Maximum Sum SubArray

I am trying to find the contiguous subarray within an array which has the largest sum. So, for the array
{5, 15, -30, 10, -5, 40, 10}
the maximum sum possible using those numbers contiguously would be 55, or (10 + (-5) + 40 + 10) = 55. The program below outputs the maximum sum of 55, however, the problem I am trying to figure out is how to print the sequence that produces this 55. In other words, how can I print out the 10, -5, 40, and 10?
public static void main(String[] args) {
int[] arr = {5, 15, -30, 10, -5, 40, 10};
System.out.println(maxSubsequenceSum(arr));
}
public static int maxSubsequenceSum(int[] X) {
int max = X[0];
int sum = X[0];
for (int i = 1; i < X.length; i++) {
sum = Math.max(X[i], sum + X[i]);
max = Math.max(max, sum);
}
return max;
}
I was thinking of creating an ArrayList to store the sum values at every index of i, so the ArrayList would look like (5, 20, -10, 10, 5, 45, 55). And then I was planning on clearing the ArrayList from index 0 to the first negative number in the list, however, this only solves the problem for this specific example, but if I change the original array of numbers, this solution won't work.
You can replace Math.Max functions by if statements and update start and end index of the best subarray. Pascal version:
if X[i] > sum + X[i] then begin
sum := X[i];
start := i;
end
else
sum := sum + X[i];
if max < sum then begin
max := sum;
finish := i;
end;
You can track the starting and ending indexes of the current best subarray in your loop. Instead of using max() to compute sumand max, just do the following :
int sum_start = 0, sum_end = 0, start = 0, end = 0;
// In the for loop
if (X[i] > sum + X[i]) {
sum = X[i];
sum_start = i;
sum_end = i;
} else {
++sum_end;
}
if (sum > max) {
start = sum_start;
end = sum_end;
max = sum;
}
there is an o(n) solution, a single for loop through the array and reset your sub-sequence whenever your current total is below 0.
{5, 15, -30, 10, -5, 40, 10}
5 + 15 = 20
20 - 30 = -10 (reset sub-sequence)
10 -5 +40 +10 = 55
end. 55 is max sub-sequence
edit: to get subsequence...
whenever you change max, update your subsequence
current left index changes only when u reset
current right index changes every iteration
new max -> save current left and right index...
It can be done by capturing the start and end while identifying maximum sub-array as follows:
Code
package recursion;
import java.util.Arrays;
public class MaximumSubArray {
private static SubArray maxSubArray(int[] values, int low, int high) {
if (low == high) {
// base condition
return new SubArray(low, high, values[low]);
} else {
int mid = (int) (low + high) / 2;
// Check left side
SubArray leftSubArray = maxSubArray(values, low, mid);
// Check right side
SubArray rightSubArray = maxSubArray(values, mid + 1, high);
// Check from middle
SubArray crossSubArray = maxCrossSubArray(values, low, mid, high);
// Compare left, right and middle arrays to find maximum sub-array
if (leftSubArray.getSum() >= rightSubArray.getSum()
&& leftSubArray.getSum() >= crossSubArray.getSum()) {
return leftSubArray;
} else if (rightSubArray.getSum() >= leftSubArray.getSum()
&& rightSubArray.getSum() >= crossSubArray.getSum()) {
return rightSubArray;
} else {
return crossSubArray;
}
}
}
private static SubArray maxCrossSubArray(int[] values, int low, int mid,
int high) {
int sum = 0;
int maxLeft = low;
int maxRight = high;
int leftSum = Integer.MIN_VALUE;
for (int i = mid; i >= low; i--) {
sum = sum + values[i];
if (sum > leftSum) {
leftSum = sum;
maxLeft = i;
}
}
sum = 0;
int rightSum = Integer.MIN_VALUE;
for (int j = mid + 1; j <= high; j++) {
sum = sum + values[j];
if (sum > rightSum) {
rightSum = sum;
maxRight = j;
}
}
SubArray max = new SubArray(maxLeft, maxRight, (leftSum + rightSum));
return max;
}
static class SubArray {
private int start;
private int end;
private int sum;
public SubArray(int start, int end, int sum) {
super();
this.start = start;
this.end = end;
this.sum = sum;
}
public int getStart() { return start; }
public void setStart(int start) { this.start = start; }
public int getEnd() { return end; }
public void setEnd(int end) { this.end = end; }
public int getSum() { return sum; }
public void setSum(int sum) { this.sum = sum; }
#Override
public String toString() {
return "SubArray [start=" + start + ", end=" + end + ", sum=" + sum + "]";
}
}
public static final void main(String[] args) {
int[] values = { 5, 15, -30, 10, -5, 40, 10 };
System.out.println("Maximum sub-array for array"
+ Arrays.toString(values) + ": " + maxSubArray(values, 0, 6));
}
}
Output
Maximum sub-array for array[5, 15, -30, 10, -5, 40, 10]: SubArray [start=3, end=6, sum=55]
Solution can be downloaded from https://github.com/gosaliajigar/Programs/blob/master/src/recursion/MaximumSubArray.java
Two subarray are
[1, 2, 3]
and [4, 9] excluding the negative number
The max sub array here is [ 4, 5]
so the output is 9
Here is the code
public class MaxSubArray{
static void sumM(int a[], int n){
int s1 = Integer.MAX_VALUE;
int k = Integer.MAX_VALUE;
int sum = 0;
int s2 = 0;
for(int i=0;i<n;i++){
if(a[i]<s1){
if(a[i]<0){
k = Math.min(a[i],s1);
}
}
if(a[i]>k){
sum+=a[i];
}
if(a[i]<k){
if(a[i]<0){
continue;
}
s2+=a[i];
}
}
if(sum>s2){
System.out.println(sum);
}
else{
System.out.println(s2);
}
}
public static void main(String[] args){
int a[] = {1,2,3,-7,4,5};
int n = a.length;
sumM(a,n);
}
}
public static int kadane(int[] A) {
int maxSoFar = 0;
int maxEndingHere = 0;
// traverse the given array
for (int i: A) {
// update the maximum sum of subarray "ending" at index `i` (by adding the
// current element to maximum sum ending at previous index `i-1`)
maxEndingHere = maxEndingHere + i;
// if the maximum sum is negative, set it to 0 (which represents
// an empty subarray)
maxEndingHere = Integer.max(maxEndingHere, 0);
// update the result if the current subarray sum is found to be greater
maxSoFar = Integer.max(maxSoFar, maxEndingHere);
}
return maxSoFar;
}
var maxSequence = function(arr){
// ...
if (arr.every((ele) => ele >= 0)) {
return arr.reduce((sum, ele) => sum + ele, 0);
} else if (arr.every((ele) => ele < 0)) {
return 0;
//for me the maximum would be the biggest negative number
//arr.reduce((max, elm) => (max > elm ? max : elm))
} else if (arr === [0]) {
return 0;
} else {
let maxSum = [];
let currentSum = 0;
for (let i = 0; i < arr.length; i++) {
currentSum = Math.max(arr[i], currentSum + arr[i]);
maxSum.push(currentSum);
}
return maxSum.reduce((max, elm) => (max > elm ? max : elm));
}
}
you need to sum all possible sub array. to do that, you can do this code
public static int maxSubsequenceSum(int[] X) {
int max = 0;
boolean max_init = false;
int max_from=0;
int max_to=0; // this is not included
for (int i = 0; i < X.length; i++) {
for (int j = i + 1; j < X.length + 1; j++) {
int total = 0;
for (int k = i; k < j; k++) {
total += X[k];
}
if (total > max || !max_init){
max = total;
max_init = true;
max_from = i;
max_to = j;
}
}
}
for (int i=max_from;i<max_to;i++)
System.out.print(X[i]+",");
System.out.println();
return max;
}

Categories

Resources