To rewrite the function without using recursion.
def func(num):
if num < 2:
return 1
else:
return func(num - 1) + func(num - 2)
# TODO:to rewrite the func using 'loop' instead of 'recursion'.
Below may be a solution, but i do not think it is a good way as i am using the convience of 'list'.
def func(num):
"""
I use a list to simulate a queue,
it is initialized with the param 'num' passed in,
and then judge it, if it ge 2, pop it and append the two nums 'num - 1', 'num - 2'.
And repeat it, if the number is lt 2, the index move to right by 1.
When the index is equal to the 'length - 1' of the queue, the queue if fulled with '0' and '1',
because 'func(0) = 1', 'func(1) = 1', the result is the length of the queue.
"""
index = 0
queue = [num]
while True:
value = queue[index]
if value >= 2:
queue.pop(index)
queue.append(value - 1)
queue.append(value - 2)
else:
if index == len(queue) - 1:
break
index += 1
return len(queue)
The task was interesting for me to solve, I cope with it the following way:
def f(num):
if num < 2: # margin condition
return 1
start_list = [num] # create initial list
while True:
new_list = [] # list to store new elements
changes = 0 # check if there was elements >=2
for element in start_list:
if element >= 2:
new_list.append(element - 1)
new_list.append(element - 2)
changes += 1
else:
new_list.append(element)
start_list = new_list # change start_list for new run
print(start_list)
if changes == 0:
return len(start_list)
I made performance check num = 25
my solution speed: 0.14056860000000002
recursion speed: 0.03910620000000001
your not recursion solution: 1.6991333
So it is 10 times faster.
Thank you for the task!
I am new to python and I am trying to implement heapsort from my C++ implementation. This code is unable to sort input.
I have written another program to test function build_max_heap and this function is unable to build max heap.
def max_heapify(thelist, lst_size, idx):
largest = idx
left_child = (2 * idx) + 1
right_child = (2 * idx) + 2
if left_child < lst_size and thelist[left_child] > thelist[largest]:
largest = left_child
elif right_child < len(thelist) and thelist[right_child] > thelist[largest]:
largest = right_child
if largest != idx:
thelist[idx], thelist[largest] = thelist[largest], thelist[idx]
max_heapify(thelist, lst_size, largest)
def build_max_heap(thelist, lst_size):
for curr_idx in range(lst_size // 2 - 1, -1, -1):
max_heapify(thelist, lst_size, curr_idx)
def heap_sort(thelist):
if len(thelist) == 0:
print("Empty list!!")
elif len(thelist) == 1:
print("Only one element!!")
else:
build_max_heap(thelist, len(thelist))
for curr_idx in range(len(thelist) -1, 0, -1):
thelist[curr_idx], thelist[0] = thelist[0], thelist[curr_idx]
max_heapify(thelist, curr_idx, 0)
There are two errors in your heapify function:
The second branch should not be an elif, but an if, since you'll want to select the right child, even if the left child is greater than its parent, but when the right child is even greater.
You don't want to use len(thelist) there, as your function should rely on the argument lst_size. This is needed because in the heap_sort function calls are made that pass a value for this argument that is (and must be) less than the actual list length.
So change:
elif right_child < len(thelist) and thelist[right_child] > thelist[largest]:
to:
if right_child < lst_size and thelist[right_child] > thelist[largest]:
When recursively passing this string into this counting function, and declaring a set as a mutable function parameter to keep track of the results through the recursion, everything seems to work fine when stepping through with a debugger (and also by the print statements in the end test case), however the return result is None. What's going on here that's causing that?
def count_ways(data, l = set()):
if len(data) == 0:
print(l) # Shows my set has stuff
print(len(l)) # Shows my set has length
return(len(l)) # Why is None being returned?!
one_dig = int(data[:1])
two_digs = int(data[:2])
if (one_dig > 0):
l.add(one_dig)
if (10 <= two_digs <= 26):
l.add(two_digs)
count_ways(data[1:])
print(count_ways("124136"))
You need to return from the non-edge condition as well.
def count_ways(data, l = set()):
if len(data) == 0:
print(l) # Shows my set has stuff
print(len(l)) # Shows my set has length
return(len(l)) # Why is None being returned?!
one_dig = int(data[:1])
two_digs = int(data[:2])
if (one_dig > 0):
l.add(one_dig)
if (10 <= two_digs <= 26):
l.add(two_digs)
return count_ways(data[1:]) # return this!!
print(count_ways("124136"))
Just in case you're interested in another option, you don't really need the argument. You can just return the union of a local set with the result of the recursion:
def count_ways(data):
l = set()
if len(data) == 0:
return l
one_dig = int(data[:1])
two_digs = int(data[:2])
if (one_dig > 0):
l.add(one_dig)
if (10 <= two_digs <= 26):
l.add(two_digs)
return l | count_ways(data[1:])
print(count_ways("124136"))
# {1, 2, 3, 4, 6, 12, 13, 24}
I am trying to implement the binary search in python and have written it as follows. However, I can't make it stop whenever needle_element is larger than the largest element in the array.
Can you help? Thanks.
def binary_search(array, needle_element):
mid = (len(array)) / 2
if not len(array):
raise "Error"
if needle_element == array[mid]:
return mid
elif needle_element > array[mid]:
return mid + binary_search(array[mid:],needle_element)
elif needle_element < array[mid]:
return binary_search(array[:mid],needle_element)
else:
raise "Error"
It would be much better to work with a lower and upper indexes as Lasse V. Karlsen was suggesting in a comment to the question.
This would be the code:
def binary_search(array, target):
lower = 0
upper = len(array)
while lower < upper: # use < instead of <=
x = lower + (upper - lower) // 2
val = array[x]
if target == val:
return x
elif target > val:
if lower == x: # these two are the actual lines
break # you're looking for
lower = x
elif target < val:
upper = x
lower < upper will stop once you have reached the smaller number (from the left side)
if lower == x: break will stop once you've reached the higher number (from the right side)
Example:
>>> binary_search([1,5,8,10], 5) # return 1
1
>>> binary_search([1,5,8,10], 0) # return None
>>> binary_search([1,5,8,10], 15) # return None
Why not use the bisect module? It should do the job you need---less code for you to maintain and test.
array[mid:] creates a new sub-copy everytime you call it = slow. Also you use recursion, which in Python is slow, too.
Try this:
def binarysearch(sequence, value):
lo, hi = 0, len(sequence) - 1
while lo <= hi:
mid = (lo + hi) // 2
if sequence[mid] < value:
lo = mid + 1
elif value < sequence[mid]:
hi = mid - 1
else:
return mid
return None
In the case that needle_element > array[mid], you currently pass array[mid:] to the recursive call. But you know that array[mid] is too small, so you can pass array[mid+1:] instead (and adjust the returned index accordingly).
If the needle is larger than all the elements in the array, doing it this way will eventually give you an empty array, and an error will be raised as expected.
Note: Creating a sub-array each time will result in bad performance for large arrays. It's better to pass in the bounds of the array instead.
You can improve your algorithm as the others suggested, but let's first look at why it doesn't work:
You're getting stuck in a loop because if needle_element > array[mid], you're including element mid in the bisected array you search next. So if needle is not in the array, you'll eventually be searching an array of length one forever. Pass array[mid+1:] instead (it's legal even if mid+1 is not a valid index), and you'll eventually call your function with an array of length zero. So len(array) == 0 means "not found", not an error. Handle it appropriately.
This is a tail recursive solution, I think this is cleaner than copying partial arrays and then keeping track of the indexes for returning:
def binarySearch(elem, arr):
# return the index at which elem lies, or return false
# if elem is not found
# pre: array must be sorted
return binarySearchHelper(elem, arr, 0, len(arr) - 1)
def binarySearchHelper(elem, arr, start, end):
if start > end:
return False
mid = (start + end)//2
if arr[mid] == elem:
return mid
elif arr[mid] > elem:
# recurse to the left of mid
return binarySearchHelper(elem, arr, start, mid - 1)
else:
# recurse to the right of mid
return binarySearchHelper(elem, arr, mid + 1, end)
def binary_search(array, target):
low = 0
mid = len(array) / 2
upper = len(array)
if len(array) == 1:
if array[0] == target:
print target
return array[0]
else:
return False
if target == array[mid]:
print array[mid]
return mid
else:
if mid > low:
arrayl = array[0:mid]
binary_search(arrayl, target)
if upper > mid:
arrayu = array[mid:len(array)]
binary_search(arrayu, target)
if __name__ == "__main__":
a = [3,2,9,8,4,1,9,6,5,9,7]
binary_search(a,9)
Using Recursion:
def binarySearch(arr,item):
c = len(arr)//2
if item > arr[c]:
ans = binarySearch(arr[c+1:],item)
if ans:
return binarySearch(arr[c+1],item)+c+1
elif item < arr[c]:
return binarySearch(arr[:c],item)
else:
return c
binarySearch([1,5,8,10,20,50,60],10)
All the answers above are true , but I think it would help to share my code
def binary_search(number):
numbers_list = range(20, 100)
i = 0
j = len(numbers_list)
while i < j:
middle = int((i + j) / 2)
if number > numbers_list[middle]:
i = middle + 1
else:
j = middle
return 'the index is '+str(i)
If you're doing a binary search, I'm guessing the array is sorted. If that is true you should be able to compare the last element in the array to the needle_element. As octopus says, this can be done before the search begins.
You can just check to see that needle_element is in the bounds of the array before starting at all. This will make it more efficient also, since you won't have to do several steps to get to the end.
if needle_element < array[0] or needle_element > array[-1]:
# do something, raise error perhaps?
It returns the index of key in array by using recursive.
round() is a function convert float to integer and make code fast and goes to expected case[O(logn)].
A=[1,2,3,4,5,6,7,8,9,10]
low = 0
hi = len(A)
v=3
def BS(A,low,hi,v):
mid = round((hi+low)/2.0)
if v == mid:
print ("You have found dude!" + " " + "Index of v is ", A.index(v))
elif v < mid:
print ("Item is smaller than mid")
hi = mid-1
BS(A,low,hi,v)
else :
print ("Item is greater than mid")
low = mid + 1
BS(A,low,hi,v)
BS(A,low,hi,v)
Without the lower/upper indexes this should also do:
def exists_element(element, array):
if not array:
yield False
mid = len(array) // 2
if element == array[mid]:
yield True
elif element < array[mid]:
yield from exists_element(element, array[:mid])
else:
yield from exists_element(element, array[mid + 1:])
Returning a boolean if the value is in the list.
Capture the first and last index of the list, loop and divide the list capturing the mid value.
In each loop will do the same, then compare if value input is equal to mid value.
def binarySearch(array, value):
array = sorted(array)
first = 0
last = len(array) - 1
while first <= last:
midIndex = (first + last) // 2
midValue = array[midIndex]
if value == midValue:
return True
if value < midValue:
last = midIndex - 1
if value > midValue:
first = midIndex + 1
return False
I'm having trouble writing a function in python that will take a list, split it into 2 equal sides and then recursively add each element in each half. In the end returning the sum of both halves.
def sumLists(aList):
half = len(aList)//2
leftHalf = aList[half:]
rightHalf = aList[:half]
if len(aList) == 1:
return aList[0]
else:
sumOfLeft = sumLists(leftHalf[1:])
resultLeft = leftHalf[0] + sumOfLeft
sumOfRight = sumLists(rightHalf[1:])
resultRight = rightHalf[0] + sumOfRight
return resultLeft + resultRight
Any tips are appreciated, thanks!
You're overcomplicating the else block. You don't need to call sumLists on leftHalf[1:] and rightHalf[1:] and manually add the first respective elements; it suffices to call sumLists on the complete lists.
This slicing is what's causing your RuntimeError. A leftHalf with length one will have a leftHalf[1:] of length zero. But your function recurses forever for lengths of length zero because you didn't write an if case for that scenario.
You could rewrite your else so that it doesn't require slicing:
def sumLists(aList):
half = len(aList)//2
leftHalf = aList[half:]
rightHalf = aList[:half]
if len(aList) == 1:
return aList[0]
else:
return sumLists(leftHalf) + sumLists(rightHalf)
... Or you could add a special case for empty lists:
def sumLists(aList):
half = len(aList)//2
leftHalf = aList[half:]
rightHalf = aList[:half]
if len(aList) == 0:
return 0
elif len(aList) == 1:
return aList[0]
else:
sumOfLeft = sumLists(leftHalf[1:])
resultLeft = leftHalf[0] + sumOfLeft
sumOfRight = sumLists(rightHalf[1:])
resultRight = rightHalf[0] + sumOfRight
return resultLeft + resultRight
Or both:
def sumLists(aList):
half = len(aList)//2
leftHalf = aList[half:]
rightHalf = aList[:half]
if len(aList) == 0:
return 0
if len(aList) == 1:
return aList[0]
else:
return sumLists(leftHalf) + sumLists(rightHalf)
I think aList[half:] is the right side, and aList[:half] is the left side, is it right?
the follow code will sum the list left and right side, hope this can solve your problem.
def sumlist(l):
if not l or not isinstance(l, list):
return 0 # or return other default value.
if len(l) == 1:
return l[0]
half = len(l) // 2
left = l[:half] # left
right = l[-half:] # right
return sumlist(left) + sumlist(right)
test:
l = [1,2,3,4,5,6,7,8,9]
result = sumlist(l)
print(result) # 40
Maybe I misread your question, but do you actually need to do both things in one function?
To sum a list recursively, you could define that the empty list (your base case) has the sum 0. Any non-empty list has the sum of the first element plus the sum of the remainder (the "tail") of the list:
def sumList(a):
return 0 if not a else a[0] + sumList(a[1:])
To split a list recursively, you could keep track of the "left" and "right" list. The left list starts out being your input, the right list is empty. You then recursively prepend the last element of the left list to the right list until the right list is no longer shorter than the left:
def splitList(a, b=None):
b = b or []
return (a, b) if len(a) <= len(b) else splitList(a[:-1], [a[-1]] + b)
I suspect that passing around slices of lists is very inefficient in Python, so it might be better to rather pass around indices, e.g.
def sumList(a, idx=None):
idx = idx or 0
return 0 if idx >= len(a) else a[idx] + sumList(a, idx+1)