Python code for Binary Search Algorithm does not compile [closed] - python

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to implement a Binary Search algorithm in Python.
I wrote this code on my phone but it didn't compile.
And I don't know why it doesn't compile.
(I haven't tried it on a computer.)
def BinarySearch(sList, search):
res=0
sortedList=sorted(sList)
x=int(len(sortedList)/2)
mid=sortedList[x]
def DivideSearch(sortedList ,search ):
first=sortedList[:mid ]
second=sortedList[mid:]
if first[len(first)-1]<search:
DivideSearch (first, search)
elif second[len(second)-1]>search:
DivideSearch (second, search)
elif len(first)==1:
res=first.pop()
elif len(second)==1:
res=second.pop()
if res==search:
return res
numbers=[1,2,3,4,5,6,7,8,9]
guess=3
print(BinarySearch(numbers,guess ))
What keeps this code from compiling?
What are my mistakes and how can I fix them?

First, your code is running fine on my machine. Second, your logic is flawed. res never gets assigned in the BinarySearch() function because it is in a different scope than in the parent function. Also, your base case check should not be done on first or second it should be done on sortedList at the beginning of the function. Also, you can do your checking if the value was found in the DivideSearch() function. I'm uploading corrected code, take a look at this
import random
def DivideSearch(sortedList, search, mid):
first = sortedList[:mid]
second = sortedList[mid:]
#check for our base case
if len(sortedList) ==1:
return sortedList[0] if sortedList[0] == search else None
#we can immediately remove half the cases if they're less than or greater than our search value
#if the greatest value element in the lower half is < search value, only search the higher value list
if first[-1] < search:
#recurse
return DivideSearch(second, search, len(second)/2)
#otherwise we want to check the lower value list
else:
return DivideSearch(first, search, len(first)/2)
def BinarySearch(sList, search):
sortedList=sorted(sList)
#determine mid cleanup
mid=len(sortedList)/2
#return the result
return DivideSearch(sortedList,search, mid)
numbers=[random.randint(1, 10) for x in range(1,10)]
guess=5

def binarys(list, item):
#you have to keep track of the head(lo) of the list and tail(hi)
lo = 0
#a list must be sorted for binary search to work because the lower values are on the left and higher on the right
slist = sorted(list)
hi = len(slist) - 1
#Keep running the search as long as the start of the list is never less than or equal to the end of the list. At that point you either have 1 item left to check or the item isn't there at all. So return False
while lo <= hi:
mid = (lo + hi)//2
#if the item you searched for is in the middle, return True
if slist[mid] == item:
return True
#since it's not in the middle the first time you checked, but if the item you're looking for is less than the value of the mid item in the list then you can ignore the entire right part of the list by making the item to the left of the midpoint the new tail(hi). midpoint minus 1 because you already established the midpoint of the original list didn't have the item you searched for.
elif item < slist[mid]:
hi = mid - 1
# if the item you're looking for is greater than the value of the mid item in the list then you can ignore the entire left part of the list by making the item to the right of the midpoint the new head(lo). midpoint plus 1 because you already established the midpoint of the original list didn't have the item you searched for.
else:
if item > slist[mid]:
lo = mid+ 1
return False
print(binarys([1,2,3,4,5,6,7,8,9,10], 1))

Related

Binary search on array with duplicate

First time posting here, so apologies in advance if I am not following best practices. My algorithm is supposed to do the following in a sorted array with possible duplicates.
Return -1 if the element does not exist in the array
Return the smallest index where the element is present.
I have written a binary search algorithm for an array without duplicate. This returns a position of the element or -1. Based on blackbox testing, I know that the non-duplicate version of the binary search works. I have then recursively called that function via another function to search from 0 to position-1 to find the first incidence of the element, if any.
I am currently failing a black box test. I am getting a wrong answer error and not a time out error. I have tried most of the corner cases that I could think of and also ran a brute force test with the naive search algorithm and could not find an issue.
I am looking for some guidance on what might be wrong in the implementation rather than an alternate solution.
The format is as follow:
Input:
5 #array size
3 4 7 7 8 #array elements need to be sorted
5 #search query array size
3 7 2 8 4 #query elements
Output
0 2 -1 4 1
My code is shown below:
class BinarySearch:
def __init__(self,input_list,query):
self.array=input_list
self.length=len(input_list)
self.query=query
return
def binary_search(self,low,high):
'''
Implementing the binary search algorithm with distinct numbers on a
sorted input.
'''
#trivial case
if (self.query<self.array[low]) or (self.query>self.array[high-1]):
return -1
elif (low>=high-1) and self.array[low]!=self.query:
return -1
else:
m=low+int(np.floor((high-low)/2))
if self.array[low]==self.query:
return low
elif (self.array[m-1]>=self.query):
return self.binary_search(low,m)
elif self.array[high-1]==self.query:
return high-1
else:
return self.binary_search(m,high)
return
class DuplicateBinarySearch(BinarySearch):
def __init__(self,input_list,query):
BinarySearch.__init__(self,input_list,query)
def handle_duplicate(self,position):
'''
Function handles the duplicate number problem.
Input: position where query is identified.
Output: updated earlier position if it exists else return
original position.
'''
if position==-1:
return -1
elif position==0:
return 0
elif self.array[position-1]!=self.query:
return position
else:
new_position=self.binary_search(0,position)
if new_position==-1 or new_position>=position:
return position
else:
return self.handle_duplicate(new_position)
def naive_duplicate(self,position):
old_position=position
if position==-1:
return -1
else:
while position>=0 and self.array[position]==self.query:
position-=1
if position==-1:
return old_position
else:
return position+1
if __name__ == '__main__':
num_keys = int(input())
input_keys = list(map(int, input().split()))
assert len(input_keys) == num_keys
num_queries = int(input())
input_queries = list(map(int, input().split()))
assert len(input_queries) == num_queries
for q in input_queries:
item=DuplicateBinarySearch(input_keys,q)
#res=item.handle_duplicate(item.binary_search(0,item.length))
#res=item.naive_duplicate(item.binary_search(0,item.length))
#assert res_check==res
print(item.handle_duplicate(item.binary_search(0,item.length)), end=' ')
#print(item.naive_duplicate(item.binary_search(0,item.length)), end=' ')
When I run a naive duplicate algorithm, I get a time out error:
Failed case #56/57: time limit exceeded (Time used: 10.00/5.00, memory used: 42201088/536870912.)
When I run the binary search with duplicate algorithm, I get a wrong answer error on a different test case:
Failed case #24/57: Wrong answer
(Time used: 0.11/5.00, memory used: 42106880/536870912.)
The problem statement is as follows:
Problem Statement
Update:
I could make the code work by making the following change but I have not been able to create a test case to see why the code would fail in the first case.
Original binary search function that works with no duplicates but fails an unknown edge case when a handle_duplicate function calls it recursively. I changed the binary search function to the following:
def binary_search(self,low,high):
'''
Implementing the binary search algorithm with distinct numbers on a sorted input.
'''
#trivial case
if (low>=high-1) and self.array[low]!=self.query:
return -1
elif (self.query<self.array[low]) or (self.query>self.array[high-1]):
return -1
else:
m=low+(high-low)//2
if self.array[low]==self.query:
return low
elif (self.array[m-1]>=self.query):
return self.binary_search(low,m)
elif self.array[m]<=self.query:
return self.binary_search(m,high)
elif self.array[high-1]==self.query:
return high-1
else:
return -1
Since you are going to implement binary search with recursive, i would suggest you add a variable 'result' which act as returning value and hold intermediate index which equal to target value.
Here is an example:
def binarySearchRecursive(nums, left, right, target, result):
"""
This is your exit point.
If the target is not found, result will be -1 since it won't change from initial value.
If the target is found, result will be the index of the first occurrence of the target.
"""
if left > right:
return result
# Overflow prevention
mid = left + (right - left) // 2
if nums[mid] == target:
# We are not sure if this is the first occurrence of the target.
# So we will store the index to the result now, and keep checking.
result = mid
# Since we are looking for "first occurrence", we discard right half.
return binarySearchRecursive(nums, left, mid - 1, target, result)
elif target < nums[mid]:
return binarySearchRecursive(nums, left, mid - 1, target, result)
else:
return binarySearchRecursive(nums, mid + 1, right, target, result)
if __name__ == '__main__':
nums = [2,4,4,4,7,7,9]
target = 4
(left, right) = (0, len(nums)-1)
result = -1 # Initial value
index = binarySearchRecursive(nums, left, right, target, result)
if index != -1:
print(index)
else:
print('Not found')
From your updated version, I still feel the exit point of your function is a little unintuitive.(Your "trivial case" section)
Since the only condition that your searching should stop, is that you have searched all possible section of the list. That is when the range of searching area is 0, there is no element left to be search and check. In implementation, that is when left < right, or high < low, is true.
The 'result' variable, is initialized as -1 when the function first been called from main. And won't change if there is no match find. And after each successful matching, since we can not be sure if it is the first occurrence, we will just store this index into the result. If there are more 'left matching', then the value will be update. If there is not, then the value will be eventually returned. If the target is not in the list, the return will be -1, as its original initialized value.

Retrieving the minimum element in a stack at a constant time

Can you please help me understand what is going on in this line of code?
def push(self, x):
self.stack.append(x)
if len(self.minStack):
if x < self.minStack[-1][0]:
self.minStack.append([x, 1])
elif x == self.minStack[-1][0]:
self.minStack[-1][1] += 1
else:
self.minStack.append([x, 1])
it is taken from the line of this code:
class MinStack2:
def __init__(self):
self.stack, self.minStack = [], []
# #param x, an integer
# #return an integer
def push(self, x):
self.stack.append(x)
if len(self.minStack):
if x < self.minStack[-1][0]:
self.minStack.append([x, 1])
elif x == self.minStack[-1][0]:
self.minStack[-1][1] += 1
else:
self.minStack.append([x, 1])
You can also find it at this GitHub account: https://github.com/kamyu104/LeetCode/blob/master/Python/min-stack.py
Thank you in advance
Please, dont just mark it down if there is any misunderstanding for you. Leave a feedback rather. This is a plattform to learn and I feel like marking post down without an explanantion is very uneducated
Whenever you push onto the stack, you also check if this item is smaller than the previous minimum, which is kept on top of minStack, along with the count of how many of that item are in the stack.
If the item is smaller, then you push it (with a count of 1) onto minStack. If it's the same, you increment the count of that item by one.
Every time you pop an item, if it is the smallest item in the stack (i.e. == minStack[-1][0]), you decrement the count of the smallest item. If that count becomes zero, you pop the item off minStack. Now the smallest item in the stack is whatever it was before the first of that smaller item was added. This is because in order to discard that first instance of the smallest item, we had to pop everything on top of it first, essentially rolling the stack back to the point in time at which the smallest element was added.
PS: When you find yourself writing your own stack implementations, know that any stack that doesn't return the items it pops is acting very strangely.

Binary search: weird middle point calculation

Regarding calculation of the list mid-point: why is there
i = (first +last) //2
and last is initialized to len(a_list) - 1? From my quick tests, this algorithm without -1 works correctly.
def binary_search(a_list, item):
"""Performs iterative binary search to find the position of an integer in a given, sorted, list.
a_list -- sorted list of integers
item -- integer you are searching for the position of
"""
first = 0
last = len(a_list) - 1
while first <= last:
i = (first + last) / 2
if a_list[i] == item:
return '{item} found at position {i}'.format(item=item, i=i)
elif a_list[i] > item:
last = i - 1
elif a_list[i] < item:
first = i + 1
else:
return '{item} not found in the list'.format(item=item)
The last legal index is len(a_list) - 1. The algorithm will work correctly, as first will always be no more than this, so that the truncated mean will never go out of bounds. However, without the -1, the midpoint computation will be one larger than optimum about half the time, resulting in a slight loss of speed.
Consider the case where the item you're searching for is greater than all the elements of the list. In that case the statement first = i + 1 gets executed repeatedly. Finally you get to the last iteration of the loop, where first == last. In that case i is also equal to last, but if last=len() then i is off the end of the list! The first if statement will fail with an index out of range.
See for yourself: https://ideone.com/yvdTzo
You have another error in that code too, but I'll let you find it for yourself.

Find index of list using binary recursive function

So, ive been instructed to create a function with 2 parameters, a list and a number, that uses a binary recursive search to see if a number is in a list. If the number is in the list i'm to return its index and if its not I am to return -1. So far i have
def findIndex(alist,num):
print(alist)
if len(alist) % 2 == 0:
mid = int((len(alist)/2)-1)
else:
mid = ((len(alist)//2))
if alist[mid] == num:
print(mid)
elif alist[mid] > num:
findIndex(alist[0:mid],num)
elif alist[mid] < num:
findIndex(alist[mid+1:],num)
I know how a binary search works. Do to the middle, if its not the number you're searching for compare that number to the number you're searching for. If its greater than the number youre searching for, search the front half of the list. If its lesser, search the back half of the list again. The problem is my code only works in the case that the number I'm searching for is less than the middle number in every case.
ANALYSIS
There are several problems with the logic.
The deleted post nailed your most glaring problem: your search works only when the search target appears in the middle of a series of left-only divisions. Otherwise, you print 0, the index when the list gets down to a single item.
If the target is not in the list, your program crashes on index out of range, when you try to find the midpoint of an empty list.
You never return anything. Printing a result is not the same as returning a value.
SOLUTION
There are two straightforward ways to handle this. The first is to use findIndex as a wrapper function, and write the function you want to be called by that. For instance:
def findIndex(alist,num):
return binaryFind(alist, 0, len(alist), num)
def binaryFind(alist, left, right, target):
# Here, you write a typical binary search function
# with left & right limits.
The second is to return the index you find, but adjust it for all of the times you cut off the left half of the list. Each level of call has to add that adjustment to the return value, passing the sum back to the previous level. The simple case looks like this, where you're recurring on the right half of the list:
elif alist[mid] < num:
return (mid+1) + findIndex(alist[mid+1:], num)
Does that get you moving toward a useful solution?

recursion, finding max, why is it not stopping?

I tried to find the maximum value in a sorted list. but the recursion is not stopping. please, can somebody help me?
A = [5,16,28,43,0,1]
start = 0
end = len(A) - 1
mid = 0
print mid
def search(start, end, mid):
mid = int((start + end) / 2)
print mid
if A[mid] > [mid - 1] and A[mid] > A[mid + 1]:
return A[mid]
else:
if A[mid - 1] > A[mid + 1]:
search(start, mid, mid)
else:
search(mid, end, mid)
print search(start, end, mid)
You need to add a "basis case" (where the recursion stops).
A natural basis case for this problem: if start is equal to end, just return A[start]
EDIT:
I just looked at this and the more I look the more confused I get. Why are you using recursion to find a max? It would make more sense to use recursion to do a "binary search" to find a value inside a sorted list.
If you want to really find a max value, that's pretty easy. With recursion, we first want a "basis case" that gives us a trivial solution; then we want more code that will take us one step closer to that solution.
In this case, the basis case: we have only one value in the list; return it as the max. To be specific, if the start and end together specify just one value, return that one value. To make it proof against errors, might as well make this also handle the case where start is equal to or even greater than end.
Next remember the first value.
Next make a recursive call, but add one to start to reduce the size of the list we are considering. This is the part that takes us one step closer to a solution. Repeat this step enough times and we arrive at the basis case where there is only one value in the list to consider.
Finally compare the remembered first value with the result of the recursive call and return the larger of the two.
I'll lay it out in psuedocode for you:
BASIS CASE: start and end specify one value: return A[start]
save A[0] in a variable
save recursive_call_to_this_function(start+1, end) in a variable
compare two saved values and return the larger
Once you have tried to write the above in code, peek below this line for my working tested solution.
def recursive_max(start, end):
if start >= end - 1:
return A[start]
x0 = A[start]
x1 = recursive_max(start+1, end)
if x0 >= x1:
return x0
else:
return x1
print recursive_max(start, end)
I agree with most of steveha's answer, but rather than picking off one element at a time I'd suggest dividing the list into halves and finding the max in each half. You won't do any fewer comparisons, but the growth of the recursive stack will be O(log(len(A))) rather than O(len(A)). For large lists this would be the difference between getting a stack overflow or not.
My implementation (which takes the list as an argument rather than expecting it to be global) follows:
def recursive_max(value_list, start, end):
if start >= end:
return value_list[start]
mid = start + (end - start) // 2
lower_half_max = recursive_max(value_list, start, mid)
upper_half_max = recursive_max(value_list, mid+1, end)
if lower_half_max > upper_half_max:
return lower_half_max
else:
return upper_half_max

Categories