Restaurant Maximum Profit using Dynamic Programming - java

Its an assignment task,I have spend 2 days to come up with a solution but still having lots of confusion,however here I need to make few points clear. Following is the problem:
Yuckdonald’s is considering opening a series of restaurant along QVH. n possible locations are along a straight line and the distances of these locations from the start of QVH are in miles and in increasing order m1, m2, ...., mn. The constraints are as follows:
1. At each location, Yuckdonald may open one restaurant and expected profit from opening a restaurant at location i is given as pi
2. Any two restaurants should be at least k miles apart, where k is a positive integer
My solution:
public class RestaurantProblem {
int[] Profit;
int[] P;
int[] L;
int k;
public RestaurantProblem(int[] L , int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
}
public int compute(int i){
if(i==0)
return 0;
Profit[i]= P[i]+(L[i]-L[i-1]< k ? 0:compute(i-1));//if condition satisfies then adding previous otherwise zero
if (Profit[i]<compute(i-1)){
Profit[i] = compute(i-1);
}
return Profit[i];
}
public static void main(String args[]){
int[] m = {0,5,10,15,19,25,28,29};
int[] p = {0,10,4,61,21,13,19,15};
int k = 5;
RestaurantProblem rp = new RestaurantProblem(m, p ,k);
rp.compute(m.length-1);
for(int n : rp.Profit)
System.out.println(n);
}
}
This solution giving me 88 however if I exclude (Restaurant at 25 with Profit 13) and include (Restaurant 28 with profit 19) I can have 94 max...
point me if I am wrong or how can I achieve this if its true.

I was able to identify 2 mistakes:
You are not actually using dynamic programming
, you are just storing the results in a data structure, which wouldn't be that bad for performance if the program worked the way you have written it and if you did only 1 recursive call.
However you do at least 2 recursive calls. Therefore the program runs in Ω(2^n) instead of O(n).
Dynamic programming usually works like this (pseudocode):
calculate(input) {
if (value already calculated for input)
return previously calculated value
else
calculate and store value for input and return result
}
You could do this by initializing the array elements to -1 (or 0 if all profits are positive):
Profit = new int[L.length];
Arrays.fill(Profit, -1); // no need to do this, if you are using 0
public int compute(int i) {
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
...
You assume the previous restaurant can only be build at the previous position
Profit[i] = P[i] + (L[i]-L[i-1]< k ? 0 : compute(i-1));
^
Just ignores all positions before i-1
Instead you should use the profit for the last position that is at least k miles away.
Example
k = 3
L 1 2 3 ... 100
P 5 5 5 ... 5
here L[i] - L[i-1] < k is true for all i and therefore the result will just be P[99] = 5 but it should be 34 * 5 = 170.
int[] lastPos;
public RestaurantProblem(int[] L, int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
lastPos = new int[L.length];
Arrays.fill(lastPos, -2);
Arrays.fill(Profit, -1);
}
public int computeLastPos(int i) {
if (i < 0) {
return -1;
}
if (lastPos[i] >= -1) {
return lastPos[i];
}
int max = L[i] - k;
int lastLastPos = computeLastPos(i - 1), temp;
while ((temp = lastLastPos + 1) < i && L[temp] <= max) {
lastLastPos++;
}
return lastPos[i] = lastLastPos;
}
public int compute(int i) {
if (i < 0) {
// no restaurants can be build before pos 0
return 0;
}
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
int profitNoRestaurant = compute(i - 1);
if (P[i] <= 0) {
// no profit can be gained by building this restaurant
return Profit[i] = profitNoRestaurant;
}
return Profit[i] = Math.max(profitNoRestaurant, P[i] + compute(computeLastPos(i)));
}

To my understanding, the prolem can be modelled with a two-dimensional state space, which I don't find in the presented implementation. For each (i,j) in{0,...,n-1}times{0,...,n-1}` let
profit(i,j) := the maximum profit attainable for selecting locations
from {0,...,i} where the farthest location selected is
no further than at position j
(or minus infinity if no such solution exist)
and note that the recurrence relation
profit(i,j) = min{ p[i] + profit(i-1,lastpos(i)),
profit(i-1,j)
}
where lastpos(i) is the location which is farthest from the start, but no closer than k to position i; the first case above corresponds to selection location i into the solution while the second case corresponds to omitting location j in the solution. The overall solution can be obtained by evaluating profit(n-1,n-1); the evaluation can be done either recursively or by filling a two-dimensional array in a bottom-up manner and returning its contents at (n-1,n-1).

Related

binary partition an array using java

I am a beginner(first year uni student) programmer trying to solve this problem which i'm finding somewhat difficult. If you are to answer this question, don't provide me with a complex daunting algorithm that will leave me scratching my head. I'll really appreciate it if you explain it step my step (both logically/conceptually then through code)
The problem is as follows:image
I have tried to attempt it and my code only works for a certain case that i tested.
package com.company;
import java.lang.Math;
public class Main {
public static int[][] binary_partition(int array[], int k){
int x = (int) Math.pow(2,k);
int[][] partition = new int[((array.length/x)*2)][array.length/x];
int divisor = array.length/x;
if ((array.length % 2) != 0){
return partition;
}
if (divisor >= array.length-1){
return partition;
}
if (k==1){
return partition;
}
int p = 0;
for(int i=0;i<((array.length/x)*2);i++)
{
for (int j = 0; j<array.length/x;j++)
{
partition[i][j] = array[p];
p += 1;
}
}
return partition;
}
public static void main(String[] args){
int[] array = {3, 2, 4, 7, 8, 9, 2, 3};
int[][] result = binary_partition(array,2);
for (int[] x : result){
for (int y : x)
{
System.out.print(y + " ");
}
System.out.println();
}
}
}
Your question is unclear, but this solution creates a function that partitions an array with the right length into 2^k sets.
First, an interesting fact: using the bitshift operator << on an integer increases its value by a power of two. So to find out the size of your partition, you could write
int numPartitions = 1 << k; // Equivalent to getting the integer value of 2^k
With this fact, the function becomes
public static int[][] partition(int[] set, int k) {
if (set == null)
return null; // Don't try to partition a null reference
// If k = 0, the partition of the set is just the set
if (k == 0) {
int[][] partition = new int[1][set.length];
// Copy the original set into the partition
System.arraycopy(set, 0, partition[0], 0, set.length);
return partition;
}
int numPartitions = 1 << k; // The number of sets to partition the array into
int numElements = set.length / numPartitions; // The number of elements per partition
/* Check if the set has enough elements to create a partition and make sure
that the partitions are even */
if (numElements == 0 || set.length % numElements != 0)
return null; // Replace with an error/exception of your choice
int[][] partition = new int[numPartitions][numElements];
int index = 0;
for (int r = 0; r < numPartitions; r++) {
for (int c = 0; c < numElements; c++) {
partition[r][c] = set[index++]; // Assign an element to the partition
}
}
return partition;
}
There are a few lines of your code where the intention is not clear. For example, it is not clear why you are validating divisor >= array.length-1. Checking k==1 is also incorrect because k=1 is a valid input to the method. In fact, all your validation checks are not needed. All you need to validate is that array.length is divisible by x.
The main problem that you have seems to be that you mixed up the lengths of the resulting array.
The resulting array should have a length of array.length / x, and each of the subarrays should have a length of x, hence:
int[][] partition = new int[array.length/x][x];
If you also fix your bounds on the for loops, your code should work.
Your nested for loop can be rewritten as a single for loop:
for(int i = 0 ; i < array.length ; i++)
{
int index = i / x;
int subArrayIndex = i % x;
partition[index][subArrayIndex] = array[i];
}
You just need to figure out which indices a an element array[i] belongs by dividing and getting the remainder.

My merge sort code is completely correct, yet no sorting is taking place

I have a public static int Dlist[ ][ ] declared in the class and the below mentioned functions are written.
I saw a similar code (only the basic mergesort code on GeeksforGeeks) where they take k = 1 and their code works completely welll. where as, my does something but the result is not what is expected. i am not able to understand why k=1 working ?
I'd like to know two things.
1) why k = 1 works (https://www.geeksforgeeks.org/java-program-for-merge-sort/)
Shouldn't it be k = 0 and instead of arr[k] it should have been arr[l+k]
2) What is the problem in my code? Why is it not doing anything?
*Also LI is left indes, RI is right index, MI is middle index, ii is for Dlist[ ][ii]
public static void mergeSort(int Dlist[][], int ii, int li, int ri)
{
if(ri > li)
{
int m = (li+ri)/2;
mergeSort(Dlist, ii, li, m);
mergeSort(Dlist, ii, m + 1, ri);
Merge(Dlist, ii, li, m, ri);
}
}
public static void Merge(int Dlist[][], int ii, int li, int m, int ri)
{
int la[][] = new int[m-li+1][2];
int ra[][] = new int[ri-m][2];
int i,j,k;
for(i = 0; i < m-li+1; i++)
{
la[i][0] = Dlist[li+i][0];
la[i][1] = Dlist[li+i][1];
}
for(i = 0; i < ri-m; i++)
{
ra[i][0] = Dlist[m+i+1][0];
ra[i][1] = Dlist[m+i+1][1];
}
i = 0; j = 0; k = 0;
while ((i < m-li+1) && (j < m-ri))
{
if(la[i][ii] < ra[j][ii])
{
Dlist[(li+k)][ii] = la[i][ii];
if(ii == 1)
{
Dlist[(li+k)][0] = la[i][0];
}
i++;
k++;
}
else
{
Dlist[(li+k)][ii] = ra[j][ii];
if(ii == 1)
{
Dlist[(li+k)][0] = ra[j][0];
}
j++;
k++;
}
}
while (i < m-li+1)
{
Dlist[li+k][ii] = la[i][ii];
if(ii == 1)
{
Dlist[li+k][0] = la[i][0];
}
i++;
k++;
}
while (j < m-ri)
{
Dlist[li+k][ii] = ra[j][ii];
if(ii == 1)
{
Dlist[li+k][0] = ra[j][0];
}
j++;
k++;
}
}
The aim of the code is to convert this :-
*The sorting is done with respect to Dlist[ ][1] in descending order.
2 4 5 7 8
4 2 7 9 1
into this :-
7 5 2 4 8
9 7 4 2 1
But the functions don't do anything.
Final Update :-
I was able to make the same code work by copying Dlist[][1] to another array. Then applying those functions on this new copied array and in merge function, while modifying copied array, i made same modifications in Dlist. Don't know why it worked that way. But that worked for me.
It's not k = 1, it's k = l (in upper case K = L).
mergeSort(Dlist, ii, m + 1, mi); should be mergeSort(Dlist, ii, m + 1, ri);
Regardless if ii == 0 or ii == 1, merge should always copy DList[..][0] and DList[..][1].
The code would be simpler if ri was the ending index (last index + 1), eliminating all the +1 in the code. You could change the index names to bgn or bi (instead of li) and end or ei (instead of ri).
Take a look at the wiki example for top down merge sort. It does a one time copy of the original array, into a one time allocated working array, then swaps the array names in the recursive calls so that the direction of merge corresponds to the level of recursion, eliminating the need to create sub-arrays or copy back. It also passes the beginning and ending indexes (as opposed to beginning and last index), and in the initial call beginning index = 0 and ending index = size of array (n).
https://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation

Explanation of Dynamic Programming solution

This is the problem: given a number of bricks n, between 3 and 200, return the number of different staircases that can be built. Each type of staircase should consist of 2 or more steps. No two steps are allowed to be at the same height - each step must be lower than the previous one. All steps must contain at least one brick. A step's height is classified as the total amount of bricks that make up that step.
For example, when N = 3, you have only 1 choice of how to build the staircase, with the first step having a height of 2 and the second step having a height of 1: (# indicates a brick)
#
##
21
When N = 4, you still only have 1 staircase choice:
#
#
##
31
But when N = 5, there are two ways you can build a staircase from the given bricks. The two staircases can have heights (4, 1) or (3, 2), as shown below:
#
#
#
##
41
#
##
##
32
I found a solution online, but I don't quite intuitively understand the dynamic programming solution.
public class Answer {
static int[][] p = new int[201][201];
public static void fillP() {
p[1][1] = 1;
p[2][2] = 1;
for (int w = 3; w < 201 ; w++) {
for (int m = 1; m <= w; m++) {
if (w-m == 0) {
p[w][m] = 1 + p[w][m-1];
} else if (w-m < m) {
p[w][m] = p[w-m][w-m] + p[w][m-1];
} else if (w-m == m) {
p[w][m] = p[m][m-1] + p[w][m-1];
} else if (w-m >m) {
p[w][m] = p[w-m][m-1] + p[w][m-1];
}
}
}
}
public static int answer(int n) {
fillP();
return p[n][n] - 1;
}
}
In particular, how would one come up with the relationships between each successive entry in the array?
This is a very interesting question. First, let's try to understand the recurrence relation:
If we currently built a step of height h and we have b bricks left to use, the number of ways we could complete the staircase from here is equal to the sum of all the ways we can complete the staircase with the next step of height h' and b - h' bricks, for 0 < h' < h.
Once we have that recurrence relation, we can devise a recursive solution; however, at it's current state, the solution runs in exponential time. So, we just need to "cache" our results:
import java.util.Scanner;
public class Stairs {
static int LIMIT = 200;
static int DIRTY = -1;
static int[][] cache = new int[LIMIT + 2][LIMIT + 2];
public static void clearCache() {
for (int i = 0; i <= LIMIT + 1; i++) {
for (int j = 0; j <= LIMIT + 1; j++) {
// mark cache as dirty/garbage values
cache[i][j] = DIRTY;
}
}
}
public static int numberOfStaircases(int level, int bricks, int steps) {
// base cases
if (bricks < 0) return 0;
if (bricks == 0 && steps >= 2) return 1;
// only compute answer if we haven't already
if (cache[level][bricks] == DIRTY) {
int ways = 0;
for (int nextLevel = level - 1; nextLevel > 0; nextLevel--) {
ways += numberOfStaircases(nextLevel, bricks - nextLevel, steps + 1);
}
cache[level][bricks] = ways;
}
return cache[level][bricks];
}
public static int answer(int n) {
clearCache();
return numberOfStaircases(n + 1, n, 0);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
System.out.println(answer(n));
}
}
From the code you provided, it seems as if the author went one more step further and replaced the recursive solution with a purely iterative version. This means that the author made a bottom-up solution rather than a top-down solution.
We could also approach the problem more mathematically:
How many distinct non-trivial integer partitions does n have?
So for n = 6, we have: 5 + 1, 4 + 2, 3 + 2 + 1. So answer(6) = 3. Interestingly enough, Euler proved that the number of distinct integer partitions for a given n is always the same as the number of not necessarily distinct odd integer partitions.
(As a side note, I know where this question comes from. Good luck!)
Good explanation of this problem (The Grandest Staircase Of Them All) is on the page with several different solutions.
https://jtp.io/2016/07/26/dynamic-programming-python.html
For building a staircase, we can consider it as a pyramid to build on top of each step with the amount of bricks that remain with us as we ascend and complete our staircase.
For n bricks we have, we can start with i bricks on top of the first step, which means we have n-i bricks remaining with us for the current step. As we calculate the number of ways for building a multilevel staircase of n bricks, for first step n-i, the number of ways are - to build the staircase with i bricks which can either be multilevel or a single step. We can follow this relative mechanism to get the total number of staircases that are possible from the zeroth step with n bricks.
To avoid calculating the same results for a pyramid of bricks i, we can use an in memory cache which stores results of the possible staircases for n bricks with k as its last step (since the possible staircases will depend on the previous step over which the pyramid will be placed just to avoid double steps or last step becoming smaller than the next one).
package com.dp;
import java.util.HashMap;
import java.util.Map;
public class Staircases {
private static Map<String, Long> cacheNumberStaircasesForNBricks = new HashMap<String, Long>();
public static void main(String[] args) {
int bricks = 1000;
Long start = System.currentTimeMillis();
long numberOfStaircases = getStaircases(bricks, Integer.MAX_VALUE, true);
Long end = System.currentTimeMillis();
System.out.println(numberOfStaircases);
System.out.println("Time taken " + (end - start) + " ms");
}
/*
* For n bricks returns number of staircases can be formed with minimum 2
* stairs and no double steps, with k as the number of bricks in last step
*/
private static long getStaircases(int n, int k, boolean multilevelOnly) {
/*
* if the last step was same as n, you can't get a single step of n bricks as the next step,
* hence the staircase needs to be multilevel
*/
if (n == k) {
multilevelOnly = true;
}
/*
* for n less than 3 ie 1 or 2 there is only one stair case possible if the last step is of greater number of bricks
*/
if (n < 3) {
if (k <= n) {
return 0;
}
return 1;
}
/*
* for n =3, if multilevel is allowed only, then only one combination is
* there ie 2,1.
*/
if (n == 3) {
if (k < n) {
return 0;
}
if (multilevelOnly) {
return 1;
}
}
/*
* refer from the in-memory cache. Don't compute if we have computed for last step (k) and current bricks left (n) to build the rest of the staircase
*/
String cacheKey = n + "-" + k;
if (cacheNumberStaircasesForNBricks.get(cacheKey) != null) {
return cacheNumberStaircasesForNBricks.get(cacheKey);
}
/*
* start with one case which involves a single step of n bricks.
* for multilevel only or last step being smaller(invalid scenario) staircases, put the initial count as zero
*/
long numberOfStaircases = multilevelOnly || k < n ? 0 : 1;
for (int i = 1; n - i > 0; i++) {
// current step must be smaller than the last step
if (n - i < k) {
numberOfStaircases += getStaircases(i, n - i, false);
}
}
cacheNumberStaircasesForNBricks.put(cacheKey, numberOfStaircases);
return numberOfStaircases;
}
}

Finding max and min using divide and conquer approach

I know this is a silly question,but I'm not getting this at all.
In this code taken from http://somnathkayal.blogspot.in/2012/08/finding-maximum-and-minimum-using.html
public int[] maxMin(int[] a,int i,int j,int max,int min) {
int mid,max1,min1;
int result[] = new int[2];
//Small(P)
if (i==j) max = min = a[i];
else if (i==j-1) { // Another case of Small(P)
if (a[i] < a[j]) {
this.max = getMax(this.max,a[j]);
this.min = getMin(this.min,a[i]);
}
else {
this.max = getMax(this.max,a[i]);
this.min = getMin(this.min,a[j]); }
} else {
// if P is not small, divide P into sub-problems.
// Find where to split the set.
mid = (i + j) / 2;
// Solve the sub-problems.
max1 = min1 = a[mid+1];
maxMin( a, i, mid, max, min );
maxMin( a, mid+1, j, max1, min1 );
// Combine the solutions.
if (this.max < max1) this.max = max1;
if (this.min > min1) this.min = min1;
}
result[0] = this.max;
result[1] = this.min;
return result;
}
}
Let's say the array is 8,5,3,7 and we have to find max and min,
Initial values of max and min=arr[0]=8;
First time list will be divided into 8,5
We call MaxMin with max=8 and min=8,since i==j-1,we will get max=8,min=5,
Next time list will be divided into [3,7],
min1=max1=arr[mid+1]=3,
We call MaxMin with max=3 and min=3.Since i is equal to j-1,we will get max=7,min=3,
Next the comparison is performed between max1,max and min1,min ,
Here is my confusion,
The values of max and max1 here is 8 and 7 respectively,but how???
We have not modified max1 anywhere,then how it will have a value 7,
As per my understanding,we had called MaxMin with max=3 and min=3 and then updated max=7 and min=3,but we had not returned these updated values,then how the values of max1 and min1 got updated,
I'm stuck at this,please explain.
Thanks.
It looks like you are updating 2 external values (not in this function) which are this.min and this.max
All you do is splitting in pieces of 1 or 2 elements and then update this.min and this.max, so you could also directly scan the array and check all int value for min/max. This is not really doing divide and conquer.
Here is a solution that really use divide and conquer :
public int[] maxMin(int[] a,int i,int j) {
int localmin,localmax;
int mid,max1,min1,max2,min2;
int[] result = new int[2];
//Small(P) when P is one element
if (i==j) {
localmin = a[i]
localmax = a[i];
}
else {
// if P is not small, divide P into sub-problems.
// where to split the set
mid = (i + j) / 2;
// Solve the sub-problems.
int[] result1 = maxMin( a, i, mid);
int[] result2 = maxMin( a, mid+1, j);
max1 = result1[0];
min1 = result1[1];
max2=result2[0];
min2=result2[1];
// Combine the solutions.
if (max1 < max2) localmax = max2;
else localmax=max1;
if (min1 < min2) localmin = min1;
else localmin=min2;
}
result[0] = localmax;
result[1] = localmin;
return result;
}
Frankly that blogger's code looks like a mess. You should have no confidence in it.
Take is this line early on:
if (i==j) max = min = a[i];
The values passed INTO the function, max and min, aren't ever used in this case, they are just set, and then lost forever. Note also if this line runs, the array result is neither set nor returned. (I would have thought that the compiler would warn that there are code paths that don't return a value.) So that's a bug, but since he never uses the return value anywhere it might be harmless.
The code sometimes acts like it is returning values through max and min (can't be done), while other parts of the code pass back the array result, or set this.max and this.min.
I can't quite decide without running it if the algorithm will ever return the wrong result. It may just happen to work. But its a mess, and if it were written better you could see how it worked with some confidence. I think the author should have written it in a more purely functional style, with no reliance on external variables like this.min and this.max.
Parenthetically, I note that when someone asked a question in the comments he replied to the effect that understanding the algorithm was the main goal. "Implementation [of] this algorithm is very much complex. For you I am updating a program with this." Gee, thanks.
In short, find a different example to study. Lord of dark posted a response as I originally wrote this, and it looks much improved.
Code
import java.util.Random;
public class MinMaxArray {
private static Random R = new Random();
public static void main(String[] args){
System.out.print("\nPress any key to continue.. ");
try{
System.in.read();
}
catch(Exception e){
;
}
int N = R.nextInt(10)+5;
int[] A = new int[N];
for(int i=0; i<N; i++){
int VAL = R.nextInt(200)-100;
A[i] = VAL;
}
Print(A);
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
P = MinMax(A, 0, A.length-1);
System.out.println("\nMin: " + P.MIN);
System.out.println("\nMax: " + P.MAX);
}
private static Pair MinMax(int[] A, int start, int end) {
Pair P = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair P_ = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
Pair F = new Pair(Integer.MIN_VALUE, Integer.MAX_VALUE);
if(start == end){
P.MIN = A[start];
P.MAX = A[start];
return P;
}
else if(start + 1 == end){
if(A[start] > A[end]){
P.MAX = A[start];
P.MIN = A[end];
}
else{
P.MAX = A[end];
P.MIN = A[start];
}
return P;
}
else{
int mid = (start + (end - start)/2);
P = MinMax(A, start, mid);
P_ = MinMax(A, (mid + 1), end);
if(P.MAX > P_.MAX){
F.MAX = P.MAX;
}
else{
F.MAX = P_.MAX;
}
if(P.MIN < P_.MIN){
F.MIN = P.MIN;
}
else{
F.MIN = P_.MIN;
}
return F;
}
}
private static void Print(int[] A) {
System.out.println();
for(int x: A){
System.out.print(x + " ");
}
System.out.println();
}
}
class Pair{
public int MIN, MAX;
public Pair(int MIN, int MAX){
this.MIN = MIN;
this.MAX = MAX;
}
}
Explanation
This is the JAVA code for finding out the MIN and MAX value in an Array using the Divide & Conquer approach, with the help of a Pair class.
The Random class of JAVA initializes the Array with a Random size N ε(5, 15) and with Random values ranging between (-100, 100).
An Object P of the Pair class is created which takes back the return value from MinMax() method. The MinMax() method takes an Array (A[]), a Starting Index (start) and a Final Index (end) as the Parameters.
Working Logic
Three different objects P, P_, F are created, of the Pair class.
Cases :-
Array Size -> 1 (start == end) : In this case, both the MIN and the MAX value are A[0], which is then assigned to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size -> 2 (start + 1 == end) : In this case, the code block compares both the values of the Array and then assign it to the object P of the Pair class as P.MIN and P.MAX, which is then returned.
Array Size > 2 : In this case, the Mid is calculated and the MinMax method is called from start -> mid and (mid + 1) -> end. which again will call recursively until the first two cases hit and returns the value. The values are stored in object P and P_, which are then compared and then finally returned by object F as F.MAX and F.MIN.
The Pair Class has one method by the same name Pair(), which takes 2 Int parameters, as MIN and MAX, assigned to then as Pair.MIN and Pair.MAX
Further Links for Code
https://www.techiedelight.com/find-minimum-maximum-element-array-minimum-comparisons/
https://www.enjoyalgorithms.com/blog/find-the-minimum-and-maximum-value-in-an-array

How to calculate the median of an array?

I'm trying to calculate the total, mean and median of an array thats populated by input received by a textfield. I've managed to work out the total and the mean, I just can't get the median to work. I think the array needs to be sorted before I can do this, but I'm not sure how to do this. Is this the problem, or is there another one that I didn't find? Here is my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class whileloopq extends Applet implements ActionListener
{
Label label;
TextField input;
int num;
int index;
int[] numArray = new int[20];
int sum;
int total;
double avg;
int median;
public void init ()
{
label = new Label("Enter numbers");
input = new TextField(5);
add(label);
add(input);
input.addActionListener(this);
index = 0;
}
public void actionPerformed (ActionEvent ev)
{
int num = Integer.parseInt(input.getText());
numArray[index] = num;
index++;
if (index == 20)
input.setEnabled(false);
input.setText("");
sum = 0;
for (int i = 0; i < numArray.length; i++)
{
sum += numArray[i];
}
total = sum;
avg = total / index;
median = numArray[numArray.length/2];
repaint();
}
public void paint (Graphics graf)
{
graf.drawString("Total = " + Integer.toString(total), 25, 85);
graf.drawString("Average = " + Double.toString(avg), 25, 100);
graf.drawString("Median = " + Integer.toString(median), 25, 115);
}
}
The Arrays class in Java has a static sort function, which you can invoke with Arrays.sort(numArray).
Arrays.sort(numArray);
double median;
if (numArray.length % 2 == 0)
median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2;
else
median = (double) numArray[numArray.length/2];
Sorting the array is unnecessary and inefficient. There's a variation of the QuickSort (QuickSelect) algorithm which has an average run time of O(n); if you sort first, you're down to O(n log n). It actually finds the nth smallest item in a list; for a median, you just use n = half the list length. Let's call it quickNth (list, n).
The concept is that to find the nth smallest, choose a 'pivot' value. (Exactly how you choose it isn't critical; if you know the data will be thoroughly random, you can take the first item on the list.)
Split the original list into three smaller lists:
One with values smaller than the pivot.
One with values equal to the pivot.
And one with values greater than the pivot.
You then have three cases:
The "smaller" list has >= n items. In that case, you know that the nth smallest is in that list. Return quickNth(smaller, n).
The smaller list has < n items, but the sum of the lengths of the smaller and equal lists have >= n items. In this case, the nth is equal to any item in the "equal" list; you're done.
n is greater than the sum of the lengths of the smaller and equal lists. In that case, you can essentially skip over those two, and adjust n accordingly. Return quickNth(greater, n - length(smaller) - length(equal)).
Done.
If you're not sure that the data is thoroughly random, you need to be more sophisticated about choosing the pivot. Taking the median of the first value in the list, the last value in the list, and the one midway between the two works pretty well.
If you're very unlucky with your choice of pivots, and you always choose the smallest or highest value as your pivot, this takes O(n^2) time; that's bad. But, it's also very unlikely if you choose your pivot with a decent algorithm.
Sample code:
import java.util.*;
public class Utility {
/****************
* #param coll an ArrayList of Comparable objects
* #return the median of coll
*****************/
public static <T extends Number> double median(ArrayList<T> coll, Comparator<T> comp) {
double result;
int n = coll.size()/2;
if (coll.size() % 2 == 0) // even number of items; find the middle two and average them
result = (nth(coll, n-1, comp).doubleValue() + nth(coll, n, comp).doubleValue()) / 2.0;
else // odd number of items; return the one in the middle
result = nth(coll, n, comp).doubleValue();
return result;
} // median(coll)
/*****************
* #param coll a collection of Comparable objects
* #param n the position of the desired object, using the ordering defined on the list elements
* #return the nth smallest object
*******************/
public static <T> T nth(ArrayList<T> coll, int n, Comparator<T> comp) {
T result, pivot;
ArrayList<T> underPivot = new ArrayList<>(), overPivot = new ArrayList<>(), equalPivot = new ArrayList<>();
// choosing a pivot is a whole topic in itself.
// this implementation uses the simple strategy of grabbing something from the middle of the ArrayList.
pivot = coll.get(n/2);
// split coll into 3 lists based on comparison with the pivot
for (T obj : coll) {
int order = comp.compare(obj, pivot);
if (order < 0) // obj < pivot
underPivot.add(obj);
else if (order > 0) // obj > pivot
overPivot.add(obj);
else // obj = pivot
equalPivot.add(obj);
} // for each obj in coll
// recurse on the appropriate list
if (n < underPivot.size())
result = nth(underPivot, n, comp);
else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it
result = pivot;
else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the recursion.
result = nth(overPivot, n - underPivot.size() - equalPivot.size(), comp);
return result;
} // nth(coll, n)
public static void main (String[] args) {
Comparator<Integer> comp = Comparator.naturalOrder();
Random rnd = new Random();
for (int size = 1; size <= 10; size++) {
ArrayList<Integer> coll = new ArrayList<>(size);
for (int i = 0; i < size; i++)
coll.add(rnd.nextInt(100));
System.out.println("Median of " + coll.toString() + " is " + median(coll, comp));
} // for a range of possible input sizes
} // main(args)
} // Utility
If you want to use any external library here is Apache commons math library using you can calculate the Median.
For more methods and use take look at the API documentation
import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
Median median = new Median();
double medianValue = median.evaluate(values);
return medianValue;
}
.......
For more on evaluate method AbstractUnivariateStatistic#evaluate
Update
Calculate in program
Generally, median is calculated using the following two formulas given here
If n is odd then Median (M) = value of ((n + 1)/2)th item term.
If n is even then Median (M) = value of [((n)/2)th item term + ((n)/2 + 1)th item term ]/2
In your program you have numArray, first you need to sort array using Arrays#sort
Arrays.sort(numArray);
int middle = numArray.length/2;
int medianValue = 0; //declare variable
if (numArray.length%2 == 1)
medianValue = numArray[middle];
else
medianValue = (numArray[middle-1] + numArray[middle]) / 2;
Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;
Arrays.sort(numArray);
int middle = ((numArray.length) / 2);
if(numArray.length % 2 == 0){
int medianA = numArray[middle];
int medianB = numArray[middle-1];
median = (medianA + medianB) / 2;
} else{
median = numArray[middle + 1];
}
EDIT: I initially had medianB setting to middle+1 in the even length arrays, this was wrong due to arrays starting count at 0. I have updated it to use middle-1 which is correct and should work properly for an array with an even length.
You can find good explanation at https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc
The idea it to use 2 Heaps viz one max heap and mean heap.
class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();
public void add(int number) {
Queue<Integer> target = low.size() <= high.size() ? low : high;
target.add(number);
balance();
}
private void balance() {
while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) {
Integer lowHead= low.poll();
Integer highHead = high.poll();
low.add(highHead);
high.add(lowHead);
}
}
public double median() {
if(low.isEmpty() && high.isEmpty()) {
throw new IllegalStateException("Heap is empty");
} else {
return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek();
}
}
}
Try sorting the array first. Then after it's sorted, if the array has an even amount of elements the mean of the middle two is the median, if it has a odd number, the middle element is the median.
Use Arrays.sort and then take the middle element (in case the number n of elements in the array is odd) or take the average of the two middle elements (in case n is even).
public static long median(long[] l)
{
Arrays.sort(l);
int middle = l.length / 2;
if (l.length % 2 == 0)
{
long left = l[middle - 1];
long right = l[middle];
return (left + right) / 2;
}
else
{
return l[middle];
}
}
Here are some examples:
#Test
public void evenTest()
{
long[] l = {
5, 6, 1, 3, 2
};
Assert.assertEquals((3 + 4) / 2, median(l));
}
#Test
public oddTest()
{
long[] l = {
5, 1, 3, 2, 4
};
Assert.assertEquals(3, median(l));
}
And in case your input is a Collection, you might use Google Guava to do something like this:
public static long median(Collection<Long> numbers)
{
return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}
I was looking at the same statistics problems. The approach you are thinking it is good and it will work. (Answer to the sorting has been given)
But in case you are interested in algorithm performance, I think there are a couple of algorithms that have better performance than just sorting the array, one (QuickSelect) is indicated by #bruce-feist's answer and is very well explained.
[Java implementation: https://discuss.leetcode.com/topic/14611/java-quick-select ]
But there is a variation of this algorithm named median of medians, you can find a good explanation on this link:
http://austinrochford.com/posts/2013-10-28-median-of-medians.html
Java implementation of this:
- https://stackoverflow.com/a/27719796/957979
I faced a similar problem yesterday.
I wrote a method with Java generics in order to calculate the median value of every collection of Numbers; you can apply my method to collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
Note: my method works on collections, you can convert arrays of numbers to list of numbers as pointed here
And nobody paying attention when list contains only one element (list.size == 1). All your answers will crash with index out of bound exception, because integer division returns zero (1 / 2 = 0). Correct answer (in Kotlin):
MEDIAN("MEDIAN") {
override fun calculate(values: List<BigDecimal>): BigDecimal? {
if (values.size == 1) {
return values.first()
}
if (values.size > 1) {
val valuesSorted = values.sorted()
val mid = valuesSorted.size / 2
return if (valuesSorted.size % 2 != 0) {
valuesSorted[mid]
} else {
AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
}
}
return null
}
},
As #Bruce-Feist mentions, for a large number of elements, I'd avoid any solution involving sort if performance is something you are concerned about. A different approach than those suggested in the other answers is Hoare's algorithm to find the k-th smallest of element of n items. This algorithm runs in O(n).
public int findKthSmallest(int[] array, int k)
{
if (array.length < 10)
{
Arrays.sort(array);
return array[k];
}
int start = 0;
int end = array.length - 1;
int x, temp;
int i, j;
while (start < end)
{
x = array[k];
i = start;
j = end;
do
{
while (array[i] < x)
i++;
while (x < array[j])
j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (j < k)
start = i;
if (k < i)
end = j;
}
return array[k];
}
And to find the median:
public int median(int[] array)
{
int length = array.length;
if ((length & 1) == 0) // even
return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
else // odd
return findKthSmallest(array, array.length / 2);
}
public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
for (int i=0;i<arr.length;i++) {
if (arr.length % 2 == 1) {
median = Math.round(arr[arr.length/2]);
} else {
median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
}
}
return median;
}
Check out the Arrays.sort methods:
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
You should also really abstract finding the median into its own method, and just return the value to the calling method. This will make testing your code much easier.
public int[] data={31, 29, 47, 48, 23, 30, 21
, 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40};
public double median()
{
Arrays.sort(this.data);
double result=0;
int size=this.data.length;
if(size%2==1)
{
result=data[((size-1)/2)+1];
System.out.println(" uneven size : "+result);
}
else
{
int middle_pair_first_index =(size-1)/2;
result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2;
System.out.println(" Even size : "+result);
}
return result;
}
package arrays;
public class Arraymidleelement {
static public double middleArrayElement(int [] arr)
{
double mid;
if(arr.length%2==0)
{
mid=((double)arr[arr.length/2]+(double)arr[arr.length/2-1])/2;
return mid;
}
return arr[arr.length/2];
}
public static void main(String[] args) {
int arr[]= {1,2,3,4,5,6};
System.out.println( middleArrayElement(arr));
}
}

Categories

Resources