the output of my Interpolation search is wrong, why? - java

I have to write a Program which is called "Interpolation search". I came so far but now I am stuck and can´t find the error in my code.
The method split() makes a problem. This method should give me the index to split. I just typed the formula in this method. Now the big problem is, I every time get 1 as an output which is always the "leftBoundary". For example, I write in my terminal java Search 4 1 2 3 4 5 6 then I get every time 1. Why? what is wrong?
edit:
I was asked to explain what the split method does in Detail:
This method uses the formula (look at added picture) to determine where to split the (sorted) array and returns the corresponding index.
In the picture: v = wantedValue, l = leftBoundary, r = rightBoundary
enter image description here
import java.util.Scanner;
public class Search {
// This method uses the formula (look at added picture) to determine where to split the (sorted) array and returns the corresponding index.
private static int split(int[] haystack, int needle, int left, int right) {
if(haystack[right] == haystack[left]) {
return left;
}else {
needle = left + ((needle - haystack[left]) / (haystack[right] - haystack[left])) * (right - left);
return needle;
}
}
private static int search(int[] haystack, int needle) {
return -1;
}
public static void main(String[] args) {
int[] array = new int[args.length];
int leftBoundary = 1;
int rightBoundary = array.length - 1;
int wantedValue = Integer.parseInt(args[0]);
for(int i = 1; i < args.length; i++) {
array[i] = Integer.parseInt(args[i]);
}
int splitAtIndex = split(array, wantedValue, leftBoundary, rightBoundary);
System.out.println(splitAtIndex);
}
}
I tried to debug but with no success and also searched here on stackoverflow. Many have question to interpolation search, but the answers are complex and unfortunately do not explain the exact problem I have

Apart from the comment, by #user16320675, to your question, your initialization is wrong.
The first [command-line] argument is the value of wantedValue. The remaining [command-line] arguments are the elements of array.
Also, leftBoundary should be 0 (zero) and not 1 (one) since you probably want to search the whole array.
Consider the following code:
public class Search {
private static int split(int[] haystack, int needle, int left, int right) {
if (haystack[right] == haystack[left]) {
return left;
}
else {
return (int) (left + ((double) (needle - haystack[left]) / (haystack[right] - haystack[left])) * (right - left));
}
}
public static void main(String[] args) {
int[] array = new int[args.length - 1];
int leftBoundary = 0;
int rightBoundary = array.length - 1;
int wantedValue = Integer.parseInt(args[0]);
for (int i = 1; i < args.length; i++) {
array[i - 1] = Integer.parseInt(args[i]);
}
int splitAtIndex = split(array, wantedValue, leftBoundary, rightBoundary);
System.out.println(splitAtIndex);
}
}
I removed the import statement since Scanner is not used. I also removed method search since it is never called.
If I run the above code using your example [command-line] arguments, i.e.
4 1 2 3 4 5 6
then method search returns 3 — which is the index of the searched-for element in the array since 4 is the searched-for value and the array contains the numbers 1 to 6 (inclusive).
Of-course, the array being searched must be sorted.
Note that if the searched-for value is smaller than the first array element, i.e. the element at index 0 (zero), method search will return -1 (minus one) and if the searched-for value is greater than the last element in the array, method search will return the array length. Hence you can determine whether the searched-for value is not found in the array.
If the [command-line] arguments are:
4 1 2 3 5 6
then method search returns 2. Note that the searched-for value, i.e. 4, is not in the array.
It is probably also a good idea to check the parameters of method search, i.e. that right should not be less than left and that haystack contains at least one element.

Related

Optimize the given Solution without changing the logic of the program. Also calculate the Time Complexity

This is a GFG practice problem hence compiler cannot be configured
Question
Given an array of positive integers. Your task is to find the leaders in the array.
Note: An element of array is leader if it is greater than or equal to all the elements to its right side. Also, the rightmost element is always a leader.
Input:
The first line of input contains an integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains a single integer N denoting the size of array.
The second line contains N space-separated integers A1, A2, ..., AN denoting the elements of the array.
Output:
Print all the leaders.
Constraints:
1 <= T <= 100
1 <= N <= 107
0 <= Ai <= 107
My Solution :
import java.util.*;
import java.io.*;
import java.lang.*;
public class Main
{
static BufferedReader z1 = new BufferedReader(new InputStreamReader(System.in));
public static void main (String[] args)throws Exception
{
int T=Integer.parseInt(z1.readLine());
while(T-- > 0)
{
int N=Integer.parseInt(z1.readLine());
solution ob = new solution();
int []a=new int[N];
a=ob.input(N,z1);
int x=0;
ob.leader(a,N,x);
}
}
}
class solution
{
static int[] input(int N, BufferedReader z1)throws Exception
{
int a[]=new int[N];
String s=z1.readLine();
String []str=s.split(" ");
/* for(int y=0;y<N;y++)
a[y]=Integer.parseInt(str[y]); */
toInts(str,a,0);
return a;
}
static void toInts(String[] strings, int[] ints, int start) {
if (start > strings.length - 1) {
return;
}
ints[start] = Integer.parseInt(strings[start]);
toInts(strings, ints, start+1);
}
static void leader(int []a,int N,int x)
{
int count = 0;
if(x==N-1)
System.out.println(a[x]);
else
{
count = compare(a,x,x+1,count,N);
/* for(int y=x+1;y<N;y++)
if(a[x]>=a[y])
count++; */
if(count==(N-x-1))
System.out.print(a[x]);
leader(a,N,x+1);
}
}
static int compare(int []a,int x,int y,int count,int N)
{
if(y==N)
return count;
else
{
if(a[x]>=a[y])
count ++;
return compare(a,x,y+1,count,N);
}
}
}
Error :
Runtime Error:
Runtime ErrorTime Limit Exceeded
Your program took more time than expected.Time Limit Exceeded
Expected Time Limit 3.00sec
A problem (and the likely cause for the long time it takes) is that your compare() method doesn't stop once it encounters a larger value and it is therefore obvious that the current element is not a leader. Instead it will always compare all values.
This makes the runtime of your code O(N^2) for an array of size N.
This problem can be solved in O(N).
Start on the right end of the array and print the last element as leader and set it as the current maximum. Then go left and check if the current element is greater or equal than the maximum. If yes print it as a leader and set is as the maximum. Continue until you reach the left end of the array.
You can also probably save some time by replacing your recursive toInts() method with a simple for-loop to convert the strings.

Java - Trying to print all of the coincidences of a binary search

This is my current search method:
public static int search(int[] array, int numero) {
int start = 0;
int end = array.length - 1;
int center;
while (start <= end) {
center = (start + end) / 2;
if (array[center] == numero) {
return center;
} else if (array[center] < numero) {
start = center + 1;
} else {
end = center - 1;
}
}
return -1;
}
It searches from user input numero into a previously bubble sorted Array that's found in the Main method.
What I'm trying to figure out is how to print ALL of the coincidences found in the array, and not just the first one found.
I was thinking about adding results to a List and then returning that to Main, but as I tried that an endless loop happened at the first result found, causing it to add itself to the List repeatedly until the program crashes.
Assuming that you know the basic theory behind binary searches, separate it into 3 steps.
Search using binary search methods.
once a match is found, scan up from that point, until you find a non matching element.
Scan down, adding to a result list, until you find a non
matching element.
If you don't need to care about occurrence order, you could combine steps 2 and 3 and just scan up adding to the list, and scan down adding to the list, since due to the sorting, everything you hit is guaranteed to match until it doesn't.
If you do care about occurrence order, step 2 could be optimised by jumping ahead and checking, and writing a modified binary search that searches for a transition of matching/notmatching instead of a match.
This could be further optimised by keeping statistics or profiling, to find the perfect jump distance, or basing it off of the last up-most check.
actually it's easy because the list is already sorted, the numbers you expect to find are adjacent.
just like Ryan's answer, I'll put some code
public static List<Integer> searchAll (int[] array, int numero){
int firstMatchIndex = search( array, numero);
List<Integer> results = new ArrayList<Integer>():
results.add(firstMatchIndex);
boolean left = true;
while( left){
int i = firstMatchIndex - 1;
if(i<0 || array[i] != numero){
left = false;
}else{
results.add(i);
}
}
boolean right = true;
while( right){
int i = firstMatchIndex + 1;
if(i>array.length || array[i] != numero){
right = false;
}else{
results.add(i);
}
}
}

Finding the largest element in an array using recursion in Java

This is what I have so far, but I'm confused on how to keep track of the index. I would change the parameters of the method, but I'm not allowed.
I can only use a loop to make another array. Those are the restrictions.
public class RecursiveFinder {
static int checkedIndex = 0;
static int largest = 0;
public static int largestElement(int[] start){
int length = start.length;
if(start[length-1] > largest){
largest = start[length-1];
int[] newArray = Arrays.copyOf(start, length-1);
largestElement(newArray);
}
else{
return largest;
}
}
/**
* #param args
*/
public static void main(String[] args) {
int[] array1 = {0,3,3643,25,252,25232,3534,25,25235,2523,2426548,765836,7475,35,547,636,367,364,355,2,5,5,5,535};
System.out.println(largestElement(array1));
int[] array2 = {1,2,3,4,5,6,7,8,9};
System.out.println(largestElement(array2));
}
}
Recursive method doesn't need to keep the largest value inside.
2 parameters method
Start to call with:
largestElement(array, array.length-1)
Here is the method:
public static int largestElement(int[] start, int index) {
if (index>0) {
return Math.max(start[index], largestElement(start, index-1))
} else {
return start[0];
}
}
The 3rd line of method is the hardest one to understand. It returns one of two elements, larges of the one of current index and of remaining elements to be checked recursively.
The condition if (index>0) is similar to while-loop. The function is called as long as the index remains positive (reaches elements in the array).
1 parameter method
This one is a bit tricky, because you have to pass the smaller array than in the previous iteration.
public static int largestElement(int[] start) {
if (start.length == 1) {
return start[0];
}
int max = largestElement(Arrays.copyOfRange(start, 1, start.length));
return start[0] > max ? start[0] : max;
}
I hope you do this for the study purposes, actually noone has a need do this in Java.
Try that for the upper class, leave the main method it's is correct.
public class dammm {
public static int largestElement(int[] start){
int largest = start[0];
for(int i = 0; i<start.length; i++) {
if(start[i] > largest){
largest = start[i];
}
}return largest;
}
If your goal is to achieve this by using recursion, this is the code that you need. It is not the most efficient and it is not the best way to deal with the problem but it is probably what you need.
public static int largestElement(int[] start){
int length = start.length;
if (start.lenght == 1){
return start[0];
} else {
int x = largestElement(Arrays.copyOf(start, length-1))
if (x > start[length-1]){
return x;
} else {
return start[length-1];
}
}
}
Imagine that you have a set of numbers you just have to compare one number with the rest of them.
For example, given the set {1,8,5} we just have to check if 5 is larger than the largest of {1,8}. In the same way you have to check if 8 is larger than the largest of {1}. In the next iteration, when the set one have one value, you know that that value is the bigger of the set.
So, you go back to the previous level and check if the returned value (1) is larger than 8. The result (8) is returned to the previous level and is checked against 5. The conclusion is that 8 is the larger value
One parameter, no copying. Tricky thing is, we need to pass a smaller array to the same method. So a global variable is required.
// Number of elements checked so far.
private static int current = -1;
// returns the largest element.
// current should be -1 when user calls this method.
public static int largestElement(int[] array) {
if (array.length > 0) {
boolean resetCurrent = false;
if (current == -1) {
// Initialization
current = 0;
resetCurrent = true;
} else if (current >= array.length - 1) {
// Base case
return array[array.length - 1];
}
try {
int i = current++;
return Math.max(array[i], largestElement(array));
} finally {
if (resetCurrent) {
current = -1;
}
}
}
throw new IllegalArgumentException("Input array is empty.");
}
If you can create another method, everything would be much simpler.
private static int recursiveFindLargest(int [] array, int i) {
if (i > 0) {
return Math.max(array[i], recursiveFindLargest(array, i-1));
} else {
return array[0];
}
}
public static int largestElement(int [] array) {
// For empty array, we cannot return a value to indicate this situation,
//all integer values are possible for non-empty arrays.
if (array.length == 0) throw new IllegalArgumentException();
return recursiveFindLargest(array, array.length - 1);
}
For this problem you really need to think about working with the base case. Take a look at some of the simple cases you would have to deal with:
If the array is length 1, then you return the only value
If the array is length 2, then you return the maximum of the two values
If the array is length 3, then ?
From the above we can get an idea of the structure of the problem:
if array.length == 1 then
return array[0]
else
return the maximum of the values
In the above if we have only one element, it is the maximum value in the list. If we have two values, then we have to find the maximum of those values. From this, we can then use the idea that if we have three values, we can find the maximum of two of them, then compare the maximum with the third value. Expanding this into pseudo code, we can get something like:
if array.length == 1 then
return array[0]
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
return maximum(array[0], largestElement(new array))
To explain the above a little better, think of execution like a chain (example for {1, 2, 3}).
Array: {1, 2, 3}, maximum(array[0] = 1, largestElement(new array = {2, 3}))
Array: {2, 3}, maximum(array[0] = 2, largestElement(new array = {3}))
Array: {3}, array[0] = 3 => length is 1 so return 3
The above then rolls back up the 'tree' structure where we get:
maximum (1, maximum(2, (return 3)))
Once you have the maximum value, you can use the sample principle as above to find the index with a separate method:
indexOf(array, maximum)
if array[0] == maximum then
return 0
else if array.length == 1 then
return -1
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
result = indexOf(new array, maximum)
return (result == -1) ? result : result + 1
For looking into this more, I would read this from the Racket language. In essence it shows the idea of array made purely from pairs and how you can use recursion to do iteration on it.
If you are interested, Racket is a pretty good resource for understanding recursion. You can check out University of Waterloo tutorial on Racket. It can give you a brief introduction to recursion in an easy to understand way, as well as walking you through some examples to understand it better.
You don't need to keep a largest variable outside your method - that's generally not a good practice with recursion which should return all context of the results.
When you think about recursion try to think in terms of a simple base case where the answer is obvious and then, for all other cases how to break it down into a simpler case.
So in pseduo-code your algorithm should be something like:
func largest(int[] array)
if array has 1 element
return that element
else
return the larger of the first element and the result of calling largest(remaining elements)
You could use Math.max for the 'larger' calculation.
It's unfortunate that you can't change the arguments as it would be easier if you could pass the index to start at or use lists and sublists. But your copying method should work fine (assuming efficiency isn't a concern).
An alternative to the algorithm above is to make an empty array the base case. This has the advantage of coping with empty arrays (by return Integer.MIN_VALUE):
int largest(int[] array) {
return array.length == 0
? Integer.MIN_VALUE
: Math.max(array[0], largest(Arrays.copyOfRange(array, 1, array.length)));
}
Here is working example of code with one method param
public int max(int[] list) {
if (list.length == 2) return Math.max(list[0], list[1]);
int max = max(Arrays.copyOfRange(list, 1, list.length));
return list[0] < max ? max : list[0];
}
private static int maxNumber(int[] arr,int n,int max){
if(n<0){
return max;
}
max = Math.max(arr[n],max);
return maxNumber(arr,n-1,max);
}

Retrieving specific combinations

Given an Integer set, {x | 1 <= x <= n}. Consider a combination, something like 50C6 (select 6 from 50). Calculating the number of combinations and iterating over them (in sorted order) is easy.
For example, this does the trick:
public static void combo(int[] combo, int index, int f, int t) {
if (index >= combo.length) {
// display combination
// ...
return;
}
for (int i = f; i <= t - (combo.length - index) + 1; i++) {
combo[index] = i;
combo(combo, index + 1, i + 1, t);
}
}
For the above, calling combo(new int[]{0, 0, 0, 0}, 0, 1, 9) will list all the 9C4 combinations in sorted order, all 126 of them.
What I would like is the following. Given k, I'd like the algorithm to give the combination.
// Select r from c and return combination k.
public static int[] combo(int c, int r, int k) {
}
For example, combo(3,2,1) should return {1,2} and combo(3,2,3) should return {2,3} (assuming the first combination is 1 and not 0 - but that's trivial).
Doing this in O(nCr) is easy and takes little memory... Doing it in O(1) is also easy, but is requires lots of memory for larger combinations and requires pre-calculation. I don't know whether it's possible to do this in better time than O(nCr) without using a lookup table. Any confirmation/guidance would be appreciated.
Okay, I've worked it out and I am quite happy with the final result. The basic idea is as follows:
Let's say we want the k'th entry of nCr. Then, the number of combinations where we start with a 1 is (n-1)C(r-1) and a 2 is (n-2)C(r-2), etc. So, all you have to do is find out which digit needs to go at the first spot and then repeat the process for every one of the r spots.
For example, let's say we want the 30'th entry of 9C3. For 1, we have 8C2 = 28. That's not enough. For 2, 7C2 = 21. So, the first digit must be a 2 and the first entry that started with a 2 was entry 29. So now you simply repeat this process for the second and third entry.
The non-recursive solution is as follows:
public static int[] getCombo(int n, int r, int k) {
int[] result = new int[r];
int cur = 1;
int sum =0;
while (r > 0) {
int tot = c(n - cur, r - 1);
if (sum + tot < k) {
sum += tot;
cur++;
} else {
result[result.length - r] = cur++;
r--;
}
}
return result;
}
The function c() above, simply calculates "n select r".
I particularly like this as it is O(r).
So you can find the value of nCp by the equation n!/(p!*(n-p)!). So say you're solving 4C3 and you're looking for the kth combo. If the first value is a 1 then that means that you have 3C2 left which calculates to 3. So if k < 3 the first value is a 1. If not you go to 3C2 + 3C1 for the second value. And you recuse down the line. No sure if it's actually faster (the calculation of nCp) but it's an interesting way to think about the problem.

Can this be done Recursively?

So me and my friend tried to code this little game when we were children called LOVERS..
Wherein you write down the name of 2 persons,Whole name without the middle name,and count the number of L's,O's,V's,E's,R's,and S's in the name, add it together and put beside the letters.
Sample:
name 1: Hello
name 2: Care
L: 2
O: 1
V: 0
E: 2
R: 1
S: 0
afterwards you will add them in pairs.
Sample:
L: 2 > 3 > 4 > 7 > 15 > 32
O: 1 > 1 > 3 > 8 > 17
V: 0 > 2 > 5 > 9
E: 2 > 3 > 4
R: 1 > 1
S: 0
here's how it goes...first you add the values of the first 2 letters...LO then OV then VE and so on and so forth. until you get one final answer in this case 32....the 32 signifies the percentage in which the 2 people is Compatible with each other.
i know its quite stupid. haha but we just tried to program it for fun. we are 2nd year IT Students here in the philppines. anyway we were wondering if there's a way to do the calculation RECURSIVELY and if there's a way to reduce the number of Arrays used.
Here's our code:
import java.util.*;
public class LOVERS {
static Scanner console = new Scanner(System.in);
public static void main(String[] args) {
String name1="";
String name2="";
char love[] = {'L','O','V','E','R','S'};
int[] lovers = new int[6];
int[] temp= new int[6];
int[] temp2= new int[6];
boolean done = true;
while(done){
name1 = getName();
name2 = getName();
temp = getLetterCount(name1);
temp2 = getLetterCount(name2);
lovers = sumOfLetters(temp,temp2,love);
System.out.println("");
int[] firstLayer = new int[5];
int[] secondLayer = new int[4];
int[] thirdLayer = new int[3];
int[] fourthLayer = new int[2];
firstLayer = sums(lovers);
secondLayer = sums(firstLayer);
thirdLayer = sums(secondLayer);
fourthLayer = sums(thirdLayer);
int output = fourthLayer[0]+fourthLayer[1];
if(output>100){
output=100;
}
System.out.println("Result is : "+ output +"%");
System.out.println("Do you want to try again? Y/N :");
char again = ' ';
if(again == 'n')
{
done = false;
}
else done = true;
}
}
public static int[] sums (int[] y){
int[] x = new int[y.length-1];
for(int ctr=1;ctr<y.length;ctr++){
x[ctr-1]=y[ctr-1]+y[ctr];
}
return x;
}
public static String getName(){
String n="";
System.out.println("Enter name: ");
n = console.nextLine();
n = n.toUpperCase();
return n;
}
public static int[] sumOfLetters(int[] temp, int[] temp2, char[] love){
int[] lovers = new int[6];
for(int ctr=0;ctr<6;ctr++){
lovers[ctr]=temp[ctr]+temp2[ctr];
System.out.println(love[ctr]+" - "+lovers[ctr]);
}
return lovers;
}
public static int[] getLetterCount(String n){
int[] temp = new int[6];
for(int x=0;x<n.length();x++){
if(n.charAt(x)=='L'){
temp[0]++;
}
else if(n.charAt(x)=='O'){
temp[1]++;
}
else if(n.charAt(x)=='V'){
temp[2]++;
}
else if(n.charAt(x)=='E'){
temp[3]++;
}
else if(n.charAt(x)=='R'){
temp[4]++;
}
else if(n.charAt(x)=='S'){
temp[5]++;
}
}
return temp;
}
}
as you can see we used 4 arrays for the 4 layers of calculation and we used a looping statement for the calculation.
So can this be done RECURSIVELY? and How can we reduce the number of arrays used?
this can help us greatly in learning how to do proper Recursive functions since we are currently learning Data Structures. hope you guys can help me. thanks
Yes, of course you can code it recursively.
First of all, your sum-fn. Instead of going through the string byte for byte, you can pass the string to the same function over and over again, just removing one character each time. That character will be added to your result-number. Your final-check will be that the string is empty, then you return null. Evaluation will go back up the recursion, potentially adding 1 (or 0 otherwise) for each character in the string.
For clearer, more readable code you should use enums instead of byte-arrays for storing your ints.
Also, instead of static functions, make it a class in which you can access the attributes.
For the summation of the 6 chars, each level does the same operation on it. So each function call should do that addition and return the result being called in the function again. Your final-check is that only the first integer value positive. If all the other values are 0 the first one holds your sum.
Yes, you can do it recursively:
public static int L(int i) {
return (i == 0) ? LVAL : L(i - 1) + O(i - 1);
}
public static int O(int i) {
return (i == 0) ? OVAL : O(i - 1) + V(i - 1);
}
public static int V(int i) {
return (i == 0) ? VVAL : V(i - 1) + E(i - 1);
}
public static int E(int i) {
return (i == 0) ? EVAL : E(i - 1) + R(i - 1);
}
public static int R(int i) {
return (i == 0) ? RVAL : R(i - 1) + SVAL;
}
Calling L(5) gives you the answer.
Actually the problem here is one instance of a much more general class of problems/algorithms which are incidentally quite important in some fields nobody would believe from this example ;)
Basically you can regard your triangle above as a matrix. Ie the second number in the L row (the 3) would be (0,1), 3rd value in the E row would be (3,2). If you look at it you see that every value except the start values depend on exactly two other nodes, which makes this a 2-point stencil. There are some extremely intriguing algorithms out there for this kind of problem - eg a cache oblivious, parallel algorithm for higher-order stencils (LBMHD uses 13-points or something).
Anyways that stuff is completely out of your league I fear (don't ask me about details either~) - there are even more or less recent papers about this ;)
PS: And my personal small implementation. Can't get much simpler and has the typical structure
of a simple recursive program. You call it with getVal(0, 5); or more generally getVal(0, startVals.length - 1). Just think about it as working backwards from the solution to the start. We want to know what the right field in the first row has. To get this we need to know two the values of two other fields which we have to compute first in the same manner. This is done until we get to a field where we already know the result - ie our start values.
private int[] startVals; // contains start values for all 6 letters.
// for your example startVals[0] == 2; startVals[5] == 0
public int getVal(int row, int col) {
if (col == 0) return startVals[row];
return getVal(row, col-1) + getVal(row + 1, col - 1);
}

Categories

Resources