I want to implement a recursive method that finds the sum of x consecutive integers, starting from a starting number and ending with an end number.
For example, if start = 0 and end = 3, the method returns 6 (0+1+2+3). I tried to come up with the right code but I'm new to recursion and I couldn't find the right base case.
public static int summation(int start, int end) {
if (start == end) {
return 0;
}
else {
return summation(end, end - 1);
}
}
This works but make sure that start is less than end.
public static int summation(int start, int end) {
if(start < end) return start + summation(start + 1, end);
else return end;
}
If you want to use the method to calculate sum between start and end even if start > end, then use this code:
public static int summation(int start, int end) {
if(start < end) return start + summation(start + 1, end);
else if(start > end) {
start += end;
end = start - end;
start -= end;
return summation(start, end);
}
else return end;
}
If recursion is not compulsory, you can use the formula for sum of Arithmetic Progression which you learn in HighSchool Algebra.
Formula for Sum of an AP is
S = n/2 * (2a + (n-1) * d)
In your case as you have to find the sum of consequetive terms, this formula simplifies to:
S = n/2 * (2a + n -1 )
Here, a is the starting term and n is the x consequetive integers from start to end.
public long sum(int start, int end) {
int n = end - start + 1;
return n/2 * (2L * start + n - 1);
}
Works even if start and end are negative. Just make sure start < end.
Recursion is a terrible approach here. Let's apply the method Gauss used in elementary school, the sum of the numbers 1 to n is found by taking of half of n multiplied by n + 1. Like,
private static long sumN(int n) {
return ((1L + n) * n) / 2;
}
Then you can use that to find summation like
private static long summation(int start, int end) {
return sumN(end) - sumN(start);
}
No recursion (or iteration) required.
Related
I need to count the number of numbers on the right that are less than the number arr[i]. My problem is that the stack overflows at large sizes and I can't solve it in any way. Please tell me how can I refactor my code to avoid the error StackOverflow ?
public class Smaller {
public static int[] smaller(int[] unsorted) {
int[] result = new int[unsorted.length];
for (int i = 0; i < unsorted.length; i++) {
result[i] = countSmaller(unsorted[i], 0, i + 1, unsorted);
}
return result;
}
private static int countSmaller(int currentNumber, int count, int index, int[] arr) {
if (index >= arr.length) {
return count;
}
return arr[index] < currentNumber
? countSmaller(currentNumber, count + 1, index + 1, arr)
: countSmaller(currentNumber, count, index + 1, arr);
}
}
I agree with comments questioning whether recursion is your best solution here, but if it's a requirement you can avoid stack overflow by chopping subproblems in half rather than whittling them down one-by-one. The logic is that the count in the remaining data will be the sum of the count in the first half plus the count in the second half of the remaining data. This reduces the stack growth from O(n) to O(log n).
I originally did a Python implementation due to not having a Java compiler installed (plus my Java skills being rusty), but found an online java compiler at tutorialspoint.com. Here's an implementation of the divide and conquer logic described in the previous paragraph:
public class Smaller {
public static int[] smaller(int[] unsorted) {
int[] result = new int[unsorted.length];
for (int i = 0; i < unsorted.length; i++) {
result[i] = countSmaller(unsorted[i], i+1, unsorted.length-1, unsorted);
}
return result;
}
private static int countSmaller(int threshold, int start, int end, int[] unsorted) {
if (start < end) {
int mid = start + (end - start) / 2;
int count = countSmaller(threshold, start, mid, unsorted);
count += countSmaller(threshold, mid+1, end, unsorted);
return count;
} else if ((start == end) && (unsorted[start] < threshold)) {
return 1;
}
return 0;
}
}
With O(log n) stack growth, this should be able to handle ridonculously big arrays. Since the algorithm as a whole is O(n2), run time will limit you long before recursive stack limitations will.
Original Python Implementation
Sorry for showing this in Python, but I don't have a Java compiler and I didn't want to risk non-functioning code. The following does the trick and should be easy for you to translate:
def smaller(unsorted):
result = []
for i in range(len(unsorted)):
result.append(countSmaller(unsorted[i], i+1, len(unsorted)-1, unsorted))
return result
def countSmaller(threshold, start, end, unsorted):
if start < end:
mid = start + (end - start) // 2 # double slash is integer division
count = countSmaller(threshold, start, mid, unsorted)
count += countSmaller(threshold, mid+1, end, unsorted)
return count
elif start == end and unsorted[start] < threshold:
return 1
return 0
data = [10, 9, 8, 11, 7, 6]
print(smaller(data)) # [4, 3, 2, 2, 1, 0]
print(smaller([])) # []
print(smaller([42])) # [0]
I am practicing a sorted search task, from testdome.com
/**
* Implement function countNumbers that accepts a sorted array of unique integers and,
* efficiently with respect to time used, counts the number of array elements that are less than the parameter lessThan.
* <p>
* For example, SortedSearch.countNumbers(new int[] { 1, 3, 5, 7 }, 4)
* should return 2 because there are two array elements less than 4.
*/
Currently according to the site my answer has a score of 50 % due to edge cases and performance, im trying to get an opinion on what i might need to add or a different approach.
Here is my code
public static int countNumbers(int[] sortedArray, int lessThan) {
int count = 0;
if(sortedArray == null) {
return 0;
}
List<Integer> numbers = new ArrayList<>();
for (int i = 0; i < sortedArray.length; i++) {
if (sortedArray[i] < lessThan) {
count++;
} else {
break;
}
}
return count;
}
And the result i get when i test it on their environment is as follows
Example case: Correct answer
Various small arrays: Correct answer
Performance test when sortedArray contains lessThan: Time limit exceeded
Performance test when sortedArray doesn't contain lessThan: Time limit exceeded
so two performance tests fail even though i cant see this tests may be i could get a suggestion here
If O(n) is giving TLE. You need something faster than O(n). Binary Search is O(logN).
public static int countNumbers(int[] sortedArray, int lessThan) {
int start = 0;
int end = sortedArray.length - 1;
int mid = 0;
while (start <= end) {
mid = start + (end - start) / 2;
if (sortedArray[mid] < lessThan) {
if (mid < sortedArray.length - 1 && sortedArray[mid + 1] < lessThan) {
start = mid + 1;
continue;
} else {
return mid + 1;
}
}
if (sortedArray[mid] >= lessThan) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return 0;
}
Or use built-in Binary Search:
Arrays.binarySearch(new int[]{1, 2, 4}, 3) + 1) * -1;
When the key is not found, it returns negative insertion position. To convert it to index, I did + 1 and multiplied by - 1 to make it positive.
I just learned about the Binary Search algorithm and I tried to implement it. I have used a few test cases and it seems to work fine. However, when I checked on GeeksforGeeks, there are quite a few differences in the way they handled the indexing. Can anyone shed some lights on whether my implementation is good or not. And if not, how would it fail to work?
Here's my code:
static int binarySearch(int arr[], int i, int r, int x) {
if(r > 1) {
int middle = r/2;
if(arr[middle] == x) {
return middle;
}
if(arr[middle] > x) {
return binarySearch(arr, i, middle, x);
}else {
return binarySearch(arr, middle, r+1, x);
}
}
return -1;
}
Suppose that our function is going to do a binary search on the subarray arr[l..r] (inclusive). Here, r - l + 1 is the length of this subarray and when it's not a positive number (or r < l), we don't have a valid subarray and we can't search for anything, so the function stops the recursion and returns -1.
You know, we always make two subarrays with (almost) equal length. So, middle = r/2 is not correct and middle = (l + r) / 2 is correct. The new subarrays are arr[l..middle-1] and arr[middle+1..r]. We divide the subarray after checking its middle element, so these two subarrays should not contain the middle index as you see.
Now, we can rewrite your code.
static int binarySearch(int arr[], int l, int r, int x) {
if (r >= l) {
int middle = (l + r) / 2; //int middle = l + (r - l) / 2; for avoiding integer overflow
if(arr[middle] == x)
return middle;
if (arr[middle] > x)
return binarySearch(arr, l, middle - 1, x);
else
return binarySearch(arr, middle + 1, r, x);
}
return -1;
}
And this is a non-recursive version of binary search algorithm. Usually, it can work slightly faster.
static int binarySearch2(int arr[], int l, int r, int x) {
while (r >= l) {
int middle = (l + r) / 2; //int middle = l + (r - l) / 2; for avoiding integer overflow
if (arr[middle] == x)
return middle;
if (arr[middle] > x)
r = middle - 1;
else
l = middle + 1;
}
return -1;
}
Don't forget to sort your array before calling these functions.
Suppose that n is the length of the given array.
For 0-based arrays, the correct form of calling the functions is this:
binarySearch(arr, 0, n - 1, x);
and
binarySearch2(arr, 0, n - 1, x);
For 1-based arrays, the correct form of calling the functions is this:
binarySearch(arr, 1, n, x);
and
binarySearch2(arr, 1, n, x);
A simple way of solving my problem would be the following method:
public int sum(int num)
{
if(num == 1)
return 1;
else
return num + sum(num - 1);
}
My problem starts when I try to solve the same problem using the following recursive definition:
"The sum of 1 to N is the sum of 1 to N/2 plus the sum of N/2 + 1 to N".
I tried the following but I'm stuck in an infinite loop...
public int sum(int max, int base)
{
if(max == base)
return base;
else
return max/2 + sum(max/2 - 1, 1) + max + sum(max-1, max/2 + 1);
}
I can't seem to find a way forward...
You are close, try something like this
#Test
public void recursive(){
int number = 20;
System.out.println(sum(0, number));
System.out.println(sum(0, number/2));
System.out.println(sum(number/2 +1, number));
Assert.assertThat(sum(0, number), is(sum(0, number/2) + sum(number/2 +1, number)));
}
private int sum(int origin, int end) {
if(origin == end)
return end;
return origin + sum(origin+1, end);
}
Is it possible to count the number of comparisons made by a recursive binary search? If so, how?
Here is the search I am referring to:
//binary search
public static int binarySearch(int[] items, int start, int end, int goal)
{
if (start > end)
return (-1);
else
{
int mid = (start + end)/2;
if (goal == items[mid])
return (mid);
else
if (goal < items[mid])
return (binarySearch(items, start, mid - 1, goal));
else
return (binarySearch(items, mid + 1, end, goal));
}
}//end binarySearch
Declare your count variable outside of the method. Then add 1 each time that you call the method.
long count = 0;
//binary search
public static int binarySearch(int[] items, int start, int end, int goal)
{
count += 1
if (start > end)
return (-1);
else
{
int mid = (start + end)/2;
if (goal == items[mid])
return (mid);
else
if (goal < items[mid])
return (binarySearch(items, start, mid - 1, goal));
else
return (binarySearch(items, mid + 1, end, goal));
}
}//end binarySearch
Your most likely approach if you want to caller to be able to access the count is to pass in an accumulator into your binary search. In java 7 or less, AtomicLong may be a good choice (though it does have some overhead). In java 8, a LongAdder would also be good:
public static int binarySearch(int[] items, int start, int end, int goal, AtomicLong counter) {
}
and each time you do a comparison, you would just increment the count:
counter.incrementAndGet()
When you exit the search, the counter will contain the number of comparisons:
long count = counter.get()