Recently I was given a problem to solve during a technical interview: we have an array of sorted integers as an input and a single integer; we need to find the starting and ending positions of the occurrences of that integer in the array. For example, if the array is {0, 1, 1, 2, 3, 4, 4, 4, 5} and the input integer is 1, the program should return (1, 2). If the input integer is 4 and the array is the same, the program should return (5, 7). And finally, if no occurrence found, say if the input is 7, the program should return (-1, -1). I couldn't get a clean code in the assigned time, that's why I decided to try it at home and make sure my algorithm works. So here is just a simple solution. For simplicity, I used std::vector<int> as an input array, but obviously it should be a generalized function with a template parameter. Anyway, here is my solution:
As you can see, in the function above I am just calling an overloaded version of the same function, which contains the actual algorithm implementation. I added lots of explanatory comments so no more text, just the code:
// The actual interface method which is
the solution to the problem
std::pair<int, int> getRange(const std::vector<int>& numbers, int value)
{
return getRange(numbers, 0, numbers.size(), value, -1, -1);
}
As you can see, in the function above I am just calling an overloaded version of the same function, which contains the actual algorithm implementation. I added lots of explanatory comments so no more text, just the code:
// Obviously this should be just an
implementation detail
// so you don't want this be part of an
interface of your
// class/lib.
// Note the currentLow and currentUp
parameters, they are
// meant to keep track of the
so-far-found range of
// occurrences, to pass down to the
same function through
// recursive calls.
std::pair<int, int> getRange(
const std::vector<int>& numbers,
int begin,
int end,
int value,
int currentLow = -1,
int currentUp = -1)
{
// First of all, since
the original array is sorted,
// we don't need to
look for anything if the element
// we're looking for
is less than the first
// element of the
array or greater than the last,
// meaning that it's
not there for sure. So just
// returning the not
found value.
if (value < numbers[begin] || value > numbers[end - 1])
{
return std::make_pair(currentLow, currentUp);
}
// On the other hand,
if the first and last elements
// of the array are
equal to the one we're looking for,
// it means all the
elements between are also equal
// because the array
is sorted. Hence, we just return
// the whole range.
if (numbers[begin] == value && numbers[end - 1] == value)
{
return std::make_pair(begin, end - 1);
}
// If none of the easy
cases happen, then we just
// split the array in
two, and try to look for the
// range in a binary
search fashion.
int middle = begin + (end - begin) / 2;
// If the middle
element is greater than the value, then
// obviously, if the
element is in the array, it's in the
// first half (left
from middle), so we just call the
// function
recursively with the cut range.
if (value < numbers[middle])
{
// look in first half
return getRange(
numbers,
begin,
middle,
value,
currentLow,
currentUp);
}
// Same here - but
looking in the other half.
else if (value > numbers[middle])
{
// look in 2nd half
return getRange(
numbers,
middle,
end,
value,
currentLow,
currentUp);
}
// This is the most
interesting case, when middle element
// is equal to the
given value, it means there might be
// occurrences both on
left and right sides. Now we call
// the function
recursively for both left and right
// sections, but we
only take the lower bound from left
// section and the
upper bound from the right.
else
{
currentLow = (currentLow > middle || currentLow == -1) ?
middle
: currentLow;
currentUp = (currentUp < middle) ? middle
: currentUp;
// look in both
int lowerBound =
getRange(
numbers,
begin,
middle,
value,
currentLow,
currentUp).first;
int upperBound =
getRange(
numbers,
middle,
end,
value,
currentLow,
currentUp).second;
return
std::make_pair(lowerBound, upperBound);
}
}
Don't forget to include the required headers.
Don't forget to include the required headers.