StackOverFlow occuring in divide and conquer problem : maximum subArray - java

I was trying to resolve the maximum subArray sum problem with the divide and conquer approach but a runTime error (StackOverFlow) occured and I have no idea how to handle it, I think it's occuring just because of my recursive calls. Here is my approach (the error occured at the first recursive line):
class Solution {
public int maxSubArray(int[] nums){
int length = nums.length;
int middle = length / 2;
if(length == 1) {
return nums[0];
}
int[] starting = Arrays.copyOfRange(nums, 0, middle+1);
int[] ending = Arrays.copyOfRange(nums, middle +1, length);
int left = maxSubArray(starting);
int right = maxSubArray(ending);
int crossing = computeCrossingSum(starting,ending);
int result = Math.max(left,right);
int finalResult = Math.max(result,crossing);
return finalResult;
}
public int computeCrossingSum (int[] left, int[]right){
int leftS =Integer.MIN_VALUE;
int rightS =Integer.MIN_VALUE;
int leftIndex;
int rightIndex;
int sumS = 0;
for(int i = left.length -1 ; i>=0 ; i--) {
sumS += left[i];
if (sumS > leftS) {
leftS = sumS;
leftIndex = i;
}
}
int sumA = 0;
for(int i = 0 ; i< right.length ; i++){
sumA+=right[i];
if (sumA > rightS){
rightS = sumA;
leftIndex = i;
}
}
int crossingSum = leftS+rightS;
return crossingSum;
}
}

The middle + 1 in the recursive call never allow the array size to be 1, so the stop condition is never met. Remove the + 1
int[] starting = Arrays.copyOfRange(nums, 0, middle);
int[] ending = Arrays.copyOfRange(nums, middle, length);

Related

Need help in figuring out bug in Word Wrap problem DP solution

The problem statement is given here : https://practice.geeksforgeeks.org/problems/word-wrap1646/1#
This it the solution I came up with.
class Solution
{
public int solveWordWrap (int[] nums, int k)
{
return solveWordWrap(0,nums,k);
}
private int solveWordWrap(int startIndx, int[] nums, int k){
if(startIndx >= nums.length-1)
return 0;
int min = Integer.MAX_VALUE;
int charCount = 0;
int words = 0;
for(int i = startIndx; i < nums.length; i++){
charCount = charCount + nums[i];
words++;
if(charCount+words-1 <= k)
min = Math.min( (int)Math.pow(k - (charCount+ words-1),2) + solveWordWrap(i+1,nums,k),min);
else
break;
}
return min;
}
}
For the input
nums = {10,6,5,3,1,10,8,2}
k = 12
The correct solution is 45, but my code is outputting 46.
I am not able to find the error.

Mergesort not sorting correctly

I tried to implement merge sort in Java using the code below. The mergeSort() method is supposed to be a recursive method that repeatedly divides the array into smaller sections, while the merge() method takes 2 sections of the array that has already been sorted and merges them into a single sorted section.
Here's the code:
class MergeSort{
public static void mergeSort(int[] array){
mergeSort(array, 0, array.length-1);
}
public static void mergeSort(int[] array, int start, int end){
int mid = (start + end)/2;
if (end > start) {
mergeSort(array, start, mid);
mergeSort(array, mid + 1, end);
merge(array, start, end, mid + 1);
}
}
public static void merge(int[] array, int start, int end, int mid){
int length = end - start + 1,length1 = mid- start, length2 = end - mid + 1, index1 = start, index2 = mid, sortedindex = 0;
boolean cont = true;
int[] sortedArray = new int[length];
while (cont){
if (array[index1] > array[index2]){
sortedArray[sortedindex] = array[index2];
index2++;
} else{
sortedArray[sortedindex] = array[index1];
index1++;
}
sortedindex++;
//reached the end of one array, dump the rest of the remaining array in the sorted array
if (index1 >= length1){
for (index2 = index2; index2 < length2; index2++){
sortedArray[sortedindex] = array[index2];
sortedindex++;
}
cont = false;
} else if (index2 >= length2){
for (index1 =index1; index1 < length1; index1++){
sortedArray[sortedindex] = array[index1];
sortedindex++;
}
cont = false;
}
}
//copy the sorted array into the main array
for (int i = 0; i <= length - 1; i++){
array[start+i] = sortedArray[i];
}
}
}
public class Main {
public static void main(String[] args) {
// write your code here
Scanner scanner = new Scanner(System.in);
scanner.useDelimiter("\n");
Random random = new Random();
int length = scanner.nextInt();
int[] array = new int[length];
for (int i = 0; i < length;i++){
array[i] = random.nextInt(5000);
//System.out.println(array[i]);
}
MergeSort.mergeSort(array);
for (int i: array){
System.out.println(i);
}
}
}
The main class then generates an array with a user-defined length, populates it with random integers, and passes it to mergeSort().
Unfortunately the program outputs an array where the first few elements are sorted correctly, but the rest are zeros. e.g. given a randomly generated array {3291, 2879, 3078, 3609, 3534, 3922, 2793, 1098, 472, 1800}, the program outputs {472, 2879, 3291, 0, 0, 0, 0, 0, 0, 0}, with the number of correctly sorted elements in the output differing from run to run.
I can't seem to figure out what's wrong with my code. Any help would be greatly appreciated :)
while loop should close earlier.
public static void merge1(int[] array, int start, int end, int mid) {
int length = end - start + 1;
int[] sortedArray = new int[length];
int index1 = start;
int index2 = mid + 1;
int sortedindex = 0;
while (index1 <= mid && index2 <= end) {
if (array[index1] < array[index2]) {
sortedArray[sortedindex++] = array[index1++];
} else {
sortedArray[sortedindex++] = array[index2++];
}
}
// reached the end of one array, dump the rest of the remaining array in the
// sorted array
while (index1 <= mid) {
sortedArray[sortedindex++] = array[index1++];
}
while (index2 <= end) {
sortedArray[sortedindex++] = array[index2++];
}
// copy the sorted array into the main array
for (int i = 0; i <= length - 1; i++) {
array[start + i] = sortedArray[i];
}
}

Find the max value of the same length nails after hammered

I'm trying to solve this problem:
Given an array of positive integers, and an integer Y, you are allowed to replace at most Y array-elements with lesser values. Your goal is for the array to end up with as large a subset of identical values as possible. Return the size of this largest subset.
The array is originally sorted in increasing order, but you do not need to preserve that property.
So, for example, if the array is [10,20,20,30,30,30,40,40,40] and Y = 3, the result should be 6, because you can get six 30s by replacing the three 40s with 30s. If the array is [20,20,20,40,50,50,50,50] and Y = 2, the result should be 5, because you can get five 20s by replacing two of the 50s with 20s.
Below is my solution with O(nlogn) time complexity. (is that right?) I wonder if I can further optimize this solution?
Thanks in advance.
public class Nails {
public static int Solutions(int[] A, int Y) {
int N = A.length;
TreeMap < Integer, Integer > nailMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < N; i++) {
if (!nailMap.containsKey(A[i])) {
nailMap.put(A[i], 1);
} else {
nailMap.put(A[i], nailMap.get(A[i]) + 1);
}
}
List < Integer > nums = nailMap.values().stream().collect(Collectors.toList());
if (nums.size() == 1) {
return nums.get(0);
}
//else
int max = nums.get(0);
int longer = 0;
for (int j = 0; j < nums.size(); j++) {
int count = 0;
if (Y < longer) {
count = Y + nums.get(j);
} else {
count = longer + nums.get(j);
}
if (max < count) {
max = count;
}
longer += nums.get(j);
}
return max;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String[] input = scanner.nextLine().replaceAll("\\[|\\]", "").split(",");
System.out.println(Arrays.toString(input));
int[] A = new int[input.length - 1];
int Y = Integer.parseInt(input[input.length - 1]);
for (int i = 0; i < input.length; i++) {
if (i < input.length - 1) {
A[i] = Integer.parseInt(input[i]);
} else {
break;
}
}
int result = Solutions(A, Y);
System.out.println(result);
}
}
}
A C++ implementation would like the following where A is the sorted pin size array and K is the number of times the pins can be hammered.
{1,1,3,3,4,4,4,5,5}, K=2 should give 5 as the answer
{1,1,3,3,4,4,4,5,5,6,6,6,6,6,6}, K=2 should give 6 as the answer
int maxCount(vector<int>& A, int K) {
int n = A.size();
int best = 0;
int count = 1;
for (int i = 0; i < n-K-1; i++) {
if (A[i] == A[i + 1])
count = count + 1;
else
count = 1;
if (count > best)
best = count;
}
int result = max(best+K, min(K+1, n));
return result;
}
Since the array is sorted to begin with, a reasonably straightforward O(n) solution is, for each distinct value, to count how many elements have that value (by iteration) and how many elements have a greater value (by subtraction).
public static int doIt(final int[] array, final int y) {
int best = 0;
int start = 0;
while (start < array.length) {
int end = start;
while (end < array.length && array[end] == array[start]) {
++end;
}
// array[start .. (end-1)] is now the subarray consisting of a
// single value repeated (end-start) times.
best = Math.max(best, end - start + Math.min(y, array.length - end));
start = end; // skip to the next distinct value
}
assert best >= Math.min(y + 1, array.length); // sanity-check
return best;
}
First, iterate through all the nails and create a hash H that stores the number of nails for each size. For [1,2,2,3,3,3,4,4,4], H should be:
size count
1 : 1
2 : 2
3 : 3
4 : 3
Now create an little algorithm to evaluate the maximum sum for each size S, given Y:
BestForSize(S, Y){
total = H[S]
while(Y > 0){
S++
if(Y >= H[S] and S < biggestNailSize){
total += H[S]
Y -= H[S]
}
else{
total += Y
Y = 0
}
}
return total;
}
Your answer should be max(BestForSize(0, Y), BestForSize(1, Y), ..., BestForSize(maxSizeOfNail, Y)).
The complexity is O(n²). A tip to optimize is to start from the end. For example, after you have the maximum value of nails in the size 4, how can you use your answer to find the maximum number of size 3?
Here is my java implementation: First I build a reversed map of each integer and its occurence for example {1,1,1,1,3,3,4,4,5,5} would give {5=2, 4=2, 3=2, 1=4}, then for each integer I calculate the max occurence that we can get of it regarding the K and the occurences of the highest integers in the array.
public static int ourFunction(final int[] A, final int K) {
int length = A.length;
int a = 0;
int result = 0;
int b = 0;
int previousValue = 0;
TreeMap < Integer, Integer > ourMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < length; i++) {
if (!ourMap.containsKey(A[i])) {
ourMap.put(A[i], 1);
} else {
ourMap.put(A[i], ourMap.get(A[i]) + 1);
}
}
for (Map.Entry<Integer, Integer> entry : ourMap.entrySet()) {
if( a == 0) {
a++;
result = entry.getValue();
previousValue = entry.getValue();
} else {
if( K < previousValue)
b = K;
else
b = previousValue;
if ( b + entry.getValue() > result )
result = b + entry.getValue();
previousValue += entry.getValue();
}
}
return result;
}
Since the array is sorted, we can have an O(n) solution by iterating and checking if current element is equals to previous element and keeping track of the max length.
static int findMax(int []a,int y) {
int n = a.length,current = 1,max = 0,diff = 0;
for(int i = 1; i< n; i++) {
if(a[i] == a[i-1]) {
current++;
diff = Math.min(y, n-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
given int array is not sorted than you should sort
public static int findMax(int []A,int K) {
int current = 1,max = 0,diff = 0;
List<Integer> sorted=Arrays.stream(A).sorted().boxed().collect(Collectors.toList());
for(int i = 1; i< sorted.size(); i++) {
if(sorted.get(i).equals(sorted.get(i-1))) {
current++;
diff = Math.min(K, sorted.size()-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
public static void main(String args[]) {
List<Integer> A = Arrays.asList(3,1,5,3,4,4,3,3,5,5,5,1);
int[] Al = A.stream().mapToInt(Integer::intValue).toArray();
int result=findMax(Al, 5);
System.out.println(result);
}

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;
}

splitting array using recursion java

I am trying to spit an int array and add up the elements but im getting errors. Here is my code. I can't figure it out.
int arraySize = 10;
int[] numsToSum = new int[arraySize];
for (int i = 0; i < arraySize; i++)
{
numsToSum[i] = i * 3;
System.out.println(numsToSum[i]);
}
int sum3 = sumArray3(numsToSum, 0, arraySize - 1);
System.out.println(sum3);
public static int sumArray3(int [] array, int start, int end)
{
int results = 0;
int mid = (start + end)/2;
if(array.length > 0)
{
results += sumArray3(array, start + 1, mid) + sumArray3(array, mid +1, end);
}
return results;
You don't have a recursion termination condition, in this case i'd assume you want to check if the start and end counters for the array are the same. Check the code below.
class StackOv {
public static void main(String[] args) {
int arraySize = 10;
int[] numsToSum = new int[arraySize];
for (int i = 0; i < arraySize; i++)
{
numsToSum[i] = i * 3;
System.out.println(numsToSum[i]);
}
int sum3 = sumArray3(numsToSum, 0, arraySize - 1);
System.out.println(sum3);
}
public static int sumArray3(int [] array, int start, int end)
{
int results = 0;
if(start == end)
return array[start];
int mid = (start + end)/2;
if(array.length > 0) {
results += sumArray3(array, start, mid) + sumArray3(array, mid +1, end);
}
return results;
}
}
I finally figured it out. Thanks for your help. I didn't have a base like you said.
public static int sumArray3(int [] array, int start, int end)
{
int results = 0;
int mid = (start + end)/2;
if(start < end)
{
results += sumArray3(array, start, mid) + sumArray3(array, mid +1, end);
}
else
results = array[start];
return results;
}
It looks like you don't have a "base-case", where you return a solid value. Your function as-is will always return 0.
At a guess, I would say you should start by changing it so that you check whether start+1 <= end and if so, returning your current value; if not returning the value at that index, with an else:
else {
results = array[start];
}

Categories

Resources