Average of a sequence of integers using divide and conquer - java

Given a sequence of integers, how can I find the average of it using a divide and conquer approach? I have to write a method "double avg(int[] a, int l, int r)" that finds the average in the array A, spanning from 'l' to 'r' as homework, but I get a StackOverflowError on the first recursive call - not in the second, though! - of my code, and I can't seem to understand why. Also, I'm pretty sure it doesn't give me a true average, but I found no way to check the average of a sequence using the divide and conquer. Here is my code:
public class Average {
public static void main(String[] args) {
int[] A = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
int l = 0;
int r = A.length-1;
System.out.println("Average of the array: "+averageCheck(A, l, r));
}
public static double averageCheck(int[] A, int l, int r) {
if (l==r) {
return A[l];
}
// Base Case: if there's just a single element it is the average of the array itself
int mid = (l+r)/2;
double avLeft = 0;
double avRight = 0;
avLeft = A[l]/r + averageCheck(A, l, mid);
avRight = A[mid+1]/r + averageCheck(A, mid+2, r);
double average = ( (avLeft*mid) + (avRight * (r-mid) ) ) /r;
return average;
}
}

Your recursivity does not end when r == l + 1. In this case, mid == l and in the second recursive call, mid+2 will be greater than r. Add this at the beginning of the function:
if(l > r)
return 0;
Example, imagine l == 5 and r == 6, then mid will have the value 5. The second call will be averageCheck(A, 7, 6) as mid+2 is 7. In this call, the condition l == r will be false. Continue in the same logic and you will find that the recursivity will not end.
I think also that it would be better if you calculate the sum recursively and divide by the length at the end.
I suggest this solution:
public class Average {
public static void main(String[] args) {
int[] A = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20};
System.out.println("Average of the array: "+average(A));
}
public static double average (int[] A) {
return averageCheck(A, 0, A.length - 1) / A.length;
}
public static double averageCheck(int[] A, int l, int r) {
if (l > r)
return 0;
if (l==r) {
return A[l];
}
// Base Case: if there's just a single element it is the average of the array itself
int mid = (l+r)/2;
double avLeft = 0;
double avRight = 0;
avLeft = averageCheck(A, l, mid);
avRight = averageCheck(A, mid+1, r);
double average = avLeft + avRight;
return average;
}
}

Related

Why does this QuickSort code fail using Hoare's partition?

class QuickSort {
public static void main(String[] args) {
int arr[] = { 8, 3, 5, 1, 34, 6, 35, 5, 23, 2, 7 };
int n = arr.length;
for (int x : arr)
System.out.print(x + " ");
System.out.println();
qSort(arr, 0, n - 1);
for (int x : arr)
System.out.print(x + " ");
}
static int partition(int arr[], int l, int h) {
int pivot = arr[h];
int i = l - 1, j = h + 1;
while (true) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
swap(i,j,arr);
}
}
static void qSort(int arr[], int l, int h) {
if (l < h) {
int p = partition(arr, l, h);
qSort(arr, l, p);
qSort(arr, p + 1, h);
}
}}
It works when I choose the pivot as arr[l] , however gives stackoverflow error because if recursion when pivot is chosen as arr[h].
Does the choice of pivot matter? And if at all it matters, could you please tell why?
Hoare partition scheme will not work if arr[h] is chosen as the pivot. It will work for any other element of arr[l] to arr[h-1]. The failure occurs when the size is reduced to 2 elements, h = l+1, and a[l] < a[h]. The loop exits with i == h and j == h, and returns h. Then it calls itself again, with the same values for l and h (h == l+1), resulting in infinite recursion stopped only by a stack overflow exception.
Typcially for Hoare partition scheme arr[(l+h)/2] is chosen as the pivot. This relies on the divide by 2 to round down to l when h = l+1.

Reduce the array to 0 in minimum moves with given constraints

You are given a city which lies on the x-axis. It has n buildings. The first building lies in x = 1 and has height h1, the second building lies on x = 2 and has height h2 and so on. You are a gigantic monster with a sword who wants to destroy the city. You are also a computer scientist at heart so you efficiency is the key, hence you want to destroy the city using minimum number of moves.
You can make one of the two moves :
1. Make a horizontal cut from x = L to x = R, cutting down the heights of the buildings from x = L to X = R by 1.
2. make a vertical cut at x = P, completely destroying the building at x = P thereby making its height zero.**
Note that : for the 1st type of move, every city in the range from L to R must have at least 1 height remaining, i.e. you cannot strike through an empty space.
Print the minimum number of moves needed to destroy the city.
Input
First line contains the number of test cases.
For each test case, the first line contains the number of buildings n.
Second line contains n integers denoting the heights of the building
Output
For every test case, print the minimum number of moves to destroy the city on a new line.
Notes
1 ≤ n ≤ 1000
0 ≤ hi ≤ 1000
Sample Input 0
2
5
2 2 2 3 3
5
10 2 10 2 10
Sample Output 0
3
5
I cannot figure out the approach to the question.
My code does not work for the following input:
1 1 1 2 4 5 7 7 8 9**
In my code i reduce the min value from all elements. Then find out the subarray between zeros and then compare the length of subarray(j-i) with the minimum value. if the length is less, then then we need to follow move 2, else move 1.
My code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.Scanner;
public class Main {
static int findmin(int arr[], int i, int j) {
int min = Integer.MAX_VALUE;
for (int k = i; k < j; k++) {
if (min > arr[k]) {
min = arr[k];
}
}
return min;
}
static void subtractmin(int arr[], int i, int j, int min) {
//if both the length of subarray and min are equal, we destroy separately
if (j - i <= min) {
for (int k = i; k < j; k++) {
// if
arr[k] = 0;
}
} else {
//subtract all
for (int k = i; k < j; k++)
// if
{
arr[k] -= min;
}
}
}
public static void main(String[] args) {
//int input[] = {10, 2, 10, 2, 10};// 5
//int input[] = {2, 2, 2, 3, 3};// 5
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- != 0) {
int zeros = 0;
int n = sc.nextInt();
int input[] = new int[n];
int min = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
input[i] = sc.nextInt();
if (min > input[i]) {
min = input[i];
}
if (input[i] == 0) {
zeros++;
}
}
//subtract minimum element from array
int count = 0;
if (zeros == 0) {
count += min;
subtractmin(input, 0, n, min);
} else {
count += min;
subtractmin(input, 0, n, min);
}
//traverse the array and findsubarrays between 0's
//1) if an element is surrounded by 0's it will be destroyed at once separately
// 2) also if length of subarray<min element, they all need to be destroyed separately
// 3) if min<length of subarray they need to be destroyed at once with count+=min
int i = 0, j = 0;
while (true) {
//move i to the first non zero element
for ( i = 0; i < n; i++) {
if (input[i] != 0) {
break;
}
}
//means whole array is 0;
if (i == n) {
System.out.println(Math.min(count, n - zeros));
break;
}
///start with the first non zero element and fin
for (j = i; j <= n; j++) {
if ( j == n || input[j] == 0) {
// take out min element
int minEle = findmin(input, i, j) ;
//if min lement is greater than subarray size, destroy separately
count += Math.min(minEle, j - i);
//System.out.println("count="+count+"min element="+minEle);
// subtract minimum element
subtractmin(input, i, j, minEle);
}
//if last elemnt is not zero
}
}
}
}
}
A possible hint here is that reducing a building to zero separates sections, which implies divide and conquer.
Let f(A, l, r) represent the optimal number of moves for the section of A indexed at [l, r]. Then:
f(A, l, r):
min(
# Reduce the whole section
# without separating it, using
# move 1, the horizontal cuts.
max(A[l..r]),
# Divide and conquer
1 + f(A, l, k-1) + f(A, k+1, r)
)
for all l ≤ k ≤ r
Except we don't need to try all ks, just one that points to max(A). Not removing max(A) implies we would need to either perform max(A) moves or we would have to remove it later.
JavaScript code:
function findMax(A, l, r){
let idx = l;
for (let i=l; i<=r; i++)
if (A[i] > A[idx])
idx = i;
return idx;
}
function f(A, l=0, r=A.length-1, memo={}){
if (l > r)
return 0;
if (l == r)
return 1;
const key = String([l, r]);
if (memo.hasOwnProperty(key))
return memo[key];
const k = findMax(A, l, r);
const best = Math.min(A[k], 1 + f(A, l, k-1, memo) + f(A, k+1, r, memo));
return memo[key] = best;
}
var As = [
[2, 2, 2, 3, 3],
[10, 2, 10, 2, 10],
[1, 1, 1, 2, 4, 5, 7, 7, 8, 9]
];
for (let A of As)
console.log(f(A));
The probleme you have is not in the code, but in the algorithm. If the size of a segment is small enough, effectivelly you have to perform move 2. However, this condition is not indispensable.
In practice, a simple recursive approach can solve this problem. In a given segment [k, l], after having substracted the min value, you simply have to perform:
n_moves = min (n, vmin + min_moves(x, k, l));
In the following, one function detects positions of the zeros and sum the moves corresponding to each segment
and another function is called for each segment with no zero inside.
The following code is in C++, but it is rather simple and should be easily translated to another language.
Output:
1 2 7 : 3
2 2 2 3 3 : 3
10 2 10 2 10 : 5
1 1 1 2 4 5 7 7 8 9 : 8
This code is provided for completeness. What is important is the algorithm itself.
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> get_zeros (const std::vector<int> &x, int k, int l) {
std::vector<int> zeros;
for (int i = k; i <= l; ++i) {
if (x[i] == 0) zeros.push_back(i);
}
return zeros;
}
int min_moves (std::vector<int> &x, int k, int l);
// This function is called after detection the position of the zeros -> no zero inside
int min_moves_no_zero (std::vector<int> &x, int k, int l) {
int n = l-k+1;
if (n == 0) return 0;
if (n == 1) return 1;
int vmin = 10000;
for (int i = k; i <= l; ++i) {
if (x[i] < vmin) vmin = x[i];
}
for (int i = k; i <= l; ++i) {
x[i] -= vmin;
}
int nm = std::min (n, vmin + min_moves(x, k, l));
return nm;
}
// This function detects positions of the zeros and sum the moves corresponding to each segment
int min_moves (std::vector<int> &x, int k, int l) {
auto zeros = get_zeros (x, k, l);
if (zeros.size() == 0) return min_moves_no_zero (x, k, l);
int start = k;
int total = 0;
for (int z = 0; z < zeros.size(); ++z) {
int end = zeros[z] - 1;
if (start != zeros[z]) {
total += min_moves_no_zero (x, start, end);
}
start = end + 2;
}
if (start <= l) {
total += min_moves_no_zero (x, start, l);
}
return total;
}
void print (const std::vector<int> &x) {
for (auto k: x) {
std::cout << k << " ";
}
}
int main() {
std::vector<std::vector<int>> input {
{1, 2, 7},
{2, 2, 2, 3, 3},
{10, 2, 10, 2, 10},
{1, 1, 1, 2, 4, 5, 7, 7, 8, 9}
};
for (auto& arr: input) {
auto save = arr;
int moves = min_moves (arr, 0, arr.size()-1);
print (save);
std::cout << " : " << moves << "\n";
}
}

Java divide and conquer algorithm stack overflow error

I am trying to find out the index of the smallest number in an int array using divide and conquer and I have this stack overflow error:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.StrictMath.floor(Unknown Source)
at java.lang.Math.floor(Unknown Source)
This is my divide and conquer method:
private static int dC(int[] a, int f, int l) {
if(f == 1)
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Here is what I put in my main method:
int[] a = {35,30,40,50};
System.out.println(dC(a, 0, 3));
You have a problem with your stoping "rule"
private static int dC(int[] a, int f, int l) {
if(l == f) // <-- This mean you have one item, so you want to return it.
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Also, I would try to do the calculation only once, so something like this (also what Joop Eggen said about Integers arithmetics):
private static int dC(int[] a, int f, int l) {
if(l == f)
return f;
int m = (f+l) / 2;
int left = dC(a, f, m);
int right = dC(a, m+1, l);
if(a[left] > a[right])
return left;
else
return right;
}
This is just the classical binary search problem. From what I can glean by looking at your code, you seem to be getting bogged down in the logic used to make each recursive call to the left and right subarrays of the current array. The logic I used below is to take everything from the start to (start+end)/2 for the left recursion, and everything from ((start+end)/2) + 1 to end for the right recursion. This guarantees that there would never be any overlap.
The base case occurs when the algorithm finds itself sitting on a single entry in the array. In this case, we just return that value, and we do not recurse further.
private static int dC(int[] a, int start, int end) {
if (start == end) return a[start];
int left = dC(a, start, (start+end)/2);
int right = dC(a, ((start+end)/2) + 1, end);
return left < right ? left : right;
}
public static void main(String args[])
{
int[] a = {10, 3, 74, 0, 99, 9, 13};
System.out.println(dC(a, 0, 6)); // prints 0
}
Demo
Note: I have no idea what role Math.floor would be playing here, since you're using arrays of integer numbers, not doubles or floats. I removed this, because I saw no need for it.
It's a typical problem locating the index to the min/max, you can try it as:
public static void main(String... args) {
int[] arr = generateArrays(100, 1000, 0, 10000, true);
int minIndex = findMinIndex(arr, 1, arr.length - 1);
int theMin = arr[minIndex];
Arrays.sort(arr);
System.out.println(String.format("The min located correctly: %s", arr[0] == theMin));
}
private static int findMinIndex(int[] a, int l, int r) {
if (r - l < 1) return l;
int mid = l + (r - l) / 2;
int lIndex = findMinIndex(a, l + 1, mid);
int rIndex = findMinIndex(a, mid + 1, r);
int theMinIndex = l;
if (a[lIndex] < a[theMinIndex]) theMinIndex = lIndex;
if (a[rIndex] < a[theMinIndex]) theMinIndex = rIndex;
return theMinIndex;
}
And the helper to generate a random array.
public static int[] generateArrays(int minSize, int maxSize, int low, int high, boolean isUnique) {
Random random = new Random(System.currentTimeMillis());
int N = random.nextInt(maxSize - minSize + 1) + minSize;
if (isUnique) {
Set<Integer> intSet = new HashSet<>();
while (intSet.size() < N) {
intSet.add(random.nextInt(high - low) + low);
}
return intSet.stream().mapToInt(Integer::intValue).toArray();
} else {
int[] arr = new int[N];
for (int i = 0; i < N; ++i) {
arr[i] = random.nextInt(high - low) + low;
}
return arr;
}
}

Recursive max stack overflow error

I am trying to write a 3 input recursive program for max and min for a data structures class. I am getting a stack overflow error. I cannot tell if I am going off the end of the array, but I shouldn't be as far as my understanding goes. Any help would be appreciated. Here is my code:
class Extrema {
// maxArray()
// returns the largest value in int array A
// p is position zero, r is position length-1
static int maxArray(int[] A, int p, int r) {
int q;
if (p == r) {
return A[p];
} else {
q = (p + r)/2;
return max(maxArray(A, p, q-1), maxArray(A, q+1, r));
}
}
// max()
// returns the largest value of two ints
private static int max(int a, int b) {
return a > b ? a : b;
}
// main()
public static void main(String[] args) {
int[] B = {-1, 2, 6, 3, 9, 2, -3, -2, 11, 5, 7};
System.out.println( "max = " + maxArray(B, 0, B.length-1) ); // output: max = 11
}
}
Either do it non recursive since recursion really does not make any sense here:
static int maxArray(int[] A, int p, int r) {
int max = A[p];
for (int i = p + 1; i <= r; i++) {
if (A[i] > max)
max = A[i];
}
return max;
}
Or if you insist on some kind of recursion use your code existing with just a minor change:
return max(maxArray(A, p, q), maxArray(A, q+1, r));
Note the call to the first maxArray function now gets passed q and not q-1 as end index.
Change this code
if (p == r) {
return A[p];
}
to
if (p >= r) {
return A[p];
}
and note that when you call statement
return max(maxArray(A, p, q-1), maxArray(A, q+1, r));
you lose q element, so call
return max(maxArray(A, p, q), maxArray(A, q+1, r));

A recursive algorithm to find every possible sum given an integer array?

So given an array for example [3, 5, 7, 2] I want to use recursion to give me all the possible combinations of sums, for example: 3, 5, 7, 2, 8(3+5),10(3+7),5(3+5)... 15(3+5+7) etc. I'm not exactly sure how to go about this using java.
You have two choice with each number in the array.
Use the number
Don't use the number
void foo(int[] array, int start, int sum) {
if(array.length == start) return;
int val = sum + array[start];
//print val;
foo(array, start + 1, val); //use the number
foo(array, start + 1, sum); //don't use the number
}
the initial call is foo(a, 0, 0)
An recursive algorithm for this could work as follows:
All the sums for a list equals the union of:
The first number plus the sums of the sublist without the first number
The sums of the sublist without the first number
Eventually your recursive call will hit the stopping condition of an empty list, which has only one sum(zero)
Here's one way of doing it in pseudo code:
getAllPossibleSums(list)
if(list.length == 1)
return list[0];
otherSums = getAllPossibleSums(list[1:end])
return union(
otherSums, list[0] + otherSums);
public static void main(String[] args) {
findAllSums(new int[] {3, 5, 7, 2}, 0, 0);
}
static void findAllSums(int[] arrayOfNumbers, int index, int sum) {
if (index == arrayOfNumbers.length) {
System.out.println(sum);
return;
}
findAllSums(arrayOfNumbers, index + 1, sum + arrayOfNumbers[index]);
findAllSums(arrayOfNumbers, index + 1, sum);
}
You have two branches, one in which you add the current number and another in which you don't.
public static void main(String[] args) {
int [] A = {3, 5, 7, 2};
int summation = recursiveSum(A, 0, A.length-1);
System.out.println(summation);
}
static int recursiveSum(int[] Array, int p, int q) {
int mid = (p+q)/2; //Base case
if (p>q) return 0; //Base case
else if (p==q) return Array[p];
**else
return recursiveSum(Array, p, mid) + recursiveSum(Array, mid + 1, q);**
}
Simplest way ever:
private int noOfSet;
Add below method:
private void checkSum() {
List<Integer> input = new ArrayList<>();
input.add(9);
input.add(8);
input.add(10);
input.add(4);
input.add(5);
input.add(7);
input.add(3);
int targetSum = 15;
checkSumRecursive(input, targetSum, new ArrayList<Integer>());
}
private void checkSumRecursive(List<Integer> remaining, int targetSum, List<Integer> listToSum) {
// Sum up partial
int sum = 0;
for (int x : listToSum) {
sum += x;
}
//Check if sum matched with potential
if (sum == targetSum) {
noOfSet++;
Log.i("Set Count", noOfSet + "");
for (int value : listToSum) {
Log.i("Value", value + "");
}
}
//Check sum passed
if (sum >= targetSum)
return;
//Iterate each input character
for (int i = 0; i < remaining.size(); i++) {
// Build list of remaining items to iterate
List<Integer> newRemaining = new ArrayList<>();
for (int j = i + 1; j < remaining.size(); j++)
newRemaining.add(remaining.get(j));
// Update partial list
List<Integer> newListToSum = new ArrayList<>(listToSum);
int currentItem = remaining.get(i);
newListToSum.add(currentItem);
checkSumRecursive(newRemaining, targetSum, newListToSum);
}
}
Hope this will help you.

Categories

Resources