An array is bitonic if it is composed of an increasing sequence of integers followed immediately by a decreasing sequence of integers. Write a program that, given a bitonic array of N distinct integer values, determines whether a given integer is in the array.
I have divided the problem in two sub-problems:
- Find the maximum.
- Do the binary search on left and right half.
Here is the complete solution:
def bin_search(ary, elem, low, high):
""" Search element in array of ascending order."""
# Gaurd clause, if element is not in array,
if low > high:
return None
mid = low + (high - low) / 2
if (ary[mid] < elem):
return bin_search(ary, elem, mid + 1, high)
elif (ary[mid] > elem):
return bin_search(ary, elem, low, mid - 1)
else:
return mid
def bin_search_reverse(ary, elem, low, high):
""" Search element in array of descending order."""
# Gaurd clause, if element is not in array,
if low > high:
return None
mid = low + (high - low) / 2
if (ary[mid] > elem):
return bin_search_reverse(ary, elem, mid + 1, high)
elif (ary[mid] < elem):
return bin_search_reverse(ary, elem, low, mid - 1)
else:
return mid
def find_max_bitonic(ary):
def recurse(low, high):
mid = low + (high - low) / 2
# Handle base cases first.
if (high - low == 1):
return high
if (ary[mid] < ary[mid+1]):
return recurse(mid, high) # Go right.
else:
return recurse(low, mid)
return recurse(0, len(ary) - 1)
def search(ary, elem):
maximum = find_max_bitonic(ary)
if (ary[maximum] == elem):
return maximum
left = bin_search(ary, elem, 0, maximum - 1)
right = bin_search_reverse(ary, elem, maximum + 1, len(ary) - 1)
return left or right
ary = (5, 15, 25, 35, 40, 45, 20, 10, 2)
print search(ary, 20)
I think there is a scope of lot of improvements. I personally think writing two separate methods for binary search can be avoided but don't know if there is any elegant alternative.
Running time
\$log_{2}O(N)\$(Finding maximum) + 2\$log_{2}O(N)\$(Binary search) = \$3log_{2}O(N)\$