Get count from array using recursion - java

I need to get the count of numbers less than the first integer in an array using recursion. I am given a function definition as
public static int countGreaterThanFirst(int[]
numbers, int startIndex, int endIndex, int firstNumber){}
I am not supposed to use a loop or global/static variable. How can I convert my implementation below to satisfy the two conditions above. I have recently asked another similar question but this is a bit different due to the need to keep track of the count variable. If someone can help, I will really appreciate.
Below is my implementation with a loop.
public static int countGreaterThanFirst(int[] numbers, int startIndex, int endIndex, int firstNumber) {
int greater_than_first = 0;
for (int count = startIndex; count <= endIndex; count++) {
if (numbers[count] > firstNumber) {
greater_than_first++;
}
}
return greater_than_first;
}

Probably you don't need that much parameters:
public static int countGreaterThanFirst(int[] numbers, int currentIndex) {
if (currentIndex == numbers.length) return 0;
else {
if (numbers[currentIndex] > numbers[0]) {
return 1 + countGreaterThanFirst(numbers, currentIndex + 1);
} else {
return countGreaterThanFirst(numbers, currentIndex + 1);
}
}
}
and you should invoke it with (for example):
countGreaterThanFirst(someArray, 1);
If you meant to find "all the numbers between numbers[startIndex] and numbers[endIndex] that are greater than firstNumber, then the implementation should be pretty similar to the above one:
public static int countGreaterThanFirst(int[] numbers, int startIndex, int endIndex, int firstNumber) {
if (startIndex > endIndex) return 0;
else {
if (numbers[startIndex] > firstNumber) {
return 1 + countGreaterThanFirst(numbers, startIndex + 1, endIndex, firstNumber);
} else {
return countGreaterThanFirst(numbers, startIndex + 1, endIndex, firstNumber);
}
}
}

Related

Efficiently, get the count of numbers in a sorted array that is less than a given number using binary search

My problem statement is this -
Find the count of numbers in a sorted array that are less than a given number, and this should be done efficiently with respect to time. I wrote a program using binary search that gets the count but time complexity wise it's failing. Need help in achieving this.
import java.util.Arrays;
public class SortedSearch {
public static int countNumbers(int[] sortedArray, int lessThan) {
if(sortedArray.length ==1 || sortedArray.length == 0) {
return singleElement(sortedArray, lessThan);
}
else {
return binarySearch(sortedArray, lessThan);
}
}
public static int singleElement(int[] sortedArray, int searchVal) {
if(sortedArray.length == 0) {
return 0;
}
if(sortedArray[0] < searchVal) {
return 1;
}
return 0;
}
private static int binarySearch(int[] sortedArray, int searchVal) {
int low = 0;
int high = (sortedArray.length)-1;
int mid = (low + high)/2;
if((sortedArray.length == 0) || (sortedArray[0] > searchVal)) {
return 0;
}
if(sortedArray[high] < searchVal) {
return sortedArray.length;
}
if(sortedArray[high] == searchVal) {
return sortedArray.length-1;
}
if(sortedArray[mid] < searchVal) {
int newLow = low;
int newHigh = calculateNewHigh(sortedArray, newLow, 0, searchVal);
int[] newArray = Arrays.copyOfRange(sortedArray, newLow, newHigh+1);
return newArray.length;
}
else {
int newLow = low;
int newHigh = mid;
int[] newArray = Arrays.copyOfRange(sortedArray, newLow, newHigh+1);
return binarySearch(newArray, searchVal);
}
}
private static int calculateNewHigh(int[] sortedArray, int low, int previousHigh, int searchVal) {
int newHigh = previousHigh + (sortedArray.length-low)/2;
if(sortedArray[newHigh] < searchVal) {
newHigh = calculateNewHigh(sortedArray, newHigh, newHigh, searchVal);
}
if(sortedArray[newHigh] == searchVal) {
newHigh--;
}
if(sortedArray[newHigh] > searchVal) {
newHigh--;
}
return newHigh;
}
public static void main(String[] args) {
System.out.println(SortedSearch.countNumbers(new int[] { 1, 3, 5, 7 }, 4));
}
}
Since you're using Arrays anyway, way not use the Arrays.binarySearch(int[] a, int key) method, instead of attempting to write your own?
public static int countNumbers(int[] sortedArray, int lessThan) {
int idx = Arrays.binarySearch(sortedArray, lessThan);
if (idx < 0)
return -idx - 1; // insertion point
while (idx > 0 && sortedArray[idx - 1] == lessThan)
idx--;
return idx; // index of first element with given value
}
The while loop1 is necessary because the javadoc says:
If the array contains multiple elements with the specified value, there is no guarantee which one will be found.
1) This loop is not optimal if e.g. all values are the same, see e.g. Finding multiple entries with binary search

Maximum minus minimum in an array

I am trying to find range(max - min) of an array using recursion.
Since, there can be only one return value, I am kind of confused how to go about this problem.
What I have done so far is to find maximum and minimum recursively and then use this in range function to find the range. I was wondering if it was possible to do everything in just range function somehow recursively.
public static int max(int[] array, int N) {
int maximum;
if (N >= array.length) {
maximum = Integer.MIN_VALUE;
} else {
maximum = max(array, N + 1);
if (array[N] > maximum) {
maximum = array[N];
}
}
return maximum;
}
public static int min(int[] array, int N) {
int minimum;
if (N >= array.length) {
minimum = Integer.MAX_VALUE;
} else {
minimum = min(array, N + 1);
if (array[N] < minimum) {
minimum = array[N];
}
}
return minimum;
}
public static int range(int [] array)
{
int max1 = max(array , 0);
System.out.println(max1);
int min1 = min(array , 0);
System.out.println(min1);
int range = max1 - min1;
return range;
}
If recursion really is a requirement, and you just need the range, then this should do it:
public static int range(int [] array, int index, int min, int max)
{
if (index == array.length) {
if (index == 0)
return 0;
else
return max - min;
}
else {
int value = array[index];
return range(array, index + 1, Math.min(value, min), Math.max(value, max));
}
}
public static int range(int [] array)
{
return range(array, 0, Integer.MAX_VALUE, Integer.MIN_VALUE);
}
Your algorithm seems waaaay too complicated for what you're trying to do.
It's not clear if using recursion is a requirement. If it is not, what about this?
public int range (int[] array) {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int elem : array) {
if (elem < min) min = elem;
if (elem > max) max = elem;
}
return (max - min);
}
On mobile so I cannot test any code, but it should work.
EDIT: Ok sorry, re-reading your question I see you just want to know how to do it using recursion. Maybe you'd like to make that clear in the title itself ;-)
You could provide a int[] with min (index 0) and max (index 1) within the method and do all in the same method.
public class Test {
#org.junit.Test
public void test() {
int[] array = new int[] { -5,2,4,6,-10,44};
int[] minmax = new int[ 2 ];
minmax( array, minmax, 0 );
assertEquals( "[-10, 44]", Arrays.toString( minmax ) );
}
public static void minmax(int[] array, int[] minmax, int N) {
if (N >= array.length) {
return;
} else {
minmax(array, minmax, N + 1);
if (array[N] < minmax[0]) {
minmax[0] = array[N];
}
if (array[N] > minmax[1]) {
minmax[1] = array[N];
}
}
}
}
You could for example return an array (0 would have min and 1 have max) that way you can return both values.
A nicer way would be to pass a callback function to you method and call that once done.
findMinMax(array, (min, max) -> { System.out.println(min + " " + max);});
private void findMinMax(int[] array, BiFunction<Integer, Integer, Void> callback) {
//Do things
callback.apply(min, max);
}
This problem doesn't have any improvement from recursion, since it is a iterative problem that - instead - can result in performance issue due to the growing of stack size, in particular for big arrays.
Anyway, a more classical example in java 7 can be the following, where you can use a minimal "Couple" class to store min/max values
public class MaxMinRecurse {
void evalMaxMinInInterval(Couple maxmin, int pos, int[] values) {
if (pos >= values.length)
return;
int x = values[pos];
if (x < maxmin.min) {
maxmin.min = x;
} else if (x > maxmin.max) {
maxmin.max = x;
}
evalMaxMinInInterval(maxmin, pos + 1, values);
}
public static void main(String[] args) {
MaxMinRecurse mmr = new MaxMinRecurse();
int[] values = { 1, 5, 3, 4, 7, 3, 4, 13 };
Couple result = mmr.new Couple();
mmr.evalMaxMinInInterval(result, 0, values);
System.out.println("Max: " + result.max + ", Min:" + result.min);
}
class Couple {
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
}
}

Most efficient way to search how many times a number appears in a sorted array

I am looking for an efficient way to find how many times a particular number appears in a sorted array.
My current code:
public class Numbers {
public static void main(String[] args) {
int[] x = new int[]{1,2,3,4,4,7,7,7,7,7,8};
int count = 0;
for (int i = 0; i < x.length; ++i)
if (x[i] == 7) ++count;
System.out.println(count);
}
}
Since the array is sorted, as mentioned in the comments, you can perform 2 binary searches to find the lowest index in the array where the number appears and the highest index where the number appears. Add in a binary search to find some index, and you get an O(log n) algorithm.
Try this code out with some different array values.
public static void main(final String[] args) {
final int numberToCount = 7;
final int[] x = new int[]{1,2,3,4,4,6,6,6,6,7,7,7,7,7,8,8,8,8,8,8};
final int indexOfKnownOccurence = Arrays.binarySearch(x, numberToCount);
if (indexOfKnownOccurence < 0) {
System.out.println("No instances of the number found");
return;
}
final int lowerBound = findIndexOfFirstOccurence(x, numberToCount, 0, indexOfKnownOccurence);
final int upperBound = findIndexOfLastOccurence(x, numberToCount, indexOfKnownOccurence, x.length - 1);
System.out.println("Lower bound: " + lowerBound);
System.out.println("Upper bound: " + upperBound);
System.out.println("Number of occurrences: " + (upperBound - lowerBound + 1));
}
//Binary search for start index
public static int findIndexOfFirstOccurence(final int[] x, final int numberToFind, final int startIndex, final int endIndex) {
if (startIndex == endIndex) {
return startIndex;
} else if (x[startIndex] == numberToFind) {
return startIndex;
} else if (startIndex + 1 == endIndex) {
return endIndex;
}
final int midIndex = startIndex + (int)Math.floor((endIndex - startIndex) / 2);
if (x[midIndex] == numberToFind) {
return findIndexOfFirstOccurence(x, numberToFind, startIndex, midIndex);
} else {
return findIndexOfFirstOccurence(x, numberToFind, midIndex, endIndex);
}
}
//Binary search for end index
public static int findIndexOfLastOccurence(final int[] x, final int numberToFind, final int startIndex, final int endIndex) {
if (startIndex == endIndex) {
return endIndex;
} else if (x[endIndex] == numberToFind) {
return endIndex;
} else if (startIndex + 1 == endIndex) {
return startIndex;
}
final int midIndex = startIndex + (int)Math.floor((endIndex - startIndex) / 2);
if (x[midIndex] == numberToFind) {
return findIndexOfLastOccurence(x, numberToFind, midIndex, endIndex);
} else {
return findIndexOfLastOccurence(x, numberToFind, startIndex, midIndex);
}
}
The answer really depends on how long your array is, if it's only few 10s of elements, it's probably more efficient to do a linear scan. If it's a larger array, I'd recommend using Array.binarySearch() as in the following:
public static void main(String[] args) {
int[] x = new int[]{1,2,3,4,4,7,7,7,7,7,8};
int index = Arrays.binarySearch(x, 7);
System.out.println(index);
int count = 0;
if (index >= 0) {
// search down
int i = index - 1;
for (; i >= 0 && x[i] == 7; --i) {
}
// search up
for (++index; index < x.length && x[index] == 7; ++index) {
}
count = index - (i + 1);
}
System.out.println(count);
}
Firstly binary search will tell you if this item is present in the array, if it is, you don't really know where in the range the search found the element, but you have to do a linear scan in both directions to determine the exact count, however the number of comparisons you have to do is at most the count of this particular key... (excluding the binary search)

Using recursion in java to find the next double in an array?

Given an array, data[ ], my goal is to find the number of elements followed by a double.
(If it was a simple for loop, it'd look something like this)
for(int i = 0; i < data.length - 1; i ++) {
if(data[i]*2 == data[i+1]) {
count++;
}
}
My issue, however, is finding a certain section of the code recursively, as noted by the question marks. I'm having trouble determining how to compare a value found in the previous method call to the current method call.
public int allDoubles(int[] data) {
int count = 0;
//return the total doubles found
return doubleFinder(data, 0, data.length, count);
}
private int doubleFinder(int data[], int low, int high, int count) {
if (low == high) {
return 0;
} else { // low < high
if( ?(previous value == current value)? ) {
count++;
}
doubleFinder(data, low, high -1, count);
}
return count;
}
You are not passing the calculated result back up to the calling method. Since java is call-by-value, this won't work. Also you pass the wrong values to doubleFinder in allDoubles: You should use (data, 0, data.length-1, count) instead of (data, 0, data.length, count).
Your method could be fixed like this:
private int doubleFinder(int data[], int low, int high, int count) {
if (low == high) {
return count;
} else { // low < high
if(data[high-1]*2 == data[high]) {
count++;
}
// pass the count from the base case to calling method
return doubleFinder(data, low, high -1, count);
}
}
but you can even remove count:
private int doubleFinder(int data[], int low, int high) {
if (low == high) {
// just 1 value
return 0;
} else if (data[low]*2 == data[low+1]) {
// 1 "double" found -> add 1
return 1 + doubleFinder(data, low+1, high);
} else {
return doubleFinder(data, low+1, high);
}
}
Here is an implementation of doubleFinder() which recursively compares data[i] == 2*data[i-i], beginning with the highest index in the input array data. It counts 1 for every double (not the type) found, and returns the total count of doubles for the input entered.
private int doubleFinder(int data[], int index) {
if (index <= 0) {
return 0; // reached last number in array 'data'
} else {
if (data[index] == 2*data[index-1])
return doubleFinder(data, index-1) + 1;
else {
doubleFinder(data, index-1)
}
}
}

Segment Tree Codechef TLE

I am trying to solve this CodeChef problem:
There are N coins kept on the table, numbered from 0 to N - 1. Initially, each coin is kept tails up.
You have to perform two types of operations:
Flip all coins numbered between A and B inclusive. This is represented by the command "0 A B"
Answer how many coins numbered between A and B inclusive are heads up. This is represented by the command "1 A B".
Input: The first line contains two integers, N and Q. Each of the next Q lines are either of the form "0 A B" or "1 A B" as mentioned above.
Output: Output 1 line for each of the queries of the form "1 A B" containing the required answer for the corresponding query.
What I have used is a segment tree. So that every time user enter a query of type 1 A B the output is the sum at that interval [A,B]. However I am getting a Time Limit Exceeded error. I believe the error is due to the update step 0 A B. After updating the elements in the array I reconstruct the tree. The code is given below. Can someone help me with a faster way to update?
BTW - I am getting the desired output for the sample input.
public class SegmentTree
{
private int[] tree;
private int maxsize;
private int height;
private static int elems[];
private final int STARTINDEX = 0;
private final int ENDINDEX;
private final int ROOT = 0;
public SegmentTree(int size)
{
height = (int)(Math.ceil(Math.log(size) / Math.log(2)));
maxsize = 2 * (int) Math.pow(2, height) - 1;
tree = new int[maxsize];
ENDINDEX = size - 1;
}
private int leftchild(int pos)
{
return 2 * pos + 1;
}
private int rightchild(int pos)
{
return 2 * pos + 2;
}
private int mid(int start, int end)
{
return (start + (end - start) / 2);
}
private int getSumUtil(int startIndex, int endIndex, int queryStart, int queryEnd, int current)
{
if (queryStart <= startIndex && queryEnd >= endIndex)
{
return tree[current];
}
if (endIndex < queryStart || startIndex > queryEnd)
{
return 0;
}
int mid = mid(startIndex, endIndex);
return getSumUtil(startIndex, mid, queryStart, queryEnd, leftchild(current))
+ getSumUtil( mid + 1, endIndex, queryStart, queryEnd, rightchild(current));
}
public int getSum(int queryStart, int queryEnd)
{
if(queryStart < 0 || queryEnd > tree.length)
{
return -1;
}
return getSumUtil(STARTINDEX, ENDINDEX, queryStart, queryEnd, ROOT);
}
private int constructSegmentTreeUtil(int startIndex, int endIndex, int current)
{
if (startIndex == endIndex)
{
tree[current] = elems[startIndex];
return tree[current];
}
int mid = mid(startIndex, endIndex);
tree[current] = constructSegmentTreeUtil(startIndex, mid, leftchild(current))
+ constructSegmentTreeUtil(mid + 1, endIndex, rightchild(current));
return tree[current];
}
public void constructSegmentTree()
{
constructSegmentTreeUtil(STARTINDEX, ENDINDEX, ROOT);
}
public static void main(String[]args) throws IOException
{
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer str = new StringTokenizer(buf.readLine());
int n = Integer.parseInt(str.nextToken());
int q = Integer.parseInt(str.nextToken());
SegmentTree segmentTree = new SegmentTree(n);
int elements[] = new int[n];
for(int i = 0; i < n; i++) {
elements[i] = 0;
}
elems = elements;
segmentTree.constructSegmentTree();
while (q-- > 0) {
str = new StringTokenizer(buf.readLine());
int x = Integer.parseInt(str.nextToken());
int a = Integer.parseInt(str.nextToken());
int b = Integer.parseInt(str.nextToken());
if(x == 0) {
for(int j = a; j <= b; j++)
{
elems[j] = elems[j]^1;
}
segmentTree.constructSegmentTree();
}
else {
int num = segmentTree.getSum(a, b);
System.out.println(num);
}
}
}
}
EDIT:
According to GeeksForGeeks, tree construction costs O(n) and the update method is O(log n). So here are the new methods for update:
private void updateTreeUtil(int startIndex, int endIndex, int updatePos, int update, int current)
{
if ( updatePos < startIndex || updatePos > endIndex)
{
return;
}
tree[current] = tree[current] + update;
if (startIndex != endIndex)
{
int mid = mid(startIndex, endIndex);
updateTreeUtil(startIndex, mid, updatePos, update, leftchild(current));
updateTreeUtil(mid+1, endIndex, updatePos, update, rightchild(current));
}
}
public void update(int update, int updatePos)
{
int updatediff = update - elems[updatePos];
elems[updatePos] = update;
updateTreeUtil(STARTINDEX, ENDINDEX, updatePos, updatediff, ROOT);
}
And now the if loop in main method modified to this:
if(x == 0) {
for(int j = a; j <= b; j++)
{
segmentTree.update(elems[j]^1, j);
}
}
But still getting TLE error.
In the tutorial of GeeksForGeeks, their running time of update is O(log n), in case of updating a single element. However, when doing update for an interval, you have to use Lazy Propagation to ensure O(log n) update time, which is basically only update nodes which are visited, and hence ensure the sum of visited nodes are correct. You may search for many good tutorial on Lazy Propagation, for example:
http://se7so.blogspot.hk/2012/12/segment-trees-and-lazy-propagation.html
Wish that helps.

Categories