I'm having trouble with this binary search algorithm. Here are explanations of the variables.
value: the number being searched within the array
values[]: the array that is being searched
n: number of elements in the array
high: highest element (by zero indexed position) of portion of the array being searched
low: lowest element (by zero indexed position) the portion of the array being searched
My problem isn't the recursion. The portion of the array being searched centers around "value" and conditions identified below are being met. the problem is that my if statements don't seem to be recognizing that they are. I know the conditions are being met because when I print out values[high], values[middle], and values[low] for each recursion it shows that they are.
int search(int value, int values[], int n, int high, int low)
{
if (n <= 0)
{
return 1;
}
int middle = (high + low) / 2;
///condition #1
if (value == values[middle])
{
return 0;
}
//conditions #2 and #3 (account for the maxes and mins of the array because the operation to find middle truncates)
else if ( values[middle]==values[low] || values[middle]==values[high])
{
return 0;
}
else if (value > values[middle])
{
low = middle;
search(value, values, n, high, low);
}
else if (value < values[middle])
{
high = middle;
search(value, values, n, high, low);
}
return 2;
}
What's wrong here?
Look closely at this code:
else if (value > values[middle])
{
low = middle;
search(value, values, n, high, low);
}
else if (value < values[middle])
{
high = middle;
search(value, values, n, high, low);
}
Notice that in these cases you call the search function recursively, but you don't do anything with the return value. This means that whatever value returned by search is discarded and the code continues on as usually, ultimately returning 2.
To fix this, add in these return statements:
else if (value > values[middle])
{
low = middle;
return search(value, values, n, high, low);
}
else if (value < values[middle])
{
high = middle;
return search(value, values, n, high, low);
}
Generally speaking, if you suspect that an if statement condition isn't firing, it's worth slowly stepping through things with a debugger. Doing so would likely lead you to notice that you were (1) calling the function recursively correctly but (2) returning and discarding the returned value.
There may be other issues with the code here, but this is certainly something that you're going to need to address.
Quoth cb3k
That seemed to make it work...what might the other problems be?
Here's your code with the minimal (necessary, but not sufficient) fix diagnosed by templatetypedef and a test harness.
#include <stdio.h>
static
int search(int value, int values[], int n, int high, int low)
{
if (n <= 0)
{
return 1;
}
int middle = (high + low) / 2;
///condition #1
if (value == values[middle])
{
return 0;
}
// conditions #2 and #3 (account for the maxes and mins of the array because the operation to find middle truncates)
else if (values[middle] == values[low] || values[middle] == values[high])
{
return 0;
}
else if (value > values[middle])
{
low = middle;
return search(value, values, n, high, low);
}
else if (value < values[middle])
{
high = middle;
return search(value, values, n, high, low);
}
return 2;
}
int main(void)
{
int data[15];
for (int i = 0; i < 15; i++)
data[i] = 2 * i + 1;
printf("Data:");
for (int i = 0; i < 15; i++)
printf("%3d", data[i]);
putchar('\n');
for (int i = -1; i < 2 * 15 + 3; i++)
printf("Search for %2d - result %d\n", i, search(i, data, 15, 14, 0));
return 0;
}
Here's the output:
Data: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
Search for -1 - result 0
Search for 0 - result 0
Search for 1 - result 0
Search for 2 - result 0
Search for 3 - result 0
Search for 4 - result 0
Search for 5 - result 0
Search for 6 - result 0
Search for 7 - result 0
Search for 8 - result 0
Search for 9 - result 0
Search for 10 - result 0
Search for 11 - result 0
Search for 12 - result 0
Search for 13 - result 0
Search for 14 - result 0
Search for 15 - result 0
Search for 16 - result 0
Search for 17 - result 0
Search for 18 - result 0
Search for 19 - result 0
Search for 20 - result 0
Search for 21 - result 0
Search for 22 - result 0
Search for 23 - result 0
Search for 24 - result 0
Search for 25 - result 0
Search for 26 - result 0
Search for 27 - result 0
Search for 28 - result 0
Search for 29 - result 0
Search for 30 - result 0
Search for 31 - result 0
Search for 32 - result 0
It is returning 0 regardless of whether the value sought is present in the array or not. This is incorrect behaviour.
You should take time out to study Programming Pearls by Jon Bentley. It covers a lot the basics of the testing of binary searches in a variety of forms — the test harness shown is a variant on what he describes. Also take the time to read
Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken. Maybe you should take reassurance that lots of other people have got binary search wrong over time. (IIRC, the first versions of binary search were published in the 1950s, but it wasn't until the early 1960s that a correct version was published — and then there's the Extra information from 2006, too.)
When I added a printf() in the block after else if (values[middle] == values[low] || values[middle] == values[high]), it printed on every search that should have failed. Note that the interface makes it hard to spot what's happening — it doesn't report where the element is found, just whether it is found. You can add the debugging and code changes necessary to deal with the residual problems. (Hint: that condition is probably not part of the solution. However, when you do remove it, the code goes into a permanent loop because you don't eliminate the value known not to be in the range from the range that you check recursively.)
This seems to work — note that return 2; is never executed (because the final else if is never false.
#include <stdio.h>
static
int search(int value, int values[], int n, int high, int low)
{
//if (n <= 0)
if (n <= 0 || high < low)
{
return 1;
}
int middle = (high + low) / 2;
///condition #1
if (value == values[middle])
{
return 0;
}
#if 0
// conditions #2 and #3 (account for the maxes and mins of the array because the operation to find middle truncates)
else if (values[middle] == values[low] || values[middle] == values[high])
{
//printf(" (#2 || #3) ");
return 0;
}
#endif
else if (value > values[middle])
{
//low = middle;
low = middle + 1;
return search(value, values, n, high, low);
}
else if (value < values[middle])
{
//high = middle;
high = middle - 1;
return search(value, values, n, high, low);
}
return 2;
}
int main(void)
{
int data[15];
for (int i = 0; i < 15; i++)
data[i] = 2 * i + 1;
printf("Data:");
for (int i = 0; i < 15; i++)
printf("%3d", data[i]);
putchar('\n');
for (int i = -1; i < 2 * 15 + 3; i++)
printf("Search for %2d - result %d\n", i, search(i, data, 15, 14, 0));
return 0;
}
Output:
Data: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29
Search for -1 - result 1
Search for 0 - result 1
Search for 1 - result 0
Search for 2 - result 1
Search for 3 - result 0
Search for 4 - result 1
Search for 5 - result 0
Search for 6 - result 1
Search for 7 - result 0
Search for 8 - result 1
Search for 9 - result 0
Search for 10 - result 1
Search for 11 - result 0
Search for 12 - result 1
Search for 13 - result 0
Search for 14 - result 1
Search for 15 - result 0
Search for 16 - result 1
Search for 17 - result 0
Search for 18 - result 1
Search for 19 - result 0
Search for 20 - result 1
Search for 21 - result 0
Search for 22 - result 1
Search for 23 - result 0
Search for 24 - result 1
Search for 25 - result 0
Search for 26 - result 1
Search for 27 - result 0
Search for 28 - result 1
Search for 29 - result 0
Search for 30 - result 1
Search for 31 - result 1
Search for 32 - result 1
Related
I have to complete the function prime in order to the function main generate all prime numbers in a range specified by the user, but when I run the code specifying 1 as minimum and 100 as maximum it returns 1 with all the prime numbers.
How can I get rid of 1, once, by definition, 1 is not a prime number?
#include <cs50.h>
#include <stdio.h>
bool prime(int number);
int main(void)
{
int min;
do
{
min = get_int("Minimum: ");
}
while (min < 1);
int max;
do
{
max = get_int("Maximum: ");
}
while (min >= max);
for (int i = min; i <= max; i++)
{
if (prime(i))
{
printf("%i\n", i);
}
}
}
bool prime(int number)
{
// TODO
int j;
for (j = 2; j <= number - 1; j++)
{
if (number % j == 0)
{
return false;
}
}
return number;
}
Minimum: 1
Maximum: 100
1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
I would say that the simplest solution would be to add a test at the beginning of your prime function to indicate that any value less than "2" would yield a "false" Boolean value. With that, here is a simple refactoring of the function.
bool prime(int number)
{
// TODO
if (number < 2) /* Exit gracefully if a minimum value of 1 or less is entered */
{
return false;
}
int j;
for (j = 2; j <= number - 1; j++)
{
if (number % j == 0)
{
return false;
}
}
return true; /* Technically returning a value greater than zero will equate to true, but it is better to return "true" */
}
Also, note the revision of the final return statement in the function. Technically, any integer value greater than zero will be treated as a Boolean "true" value, it would be best to return the Boolean "true" value there so to be clear to anyone reading the code.
See if that meets the spirit of your project.
I am working on a problem that finds 'count' odd numbers below the int value 'bound' and adds up to an int value sum. It is suggested that I use recursion to solve.
I have completed the recursion and have made it solve 7 / 8 cases in mimir. There is one case that is showing a fail but I cannot figure out what is wrong even when stepping through with gdb.
Problem case:
Input: 10 54 108
EDIT:
So it turns out that my code is correct and is finding the correct answer for this case ( AKA - No solution exists ) but my problem is that I only have 3 sec of run time to find this solution and currently my code takes longer than that.
Not looking for a straight answer necessarily, more of a point in the right direction. Trying to learn from this :)
https://ibb.co/4138WBw
int odd_sum(int count, int bound, int sum)
{
if (bound % 2 == 0)
return odd_sum(count, bound -1, sum);
else if ( sum == 0 && count == 0 && bound >= -1)
return 1;
else if ( sum - bound < 0)
return odd_sum(count, bound - 2, sum);
else if (count == 0 && sum != 0)
return 0;
else if (bound < 1 && sum != 0)
return 0;
else
{
int value = (odd_sum(count - 1, bound - 2, sum - bound));
if ( value )
{
return printf("%d ", bound);
}
else
return (odd_sum(count - 1, bound - 2, sum - bound));
}
/* Do not change the main() function */
int main(void)
{
int value;
int c, b, s;
printf("Please enter 3 positive integers: count, bound, and sum:\n");
if (scanf("%d%d%d", &c, &b, &s) != 3) {
printf("Please enter 3 integers.\n");
return 1;
}
if (c <= 0 || b <= 0 || s <= 0) {
printf("Integers must be positive.\n");
return 1;
}
value = odd_sum(c, b, s);
if (value)
printf("\n");
else
printf("There are no solutions.\n");
return 0;
}
The final result needs to look like this for the two cases, ( pass or fail )
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
10 20 100
1 3 5 7 9 11 13 15 17 19
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
10 18 100
There are no solutions.
$./odd_sum
Please enter 3 positive integers: count, bound, and sum:
12 30 200
5 7 9 11 13 15 17 19 23 25 27 29
Thank you guys in advance
This code seems to return the correct result for input, (10, 54, 108): 1 3 5 7 9 11 13 15 17 27
int odd_sum(int count, int bound, int sum){
if (count == 0 && sum == 0)
return 1;
if (count == 0 || bound <= 0)
return 0;
if (bound % 2 == 0)
return odd_sum(count, bound - 1, sum);
if (odd_sum(count - 1, bound - 2, sum - bound))
return printf("%d ", bound);
else
return odd_sum(count, bound - 2, sum);
return 0;
}
I'm developing a system that can explore entirely a simple heuristic map of this gender (which can have different numbers of branches, and different depths) :
Simple heuristic map
So, I'm saving the positions explored in an int array of the size of the depth of the map. The goal is to explore all nodes of the map, so to have this output : 0 2 6, 0 2 7, 0 3 8, 0 3 9, 1 4 10 etc.. But actually with my code (which needs to be called several times because it can update just one time the array), i have this : 0 2 6, 0 2 7, 0 3 8, **1** 3 9, 1 4 10 etc..
This is my code, I don't know how to solve this problem..
void get_next_branch(int *s, int nbr_branch, int size)
{
int a;
a = 0;
while (a < size)
{
condition = (size - a)/(nbr_branch - 1);
if (condition)
{
if (s[size - 1] % (condition) + 1 == condition)
s[a]++;
}
a++;
}
}
And this is the main example who call this function.
int main(void)
{
int id[3] = {0, 2, 6};
while (id[2] < 13)
{
printf("%d %d %d\n", id[0], id[1], id[2]);
get_next_branch(id, 2, 3);
}
return (0);
}
I thank you in advance!
You might want to use a closed formula for this problem
b being the number of branches
d the depth you want to find the numbers in (d >= 0)
we get immediately
Number of nodes at depth d = bd+1
(since at depth 0 we have already two nodes, there is no "root" node used).
The number of the first node at depth d is the sum of the number of nodes of the lower levels. Basically,
first node number at depth 0 = 0
first node number at depth d > 0 = b1 + b2 + b3 + ... + bd
This is the sum of a geometric series having a ratio of b. Thanks to the formula (Wolfram)
first node number at depth d = b * (1 - bd) / (1 - b)
E.g. with b == 2 and d == 2 (3rd level)
Number of nodes: 2 ^ 3 = 8
Starting at number: 2 * (1 - 2^2) / (1 - 2) = 6
A program to show the tree at any level can be done from the formulas above.
To print a number of levels of a tree with b branches:
Utility power function
int power(int n, int e) {
if (e < 1) return 1;
int p=n;
while (--e) p *= n;
return p;
}
The two formulas above
int nodes_at_depth(int branches, int depth) {
return power(branches, depth+1);
}
int first_at_depth(int branches, int depth) {
return (branches * (1 - power(branches, depth))) / (1 - branches);
}
Sample main program, to be called
./heuristic nb_of_branches nb_of_levels
that calls the two functions
int main(int argc, char **argv)
{
if (argc != 3) return 1;
int b = atoi(*++argv);
int d = atoi(*++argv);
if (b < 2) return 2;
int i,j;
for (i=0 ; i<d ; i++) {
int n = nodes_at_depth(b, i); // number of nodes at level i
int s = first_at_depth(b, i); // first number at that level
for (j=0 ; j<n ; j++) printf(" %d", s+j);
printf("\n");
}
return 0;
}
Calling
./heuristic 2 4
gives
0 1
2 3 4 5
6 7 8 9 10 11 12 13
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
I'm trying to make a calculator for very big numbers (even bigger than long long) and I'm using arrays to make it work.
So far I have done addition, subtraction and multiplication. But I'm really stuck in division part.
EDIT:
new progress. as a friend mentioned i need to compare result array with divisor each time so i can stop the progress any time divisor is larger than dividend. I managed to make a nice function to compare it every time. this function is tested separately and it's working fine. OK. now i'm starting to make REAL progress. i got the quotient. now i will try to put quotient in array so that we can work with LARGER numbers!
#define MAX_SIZE 50
#define SIZE_USE (MAX_SIZE-1)
int div(int inum_first[], int inum_second[], int div_result[], int firstlen, int secondlen)
{
int i;
int check1 = 0, check2 = 0;
int zeroC = 0;
int tmp[MAX_SIZE];
for (i = 0; i <= SIZE_USE; i++)
{
tmp[i] = 0;
}
int inum_firstCP[MAX_SIZE] = { 0 };
for (i = 0; i <= 1; i++)
{
inum_firstCP[i] = inum_first[i]; // create a copy of inum_first
}
for (i = 0; i <= SIZE_USE; i++)
{
if (inum_first[i] != 0)
check1++;
if (inum_second[i] != 0)
check2++;
}
if (secondlen > firstlen)
{
zeroC++;
goto EOI;
}
if (check2 == 0)
{
puts("\nExpected error\n");
return -1;
}
int j = 0, p = 0;
int s = 0;
int o = 1; // o is Quotient!
do
{
for (i = SIZE_USE; i >= 0; i--)
{
if (tmp[i] = inum_firstCP[i] - inum_second[i] >= 0)
{
tmp[i] = inum_firstCP[i] - inum_second[i];
}
else
{
inum_firstCP[i - 1] = inum_firstCP[i - 1] - 1;
tmp[i] = (inum_firstCP[i] + 10) - inum_second[i];
}
inum_firstCP[i] = tmp[i];
}
if (compare(inum_firstCP, inum_second, firstlen, secondlen) < 0) break;
j++;
o++;
} while (j<MAX_SIZE); // anything else will also work
EOI:
return 0;
}
int compare(int inum_firstCP[], int inum_second[], int firstlen, int secondlen)
{
int c = 0, d = 0;
int i;
firstlen = MAX_SIZE, secondlen = MAX_SIZE; // temporary. will provide a better solution ASAP
if (firstlen > secondlen)
{
return 1;
}
else if (secondlen > firstlen)
{
return -1;
}
else
{
for (i = 0; i < firstlen; i++)
{
if (inum_firstCP[i] > inum_second[i]) c++;
else if (inum_second[i] > inum_firstCP[i]) d++;
}
if (c>d) return 1;
else if (d>c) return -1;
}
return 0; // else
}
If you have the subtraction of those big numbers the easiest solution is to take the two numbers and substract one from the other until you are left with something less then zero. It is the basic solution, it works but is a bit slow.
To make it faster you can do the following, take the divisor, multiply it by 2, if it is less then the dividend, keep on multiplying. When you will reach the first number bigger then a dividend set the corresponding bit to 1, subtract the multiplied dividend then do the same for the result.
There is the same thing nicely described on wiki.
In order to make it work you need to implement your own comparing function.
Assuming you will store the size of the malloc allocation in your structure in filed len you can do something like this:
int compare( mynum &a, mynum &b){
if (a.len() > b.len()){
return 1;
} else (if b.len() > a.len()){
return -1;
} else(){
for(int i = b.len(); i > 0; i--){
if (a[i] > b[i]){
return 1;
} else if(b[i] > a[i]){
return -1;
}
}
#if we get there the numbers are the same
return 0;
}
}
I've done this before and was very happy to implement it the same way as you'd do it by hand, with a small modification of multiple subtraction at each step. The algorithm is like that:
Multiply divisor by ten as often as you can without divisor becoming bigger than dividend.
Subtract divisor from dividend as often as you can and remember how many times.
The rest of all the subtractions is the new dividend.
Repeat at step (1) until dividend is smaller than divisor.
The current dividend is the "rest".
All the numbers remembered at step (3) are the "result" when ordered left to right (left calculated first).
Okay, let's try it by example:
E.g. you have 25391 and want to divide it by 71.
(1) 25391 and 71 * 10 = 710
25391 and 710 * 10 = 7100
25391 and 7100 * 10 = 71000 <-- TOO BIG
(2) 25391 - 7100 => X
18291 - 7100 => X
11191 - 7100 => X
4091 - 7100 <--- NOT POSSIBLE
(3) Number of X: 3
(4) 4091 > 71, okay, back to step 1.
(1) 4091 and 71 * 10 = 710
4091 and 710 * 10 = 7100 <--- TOO BIG
(2) 4091 - 710 => X
3381 - 710 => X
2671 - 710 => X
1961 - 710 => X
1251 - 710 => X
541 - 710 <--- NOT POSSIBLE
(3) Number of X: 5
(4) 541 > 71, okay, back to step 1
(1) 541 and 71 * 10 = 710 <--- TOO BIG
(2) 541 - 71 => X
470 - 71 => X
399 - 71 => X
328 - 71 => X
257 - 71 => X
186 - 71 => X
115 - 71 => X
44 - 71 <--- NOT POSSIBLE
(3) Number of X: 7
(4) 44 > 71, WRONG, continue with step 5
(5) Rest is 44
(6) Result is 357
If you had just tested how often you can subtract 71 from 25391, this loop would have had 357 iterations! Of course, my solution uses multiplication, but honestly, multiplying by 10 is no real multiplication, just shift all digits one position to the left and put a zero at the top right one.
The algorithm will need as many iterations as the result has digits and it will need at most 9 iterations (with subtraction) per digit.
#Mecki Try with 54 664 455 645 655 divided by 5 465 126 544, it fails. At step 3 you must add a number of '0' corresponding to the difference of length between the divisor (x n x 10) and the "rest". ie if the rest is 13 190 205 655 (11 digits length) and divisor is 54 651 265 440 000 (14 digits length) then three '0' must be added to the result before performing the next loop.
We are given an array of numbers and we want to find a subsequence of size 4 that is sorted in increasing order.
for eg ARRAY : -4 2 8 3 1 5
sorted subsequence of size 4 : -4 2 3 5
PS:There is a way of finding the sorted subsequence of size 3(see this). I am trying to think along the same lines but can't seem to find a solution for 4 integers.
Here is a solution that will find a sorted subsequence of fixed size k+1 by doing k passes over the input. Each pass is done left-to-right.
Pass 1: Create an auxiliary array p1[0..n-1]. p1[i] should store the index j of a number which is smaller than arr[i] and is on the left side of arr[i] (in other words: j<i and arr[j]<arr[i]). p1[i] should contain -1 if there is no such element. (p1 is the same as the smaller array from the solution for size 3).
Pass 2: Create an auxiliary array p2[0..n-1]. p2[i] should store the index j of a number which is smaller than arr[i], is on the left side of arr[i], and such that p1[j] != -1 (in other words: j<i, arr[j]<arr[i], and p1[j]!=-1). p2[i] should contain -1 if there is no such element.
....
Pass k: Create an auxiliary array pk[0..n-1]. pk[i] should store the index j of a number which is smaller than arr[i], is on the left side of arr[i], and such that p(k-1)[j] != -1 (in other words: j<i, arr[j]<arr[i], and p(k-1)[j]!=-1). pk[i] should contain -1 if there is no such element.
After the kth pass, each element where pk[i] != -1 corresponds to the largest element in a sorted subsequence of size k+1.
Pseudocode for kth pass (k>1):
function do_kth_pass(pk[], p_k_minus_1[])
min = -1
for i in 0..n-1:
if min != -1 and arr[i] > arr[min]:
pk[i] = min
else
pk[i] = -1
if p_k_minus_1[i] != -1 and (min == -1 or arr[i] < arr[min]):
min = i
Example:
Index: 0 1 2 3 4 5
Array: -4 2 8 3 1 5
p1: -1 0 0 0 0 0
p2: -1 -1 1 1 -1 4
p3: -1 -1 -1 -1 -1 3
After 3 passes, you have p3[5] != -1, so a sorted subsequence of size 4 exists. The indices of its elements are: p1[p2[p3[5]]], p2[p3[5]], p3[5], 5 which is 0,1,3,5
Having a greater and lesser array is a good option but it increases the space complexity. Below, is a solution to find four numbers in a linear subsequence without additional array space but rather it uses constant space and does only one pass over the array.
#include <iostream>
void sortedSubseqFour(int a[], int n)
{
int small = INT_MAX;
int middle_1 = INT_MAX;
int middle_2 = INT_MAX;
int greater = 0;
int main_small = 0;
int main_middle_1 = 0;
int main_main_small = 0;
for(int i = 0; i<n; i++)
{
if (a[i] <= small)
small = a[i];
else if (a[i] <= middle_1)
{
middle_1 = a[i];
main_small = small;
}
else if (a[i] <= middle_2)
{
middle_2 = a[i];
main_middle_1 = middle_1;
main_main_small = main_small;
}
else
{
greater = a[i];
break;
}
}
//end of loop
if (greater != 0)
std::cout << main_main_small << '\t' << main_middle_1 << '\t'
<< middle_2 << '\t' << greater;
else
std::cout << "No such Quadruple";
}
int main()
{
int arr[10] = {6, 7, 5, 1, 4, 3, 0, 7, 2, 11};
int n = 10;
sortedSubseqFour(arr, n);
return 0;
}
The above approach remembers all layers of minimum's when it sets the current minimum. The same code can also be used for a sorted subsequence of size 3 in an array by removing main_main_small and middle_2 part of the code.
If, the same code is to be extended up to size k then at say minimum i, we have to remember all minimum's before i, i.e min_1, min_2,... till min_i. Only in the last minimum, i.e. the greatest value in our subsequence, we just break and there is no need to remember previous or current minimum.
Please do inform if any bugs are discovered!
You can find the longest increasing subsequence and see if its size if greater than equal to 4(or even k in case you need to find it for a more general question). If the length of the Longest Increasing Subsequence is less than 4(or k) you can report that no such subsequence exists. LIS can be found out in O(nlog(n))
Create a smaller and greater array, similarly as to what was done for a subsequence of size 3. In addition to this, also have betweenSmallerAndCurrent array which stores the index of a value that is between the smallest and the current element - both in value and in index. More explicitly:
betweenSmallerAndCurrent[i] = -1 or
input[smaller[i]] < input[betweenSmallerAndCurrent[i]] < input[value[i]] and
smaller[i] < betweenSmallerAndCurrent[i] < value[i]
Constructing this should be pretty easy.
You'd just return the index i where betweenSmallerAndCurrent[i], smaller[betweenSmallerAndCurrent[i]] and greater[i] are all initialized. Note that we can't simply check smaller[i] as we may have something like [2,3,1,4,5], in which case, when we get to 4, the second smallest value 3 is before the current smallest value 1.
Example:
Indices: 0 1 2 3 4 5 6 7
Input: 12 11 10 5 6 2 9 30
smaller: -1 -1 -1 -1 3 -1 5 5
betweenSmallerAndCurrent:
-1 -1 -1 -1 -1 -1 4 4
greater: 7 7 7 7 7 7 7 -1
The only index with all values initialized is 6 (input value 9).
Java code: (not extensively tested)
void find4Numbers(int arr[], int n)
{
int max = n-1; //Index of maximum element from right side
int min = 0, second = -1; //Index of minimum element from left side
int i;
// Create an array that will store index of a smaller
// element on left side. If there is no smaller element
// on left side, then smaller[i] will be -1.
int[] smaller = new int[n];
int[] betweenSmallerAndCurrent = new int[n];
smaller[0] = -1; // first entry will always be -1
betweenSmallerAndCurrent[0] = -1;
for (i = 1; i < n; i++)
{
if (arr[i] <= arr[min])
{
min = i;
smaller[i] = -1;
betweenSmallerAndCurrent[i] = -1;
}
else
{
smaller[i] = min;
if (second != -1 && arr[second] < arr[i])
betweenSmallerAndCurrent[i] = second;
else
betweenSmallerAndCurrent[i] = -1;
if (second == -1 || arr[i] < arr[second])
second = i;
}
}
// Create another array that will store index of a
// greater element on right side. If there is no greater
// element on right side, then greater[i] will be -1.
int[] greater = new int[n];
greater[n-1] = -1; // last entry will always be -1
for (i = n-2; i >= 0; i--)
{
if (arr[i] >= arr[max])
{
max = i;
greater[i] = -1;
}
else
greater[i] = max;
}
// Make sure they're right
System.out.println(Arrays.toString(smaller));
System.out.println(Arrays.toString(betweenSmallerAndCurrent));
System.out.println(Arrays.toString(greater));
// Now find a number which has both a greater number on
// right side and smaller number on left side
for (i = 0; i < n; i++)
{
if (betweenSmallerAndCurrent[i] != -1 && smaller[betweenSmallerAndCurrent[i]] != -1 && greater[i] != -1)
{
System.out.printf("%d %d %d %d\n",
arr[smaller[betweenSmallerAndCurrent[i]]],
arr[betweenSmallerAndCurrent[i]],
arr[i],
arr[greater[i]]);
return;
}
}
// If we reach number, then there are no such 3 numbers
System.out.println("No such triplet found");
}
You may notice that the main code changes from this, apart from the C to Java conversion and added initializations, lies in the loop that sets up smaller. The code should be pretty easy to understand - try translating it into words if you're having trouble.
Test.
For each element, find next greater element index else -1
Now think of this as a graph and find a path of length k(if it exist)
This can be done easily in linear time using hashtable and memoization.