Implementing the Binary Search algorithm in python - python

I am new into python and i am trying to implement binary search via recursion , I could see the solution of internet but i tried all way myself because i wanted to learn , so this is my approach :
y=7
count=0
def hello(x):
while len(x)>0:
for i in x:
a=len(x)//2
if y<x[a]:
print("left_most_side", a)
return hello(x[:a])
elif y==x[a]:
print("middle", a)
return a
elif y>x[a]:
print("right_most_side", a)
return hello(x[a:])
return x
hello([1,2,3,4,5,6,7])
Its working perfects and giving the output as expected but issue is , its printing the index of bi-sectioned list, while i need the index of origional list. example : a=[1,2,3,4] it bisection this and now [1,2] and [3,4] and now if i had to find 4 then it will print 4 is at position 0 , answer is correct but only in bisectioned list , while the correct answer is "4" is in origional list at position 3 so it should print 3 , that's the problem i am facing.

As mentioned in my comment, I would recommend passing the entire list, along with the upper and lower bounds to search. This will take care of the index issue.
Furthermore, please do not have your function work with global variables. It's bad practice.
def hello(x, key, l, r):
if l < r:
a = (l + r) // 2
if key < x[a]:
return hello(x, key, l, a + 1)
elif key > x[a]:
return hello(x, key, a + 1, r)
else:
return a
else:
return -1
In [288]: src = [1,2,3,4,5,6,7]
In [289]: hello(src, key=7, l=0, r=7)
Out[289]: 6
In [290]: hello(src, key=0, l=0, r=7)
Out[290]: -1
In [291]: hello(src, key=1, l=0, r=7)
Out[291]: 0

Use left and right to track the array bounds as it passes through recursion like this
y=7
def hello (x, left, right, query):
if right >= left:
mid = left + (right - left)/2
if x[mid] == query:
return mid
elif x[mid] > query:
return hello(x, left, mid-1, query)
else:
return hello(x, mid+1, right, query)
else:
# we found nothing
return -1
arr = [1,2,3,4,5,6,7]
print hello(arr,0,len(arr),y)

Related

Python recursive helper method returns none instead of int

I wanted to write code such that I could find the k-th largest number using quick-sort and wrote the following in LeetCode, which LeetCode will call upon findKthLargest first
class Solution(object):
def partition(self, arr,left,right):
piv = arr[right]
i = left-1
counter = left
while (counter<right):
if (arr[counter]<piv):
i = i+1
tmp = arr[counter]
arr[counter]=arr[i]
arr[i]=tmp
counter = counter+1
temp = arr[i+1]
arr[i+1]=arr[right]
print('pivot '+str(piv)+' at '+str(i+1))
arr[right]=temp
print("at the nmoment "+str(arr))
return (i+1)
def helper(self,arr,left,right,k):
if (left>=right):
return
p = self.partition(arr,left,right)
print("p is now "+str(p))
if (p==len(arr)-k):
return int(arr[p])
self.helper(arr,left,p-1,k)
self.helper(arr,p+1,right,k)
def findKthLargest(self, nums, k):
f= self.helper(nums,0,len(nums)-1,k)
print(f)
I've even printed (arr[p]) INSIDE the helper method and it gave me the correct answer however inside of the method findKthLargest the variable f shows up as a none type and I was wondering where did I go wrong? At the moment I believe that it is returning a none type since inside of the recursive loops when checking if (left>=right) inside of the helper method it returns none
The problem is that your helper function does not always return a value. Only in the base case, where the if condition is true, it will return a numeric value. But it should also return that same number where the corresponding recursive calls are made.
So change:
self.helper(arr,left,p-1,k)
self.helper(arr,p+1,right,k)
to:
result = self.helper(arr,left,p-1,k)
if result is not None:
return result
return self.helper(arr,p+1,right,k)
This way the deepest return value will bubble up the recursion tree, and a success in the first recursive call will avoid that the second recursive call is made.
Hard to debug your code, this'd pass though with less statements:
class Solution:
def findKthLargest(self, nums, k):
def kth_smallest(nums, k):
if nums:
pos = partition(nums, 0, len(nums) - 1)
if k > pos + 1:
return kth_smallest(nums[pos + 1:], k - pos - 1)
elif k < pos + 1:
return kth_smallest(nums[:pos], k)
else:
return nums[pos]
def partition(nums, left, right):
res = left
while left < right:
if nums[left] < nums[right]:
nums[left], nums[res] = nums[res], nums[left]
res += 1
left += 1
nums[res], nums[right] = nums[right], nums[res]
return res
return kth_smallest(nums, len(nums) + 1 - k)

Finding the minimum in a list that is Decreasing and then Increasing and might contain duplicates

Given a list that can be broken into two pieces L[:z] and L[z:] such that the first is non-increasing and the second is non-decreasing and may or may not contain duplicate elements, create a function such that:
Input:
A list L as specified above
A value k which represents the maximum number of times any given value is repeated in the list
Output:
The minimum value of the list
Complexity & Requirements
O(log n)
Can only use built in library functions not including min/max
I have the following:
def findmin(L, k = None):
left = 0
right = len(L)-1
foundmin = False
while not foundmin:
mp = (left + right)//2
if L[mp] > L[mp+1]:
left = mp
elif L[mp-1] < L[mp]:
right = mp+1
else:
return L[mp]
It only works for some lists such as:
L = [9,9,4,3,2,1,7,7,10,10]
But it does not work correctly for lists such as:
L = [6,5,4,3,3,3,3,3,3,3,3,3,1,7,7,7,7]
I have tried modifying the function to accommodate repeated elements to no avail. I am also not seeing the utility of the input k for the function. Thoughts?
This code runs in O(logn) and has no use of the k parameter.
It is some kind of binary search like #coldspeed commented.
def find_min(l, k=None):
left = 0
right = len(l) - 1
while left <= right:
middle = (left + right) // 2
if l[middle] < l[left] or (l[middle] == l[left] and middle > left):
left = middle
elif l[middle] < l[right] or (l[middle] == l[right] and middle < right):
right = middle
else:
return l[middle]
The issue with your solution is that if the numbers on either side of mp are equal to mp, then your algorithm will output L[mp]. Thus, in the second case, it outputs 3. A simple thing would be be check the next unequal number instead of checking just the adjacent ones.
Modified solution :
def findmin(L, k = None):
left = 0
right = len(L)-1
foundmin = False
while left<right:
print(left, right)
mp = (left + right)//2
next_diff = mp+1
while(next_diff < len(L)-1 and L[next_diff] == L[mp]):
next_diff+=1
if L[mp] > L[next_diff]:
left = next_diff
elif L[mp] <= L[next_diff]:
right = mp
return L[left]
P.S : Though the complexity in this case becomes O(k* log n).

How to Memoize the solution to Unique Paths in Python

I've been trying to solve this problem for a while. A M x N grid is given and we've to find number to paths from top left corner to bottom right corner.
Simple problem though; there are many solutions as well. Here're the details.
http://www.interviewbit.com/courses/programming/topics/math/problems/paths/
http://articles.leetcode.com/2010/11/unique-paths.html
I solved this problem in Java, and wrote one more solution in Python. Now I want to modify the previous solution with Memoized table so that the final answer gets collected at the bottom right cell. Value of a cell is the sum of its right and left adjacent cells.
Here's the code I can't debug:-
class Solution:
#Actual Recursive function
def paths(self,row,col):
if row == 0 or col == 0:
self.Mat[row][col] = 1
return 1
self.Mat[row][col-1] = self.paths(row, col-1)
self.Mat[row-1][col] = self.paths(row-1, col)
self.Mat[row][col] = self.Mat[row][col-1] + self.Mat[row-1][col]
return self.Mat[row][col]
# Driver Function. This will be called
def uniquePaths(self, A, B):
self.Mat = [[-1]*B]*A
ans = self.paths(A-1, B-1)
return self.Mat[A-1][B-1]
And here is my previous solution that works - But doesn't use memoized table.
class OldSolution:
def paths(self,row,col):
if row==0 or col==0:
return 1
elif row<0 or col<0:
return 0
elif row >0 and col > 0:
return self.paths(row-1,col) + self.paths(row,col-1)
def uniquePaths(self, A, B):
Mat = [ [-1] * B ] *A
return self.paths(A-1, B-1)
sol = OldSolution()
print sol.uniquePaths(3,3) # Prints 6
Test Cases:-
3, 3 = 6
15, 9 = 319770
The issue is with the initialization of the matrix. You essentially create the same row duplicated in every column so when you update a cell, all corresponding cells in all columns get updated.
Instead of:
self.Mat = [[-1]*B]*A
Use:
self.Mat = [[-1 for i in range(B)] for j in range(A)]

search for before and after values in a long sorted list

What would be the fastest way to search for a number (eg. 12.31) in long sorted list and get the values one before and after my "search" value when the exact value isn't found (eg. 11.12 and 12.03 in the list below)?
Many thanks in advance.
long_list = [10.11, 11.12, 13.03, 14.2 .. 12345.67]
The fastest is probably to use built-in support in python. Here I'm thinking about the bisect module. Below I'm using a dictionary to quickly check in O(1) if a value is in the list; if not, bisect is used to find values smaller than and larger than the sought value.
#!/usr/bin/env python
import bisect
def find_lt(a, x):
'Find rightmost value less than x'
i = bisect.bisect_left(a, x)
if i:
return a[i-1]
raise ValueError
def find_gt(a, x):
'Find leftmost value greater than x'
i = bisect.bisect_right(a, x)
if i != len(a):
return a[i]
raise ValueError
# First create a test-list (49996 items)
i=1.0
R=[1.0]
D={}
while i < 10000:
i+=0.2
i=round(i,2)
D[i]=True
R.append(i)
# Locate a value, in this case 100.3 which is not in the list
x=100.3
if D.has_key(x):
print "found", x
else:
print find_lt(R, x)
print find_gt(R, x)
Output for x=100.3:
100.2
100.4
Exponential search (AKA galloping search) would perform better than plain binary search if the list is very long. The idea is to scan forward from position 0 on increasing steps until the answer is passed at this point a binary search can be performed to the range formed by the last two steps. If the element is not found then the last attempt will point to the closest elements.
Have a look at Basic Techniques for information retrieval. The pseudo-code algorithm is provided and they discuss its complexity against binary search.
If your list is sorted as in your example, I suppose a binary search would be fastest.
li = [10.11, 11.12, 13.03, 14.2, 15.6, 15.8, 17.9, 12345.67]
def searsh(x,li):
itli = iter(li)
a = itli.next()
if a==x:
return a
else:
while True:
b = itli.next()
if b==x:
return b
elif a<x<b:
return (a,b)
a = itli.next()
if a==x:
return a
elif b<x<a:
return (b,a)
print searsh(13.5,li)
print searsh(10.11,li)
print searsh(50.3,li)
print searsh(12345.67,li)
result
(13.03, 14.2)
10.11
(17.9, 12345.67)
12345.67
Also:
def searsh(x,li):
a = li[0]
if a==x:
return a
else:
j = 0
while True:
j += 1
b = li[j]
if b==x:
return b
elif a<x<b:
return (a,b)
j += 1
a = li[j]
if a==x:
return a
elif b<x<a:
return (b,a)

counting odd numbers in a list python

This is a part of my homework assignment and im close to the final answer but not quite yet. I need to write a function that counts odd numbers in a list.
Create a recursive function count_odd(l) which takes as its only argument a list of integers. The function will return a count of the number of list elements that are odd, i.e., not evenly divisible by 2.\
>>> print count_odd([])
0
>>> print count_odd([1, 3, 5])
3
>>> print count_odd([2, 4, 6])
0
>>> print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
8
Here is what i have so far:
#- recursive function count_odd -#
def count_odd(l):
"""returns a count of the odd integers in l.
PRE: l is a list of integers.
POST: l is unchanged."""
count_odd=0
while count_odd<len(l):
if l[count_odd]%2==0:
count_odd=count_odd
else:
l[count_odd]%2!=0
count_odd=count_odd+1
return count_odd
#- test harness
print count_odd([])
print count_odd([1, 3, 5])
print count_odd([2, 4, 6])
print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
Can u help explain what im missing. The first two test harness works fine but i cant get the final two. Thanks!
Since this is homework, consider this pseudo-code that just counts a list:
function count (LIST)
if LIST has more items
// recursive case.
// Add one for the current item we are counting,
// and call count() again to process the *remaining* items.
remaining = everything in LIST except the first item
return 1 + count(remaining)
else
// base case -- what "ends" the recursion
// If an item is removed each time, the list will eventually be empty.
return 0
This is very similar to what the homework is asking for, but it needs to be translate to Python and you must work out the correct recursive case logic.
Happy coding.
def count_odd(L):
return (L[0]%2) + count_odd(L[1:]) if L else 0
Are slices ok? Doesn't feel recursive to me, but I guess the whole thing is kind of against usual idioms (i.e. - recursion of this sort in Python):
def countOdd(l):
if l == list(): return 0 # base case, empty list means we're done
return l[0] % 2 + countOdd(l[1:]) # add 1 (or don't) depending on odd/even of element 0. recurse on the rest
x%2 is 1 for odds, 0 for evens. If you are uncomfortable with it or just don't understand it, use the following in place of the last line above:
thisElement = l[0]
restOfList = l[1:]
if thisElement % 2 == 0: currentElementOdd = 0
else: currentElementOdd = 1
return currentElementOdd + countOdd(restOfList)
PS - this is pretty recursive, see what your teacher says if you turn this in =P
>>> def countOdd(l):
... return fold(lambda x,y: x+(y&1),l,0)
...
>>> def fold(f,l,a):
... if l == list(): return a
... return fold(f,l[1:],f(a,l[0]))
All of the prior answers are subdividing the problem into subproblems of size 1 and size n-1. Several people noted that the recursive stack might easily blow out. This solution should keep the recursive stack size at O(log n):
def count_odd(series):
l = len(series) >> 1
if l < 1:
return series[0] & 1 if series else 0
else:
return count_odd(series[:l]) + count_odd(series[l:])
The goal of recursion is to divide the problem into smaller pieces, and apply the solution to the smaller pieces. In this case, we can check if the first number of the list (l[0]) is odd, then call the function again (this is the "recursion") with the rest of the list (l[1:]), adding our current result to the result of the recursion.
def count_odd(series):
if not series:
return 0
else:
left, right = series[0], series[1:]
return count_odd(right) + (1 if (left & 1) else 0)
Tail recursion
def count_odd(integers):
def iter_(lst, count):
return iter_(rest(lst), count + is_odd(first(lst))) if lst else count
return iter_(integers, 0)
def is_odd(integer):
"""Whether the `integer` is odd."""
return integer % 2 != 0 # or `return integer & 1`
def first(lst):
"""Get the first element from the `lst` list.
Return `None` if there are no elements.
"""
return lst[0] if lst else None
def rest(lst):
"""Return `lst` list without the first element."""
return lst[1:]
There is no tail-call optimization in Python, so the above version is purely educational.
The call could be visualize as:
count_odd([1,2,3]) # returns
iter_([1,2,3], 0) # could be replaced by; depth=1
iter_([2,3], 0 + is_odd(1)) if [1,2,3] else 0 # `bool([1,2,3])` is True in Python
iter_([2,3], 0 + True) # `True == 1` in Python
iter_([2,3], 1) # depth=2
iter_([3], 1 + is_odd(2)) if [2,3] else 1
iter_([3], 1 + False) # `False == 0` in Python
iter_([3], 1) # depth=3
iter_([], 1 + is_odd(3)) if [3] else 1
iter_([], 2) # depth=4
iter_(rest([]), 2 + is_odd(first([])) if [] else 2 # bool([]) is False in Python
2 # the answer
Simple trampolining
To avoid 'max recursion depth exceeded' errors for large arrays all tail calls in recursive functions can be wrapped in lambda: expressions; and special trampoline() function can be used to unwrap such expressions. It effectively converts recursion into iterating over a simple loop:
import functools
def trampoline(function):
"""Resolve delayed calls."""
#functools.wraps(function)
def wrapper(*args):
f = function(*args)
while callable(f):
f = f()
return f
return wrapper
def iter_(lst, count):
#NOTE: added `lambda:` before the tail call
return (lambda:iter_(rest(lst), count+is_odd(first(lst)))) if lst else count
#trampoline
def count_odd(integers):
return iter_(integers, 0)
Example:
count_odd([1,2,3])
iter_([1,2,3], 0) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([2,3], 0+is_odd(1)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([3], 1+is_odd(2)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([], 1+is_odd(3))
2 # callable(2) is False
I would write it like this:
def countOddNumbers(numbers):
sum = 0
for num in numbers:
if num%2!=0:
sum += numbers.count(num)
return sum
not sure if i got your question , but as above something similar:
def countOddNumbers(numbers):
count=0
for i in numbers:
if i%2!=0:
count+=1
return count
Generator can give quick result in one line code:
sum((x%2 for x in nums))

Categories

Resources