How do I find a recurrence relation for a recursive method? - java

So I'm trying to find a recurrence relation for this java method:
public static Pair min/max(int start, int end, int[] a) {
int mid;
Pair pair = new Pair(a[start], a[end]);
Pair p1;
Pair p2;
if (start == end) { //if n = 1
return pair;
}
else if (end == start + 1) { //if n = 2
if (a[start] > a[end]) {
pair.upper = a[end];
pair.lower = a[start];
} else {
pair.upper = a[start];
pair.lower = a[end];
}
return pair;
}
mid = (end + start) / 2; //if n > 2
p1 = min/max(end, mid, a);
p2 = min/max(mid + 1, ub, a);
if (p1.lower < p2.lower)
pair.upper = p1.lower;
else
pair.lower = p2.lower;
if (p1.upper > p2.upper)
pair.upper = p1.upper;
else
pair.upper = p2.upper;
return pair; //the min and max pair
}
This is supposed to find the max and min of an array by always using ⌈3n/2 - 2⌉ comparisons. It also uses this class:
class Pair {
int lower;
int upper;
Pair ( int a, int o ) { lower = a; upper = o; }
}
So what would be the recurrence relation for this method? I know that it starts out as:
C(n) = 0 if n=1
1 if n=2
And now I'm trying to figure out what the equation would be when n > 2. First off does the above method always run in ⌈3n/2 - 2⌉ comparisons. I'm just wondering because of the line mid = (lb + ub) / 2 which makes me think that I'm still splitting the array into ⌈n/2⌉ and ⌊n/2⌋ parts which would not get me ⌈3n/2 - 2⌉ comparisons each time. I know that there is a better way to do this same thing but the code I'm writing has to use recursion.
UPDATE: After adding counter statements I find that the above code does not use ⌈3n/2 - 2⌉ comparisons for every array. I think the problem is with the variable mid. With mid I'm supposed to split the array however I don't think I'm splitting it correctly to have the proper number of comparisons.

Let n = end - start + 1. I presume you mean a recurrence expressing the number of comparisons.
In the general case you are doing 4 comparisons for each level of recursion and splitting the list in half. So the recurrence is:
T(n) = 4 + T( floor(n/2) ) + T( ceiling(n/2) ) for n > 1
NB: You seem to have begun with lb and ub and switched only partially to start and end.

Related

[Java]: How to fetch the nearest smaller number from a sorted list when a number requested is not in the list

I want to fetch the nearest smaller number from a sorted list when a number requested is not in the list. Eg: List {10,14,55,97} and the requested number is
12, then I want to return 10. But the code below returns 14. This code searches on both the directions in the list. I want to search only on the lower side of the list.
I tried the following code:
public static int getClosestInteger(final List<Integer> listOfIntegers, final int requestedNumber) {
int low = 0;
int high = listOfIntegers.size() - 1;
if (high < 0) {
throw new IllegalArgumentException("The list cannot be empty");
}
while (low < high) {
final int mid = (low + high) / 2;
assert (mid < high);
final int digit1 = Math.abs(listOfIntegers.get(mid) - requestedNumber);
final int digit2 = Math.abs(listOfIntegers.get(mid + 1) - requestedNumber);
if (digit2 <= digit1) {
low = mid + 1;
} else {
high = mid;
}
}
return listOfIntegers.get(high);
}
Any suggestions on what to change?
What you're doing is a variant on the binary search algorithm.
Check out the Procedure for finding the leftmost element
In pseudo code:
function binary_search_leftmost(A, n):
L := 0
R := n
while L < R:
m := floor((L + R) / 2)
if A[m] < T:
L := m + 1
else:
R := m
return L
This will find the number of elements less than T. And since arrays start at 0, all you need to do in the end is
if A[L] == T:
return A[L]
else:
return A[L-1]
It's slightly different from your algorithm.
Or...
you could add that number to the list, find its index, decrement by one and then remove it from the list :D

Recursively finding the average of even numbers in an array

I'm trying to find the average of all even numbers in an array using recursion and I'm stuck.
I realize that n will have to be decremented for each odd number so I divide by the correct value, but I can't wrap my mind around how to do so with recursion.
I don't understand how to keep track of n as I go, considering it will just revert when I return.
Is there a way I'm missing to keep track of n, or am I looking at this the wrong way entirely?
EDIT: I should have specified, I need to use recursion specifically. It's an assignment.
public static int getEvenAverage(int[] A, int i, int n)
{
// first element
if (i == 0)
if (A[i] % 2 == 0)
return A[0];
else
return 0;
// last element
if (i == n - 1)
{
if (A[i] % 2 == 0)
return (A[i] + getEvenAverage(A, i - 1, n)) / n;
else
return (0 + getEvenAverage(A, i - 1, n)) / n;
}
if (A[i] % 2 == 0)
return A[i] + getEvenAverage(A, i - 1, n);
else
return 0 + getEvenAverage(A, i - 1, n);
}
In order to keep track of the number of even numbers you have encountered so far, just pass an extra parameter.
Moreover, you can also pass an extra parameter for the sum of even numbers and when you hit the base case you can return the average, that is, sum of even numbers divided by their count.
One more thing, your code has two base cases for the first as well as last element which is unneeded.
You can either go decrementing n ( start from size of array and go till the first element ), or
You can go incrementing i starting from 0 till you reach size of array, that is, n.
Here, is something I tried.
public static int getEvenAvg(int[] a, int n, int ct, int sum) {
if (n == -1) {
//make sure you handle the case
//when count of even numbers is zero
//otherwise you'll get Runtime Error.
return sum/ct;
}
if (a[n]%2 == 0) {
ct++;
sum+=a[n];
}
return getEvenAvg(a, n - 1, ct, sum);
}
You can call the function like this getEvenAvg(a, size_of_array - 1, 0, 0);
Example
When dealing with recursive operations, it's often useful to start with the terminating conditions. So what are our terminating conditions here?
There are no more elements to process:
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
... okay, now how do we reduce the number of elements to process? We should probably increment index?
index++;
... oh, but only when going to the next level:
getEvenAverage(elements, index++, sum, count);
Well, we're also going to have to add to sum and count, right?
sum += a[index];
count++;
.... except, only if the element is even:
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
... and that's about it:
static int getEvenAverage(int[] elements, int index, int sum, int count) {
if (index >= a.length) {
// To avoid divide-by-zero
return count == 0 ? 0 : sum / count;
}
if (a[index] % 2 == 0) {
sum += a[index];
count++;
}
return getEvenAverage(elements, index + 1, sum, count);
}
... although you likely want a wrapper function to make calling it prettier:
static int getEvenAverage(int[] elements) {
return getEvenAverage(elements, 0, 0, 0);
}
Java is not a good language for this kind of thing but here we go:
public class EvenAverageCalculation {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9,10};
System.out.println(getEvenAverage(array));
}
public static double getEvenAverage(int[] values) {
return getEvenAverage(values, 0, 0);
}
private static double getEvenAverage(int[] values, double currentAverage, int nrEvenValues) {
if (values.length == 0) {
return currentAverage;
}
int head = values[0];
int[] tail = new int[values.length - 1];
System.arraycopy(values, 1, tail, 0, tail.length);
if (head % 2 != 0) {
return getEvenAverage(tail, currentAverage, nrEvenValues);
}
double newAverage = currentAverage * nrEvenValues + head;
nrEvenValues++;
newAverage = newAverage / nrEvenValues;
return getEvenAverage(tail, newAverage, nrEvenValues);
}
}
You pass the current average and the number of even elements so far to each the recursive call. The new average is calculated by multiplying the average again with the number of elements so far, add the new single value and divide it by the new number of elements before passing it to the next recursive call.
The way of recreating new arrays for each recursive call is the part that is not that good with Java. There are other languages that have syntax for splitting head and tail of an array which comes with a much smaller memory footprint as well (each recursive call leads to the creation of a new int-array with n-1 elements). But the way I implemented that is the classical way of functional programming (at least how I learned it in 1994 when I had similar assignments with the programming language Gofer ;-)
Explanation
The difficulties here are that you need to memorize two values:
the amount of even numbers and
the total value accumulated by the even numbers.
And you need to return a final value for an average.
This means that you need to memorize three values at once while only being able to return one element.
Outline
For a clean design you need some kind of container that holds those intermediate results, for example a class like this:
public class Results {
public int totalValueOfEvens;
public int amountOfEvens;
public double getAverage() {
return totalValueOfEvens + 0.0 / amountOfEvens;
}
}
Of course you could also use something like an int[] with two entries.
After that the recursion is very simple. You just need to recursively traverse the array, like:
public void method(int[] values, int index) {
// Abort if last element
if (index == values.length - 1) {
return;
}
method(array, index + 1);
}
And while doing so, update the container with the current values.
Collecting backwards
When collecting backwards you need to store all information in the return value.
As you have multiple things to remember, you should use a container as return type (Results or a 2-entry int[]). Then simply traverse to the end, collect and return.
Here is how it could look like:
public static Results getEvenAverage(int[] values, int curIndex) {
// Traverse to the end
if (curIndex != values.length - 1) {
results = getEvenAverage(values, curIndex + 1);
}
// Update container
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
// Return accumulated results
return results;
}
Collecting forwards
The advantage of this method is that the caller does not need to call results.getAverage() by himself. You store the information in the parameters and thus be able to freely choose the return type.
We get our current value and update the container. Then we call the next element and pass him the current container.
After the last element was called, the information saved in the container is final. We now simply need to end the recursion and return to the first element. When again visiting the first element, it will compute the final output based on the information in the container and return.
public static double getEvenAverage(int[] values, int curIndex, Results results) {
// First element in recursion
if (curIndex == 0) {
// Setup the result container
results = new Results();
}
int myValue = values[curIndex];
// Whether this element contributes
if (myValue % 2 == 0) {
// Update the result container
results.totalValueOfEvens += myValue;
results.amountOfEvens++;
}
int returnValue = 0;
// Not the last element in recursion
if (curIndex != values.length - 1) {
getEvenAverage(values, curIndex + 1, results);
}
// Return current intermediate average,
// which is the correct result if current element
// is the first of the recursion
return results.getAverage();
}
Usage by end-user
The backward method is used like:
Results results = getEvenAverage(values, 0);
double average results.getAverage();
Whereas the forward method is used like:
double average = getEvenAverage(values, 0, null);
Of course you can hide that from the user using a helper method:
public double computeEvenAverageBackward(int[] values) {
return getEvenAverage(values, 0).getAverage();
}
public double computeEvenAverageForward(int[] values) {
return getEvenAverage(values, 0, null);
}
Then, for the end-user, it is just this call:
double average = computeEvenAverageBackward(values);
Here's another variant, which uses a (moderately) well known recurrence relationship for averages:
avg0 = 0
avgn = avgn-1 + (xn - avgn-1) / n
where avgn refers to the average of n observations, and xn is the nth observation.
This leads to:
/*
* a is the array of values to process
* i is the current index under consideration
* n is a counter which is incremented only if the current value gets used
* avg is the running average
*/
private static double getEvenAverage(int[] a, int i, int n, double avg) {
if (i >= a.length) {
return avg;
}
if (a[i] % 2 == 0) { // only do updates for even values
avg += (a[i] - avg) / n; // calculate delta and update the average
n += 1;
}
return getEvenAverage(a, i + 1, n, avg);
}
which can be invoked using the following front-end method to protect users from needing to know about the parameter initialization:
public static double getEvenAverage(int[] a) {
return getEvenAverage(a, 0, 1, 0.0);
}
And now for a completely different approach.
This one draws on the fact that if you have two averages, avg1 based on n1 observations and avg2 based on n2 observations, you can combine them to produce a pooled average:
avgpooled = (n1 * avg1 + n2 * avg2) / (n1 + n2).
The only issue here is that the recursive function should return two values, the average and the number of observations on which that average is based. In many other languages, that's not a problem. In Java, it requires some hackery in the form of a trivial, albeit slightly annoying, helper class:
// private helper class because Java doesn't allow multiple returns
private static class Pair {
public double avg;
public int n;
public Pair(double avg, int n) {
super();
this.avg = avg;
this.n = n;
}
}
Applying a divide and conquer strategy yields the following recursion:
private static Pair getEvenAverage(int[] a, int first, int last) {
if (first == last) {
if (a[first] % 2 == 0) {
return new Pair(a[first], 1);
}
} else {
int mid = (first + last) / 2;
Pair p1 = getEvenAverage(a, first, mid);
Pair p2 = getEvenAverage(a, mid + 1, last);
int total = p1.n + p2.n;
if (total > 0) {
return new Pair((p1.n * p1.avg + p2.n * p2.avg) / total, total);
}
}
return new Pair(0.0, 0);
}
We can deal with empty arrays, protect the end-user from having to know about the book-keeping arguments, and return just the average by using the following public front-end:
public static double getEvenAverage(int[] a) {
return a.length > 0 ? getEvenAverage(a, 0, a.length - 1).avg : 0.0;
}
This solution has the benefit of O(log n) stack growth for an array of n items, versus O(n) for the various other solutions that have been proposed. As a result, it can deal with much larger arrays without fear of a stack overflow.

What counts as a binary search comparison?

I'm writing a program that determines how many comparisons it takes to run a binary search algorithm for a given number and sorted array. What I don't understand is what counts as a comparison.
// returns the number of comparisons it takes to find key in sorted list, array
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (true) {
if (left > right) {
mid = -1;
break;
}
else {
mid = (left + right)/2;
if (key < array[mid]) {
i++;
right = mid - 1;
}
else if (key > array[mid]) {
i++;
left = mid + 1;
}
else {
break; // success
}
}
}
return i;
}
The function returns i, which is supposed to be the total number of comparisons made in finding the key in array. But what defines a comparison? Is it any time there is a conditional?
Thanks for any help, just trying to understand this concept.
Usually, a comparison occurs each time the key is compared to an array element. The code seems to not be counting that, though. It is counting how many times one of the search boundaries (left or right) is changed. It's not exactly the same thing being counted, but it's pretty close to the same thing, since the number of times a boundary is shifted is directly related to the number of times through the loop and hence to the number of times a comparison is made. At most, the two ways of counting will be off by 1 or 2 (I didn't bother to figure that out exactly).
Note also that if one were to use the usual definition, the code could be rewritten to use Integer.compare(int,int) do a single comparison of key with array[mid] to determine whether key was less than, equal to, or greater than array[mid].
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right)/2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
}
else if (comp > 0) {
left = mid + 1;
}
else {
break; // success
}
}
return i;
}

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

Max Double Slice Sum codility O(1) space complexity fail performance test case

I was trying figure out why the below solution failed for a single performance test case for the 'Max Double Slice Sum' problem in the codility website: https://codility.com/demo/take-sample-test/max_double_slice_sum
There is another solution O(n) space complexity which is easier to comprehend overhere: Max double slice sum. But i am just wondering why this O(1) solution doesn't work. Below is the actual code:
import java.util.*;
class Solution {
public int solution(int[] A) {
long maxDS = 0;
long maxDSE = 0;
long maxS = A[1];
for(int i=2; i<A.length-1; ++i){
//end at i-index
maxDSE = Math.max(maxDSE+A[i], maxS);
maxDS = Math.max(maxDS, maxDSE);
maxS = Math.max(A[i], maxS + A[i]);
}
return (int)maxDS;
}
}
The idea is simple as follow:
The problem can be readdress as finding max(A[i]+A[i+1]+...+A[j]-A[m]); 1<=i<=m<=j<=n-2; while n = A.length; we call A[m] is missing element within the slice.
maxS[i] will keep max slice which end at current index i; in other words, = max(A[t] + ... + A[i]); while t < i; so when i=1; maxS = A[1]; Note that in solution, we don't keep array but rather latest maxS at current index (See above code).
maxDSE[i] is max of all double slice which end at i; in other words, = max(A[t]+A[t+1]+...+A[i]-A[m])--end at A[i]; maxDS is the final max of double slice sum which we try to find.
Now, we just use a for-loop from i=2; -> i=A.length-2; For each index i, we notice some findings:
If the missing element is A[i], then maxDSE[i] = maxS[i-1] (max sum of
all slice which end at i-1 => or A[t] + ... + A[i] - A[i]);
If missing element is not A[i] -> so it must be somewhere from A[1]->A[i-1] -> maxDSE = maxDSE[i-1] + A[i]; such as A[t] + ... + A[i] - A[m] (not that A[i] must be last element) with t
so maxDSE[i] = Math.max(maxDSE[i-1]+A[i], maxS[i-1]);
maxDS = Math.max(maxDS, maxDSE); max amount all maxDSE;
and maxS[i] = Math.max(A[i], maxS[i-1]+A[i]);
by that way, maxDS will be the final result.
But strange that, I was only able to get 92%; with one failed performance test case as shown here:
medium_range
-1000, ..., 1000
WRONG ANSWER
got 499499 expected 499500
Could anyone please enlighten me where is problem in my solution? Thanks!
Ok, I found the error with my code. Seems that I forgot one corner cases. When calculate DSE[i], in cases A[i] is missing number, maxS should contain the case when array is empty. In other word, maxS should be calculated as:
maxS[i] = Math.max(0, Math.max(A[i]+maxS[i-1], A[i])); while 0 is for case of empty subarray (end at i-th); Math.max(A[i]+maxS[i-1], A[i]) is max of all slice with at least one element (end at i-index). The complete code as follow:
import java.util.*;
class Solution {
public int solution(int[] A) {
long maxDS = 0;
long maxDSE = 0;
long maxS = A[1];
for(int i=2; i<A.length-1; ++i){
maxDSE = Math.max(maxDSE+A[i], maxS);
maxDS = Math.max(maxDS, maxDSE);
maxS = Math.max(0, Math.max(A[i], maxS + A[i]));
}
return (int)maxDS;
}
}
It seems that for the input [-11, -53, -4, 38, 76, 80], your solution doesn't work. Yes, it tricks all the codility test cases, but I managed to trick all codility test cases for other problems too.
If you don't just want to trick codility, but also you want to come with a good solution, I suggest that you create a loop and a large number of random test cases (in number of elements and element values), and create a test method of your own, that you are sure works (even if the complexity is quadratic), compare the results from both methods and then analyze the current random input that doesn't fit.
Here is clear solution. Best approach is to use algorithm of Kanade O(N) and O(1) by space
public class DuplicateDetermineAlgorithm {
public static boolean isContainsDuplicate(int[] array) {
if (array == null) {
throw new IllegalArgumentException("Input array can not be null");
}
if (array.length < 2) {
return false;
}
for (int i = 0; i < array.length; i++) {
int pointer = convertToPositive(array[i]) - 1;
if (array[pointer] > 0) {
array[pointer] = changeSign(array[pointer]);
} else {
return true;
}
}
return false;
}
private static int convertToPositive(int value) {
return value < 0 ? changeSign(value) : value;
}
private static int changeSign(int value) {
return -1 * value;
}
}
I have coded it in vb.net and got 100/100 getting idea form solution by Guillermo
Private Function solution(A As Integer()) As Integer
' write your code in VB.NET 4.0
Dim Slice1() As Integer = Ending(A)
Dim slice2() As Integer = Starting(A)
Dim maxSUM As Integer = 0
For i As Integer = 1 To A.Length - 2
maxSUM = Math.Max(maxSUM, Slice1(i - 1) + slice2(i + 1))
Next
Return maxSUM
End Function
Public Shared Function Ending(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = 1 To input.Length - 2
result(i) = Math.Max(0, result(i - 1) + input(i))
Next
Return result
End Function
Public Shared Function Starting(input() As Integer) As Integer()
Dim result As Integer() = New Integer(input.Length - 1) {}
result(0) = InlineAssignHelper(result(input.Length - 1), 0)
For i As Integer = input.Length - 2 To 1 Step -1
result(i) = Math.Max(0, result(i + 1) + input(i))
Next
Return result
End Function
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
Visit Codility to see the results

Categories

Resources