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)
Related
I am working on a python algorithm to find the most frequent element in the list.
def GetFrequency(a, element):
return sum([1 for x in a if x == element])
def GetMajorityElement(a):
n = len(a)
if n == 1:
return a[0]
k = n // 2
elemlsub = GetMajorityElement(a[:k])
elemrsub = GetMajorityElement(a[k:])
if elemlsub == elemrsub:
return elemlsub
lcount = GetFrequency(a, elemlsub)
rcount = GetFrequency(a, elemrsub)
if lcount > k:
return elemlsub
elif rcount > k:
return elemrsub
else:
return None
I tried some test cases. Some of them are passed, but some of them fails.
For example, [1,2,1,3,4] this should return 1, buit I get None.
The implementation follows the pseudocode here:
http://users.eecs.northwestern.edu/~dda902/336/hw4-sol.pdf
The pseudocode finds the majority item and needs to be at least half. I only want to find the majority item.
Can I get some help?
Thanks!
I wrote an iterative version instead of the recursive one you're using in case you wanted something similar.
def GetFrequency(array):
majority = int(len(array)/2)
result_dict = {}
while array:
array_item = array.pop()
if result_dict.get(array_item):
result_dict[array_item] += 1
else:
result_dict[array_item] = 1
if result_dict[array_item] > majority:
return array_item
return max(result_dict, key=result_dict.get)
This will iterate through the array and return the value as soon as one hits more than 50% of the total (being a majority). Otherwise it goes through the entire array and returns the value with the greatest frequency.
def majority_element(a):
return max([(a.count(elem), elem) for elem in set(a)])[1]
EDIT
If there is a tie, the biggest value is returned. E.g: a = [1,1,2,2] returns 2. Might not be what you want but that could be changed.
EDIT 2
The pseudocode you gave divided into arrays 1 to k included, k + 1 to n. Your code does 1 to k - 1, k to end, not sure if it changes much though ? If you want to respect the algorithm you gave, you should do:
elemlsub = GetMajorityElement(a[:k+1]) # this slice is indices 0 to k
elemrsub = GetMajorityElement(a[k+1:]) # this one is k + 1 to n.
Also still according to your provided pseudocode, lcount and rcount should be compared to k + 1, not k:
if lcount > k + 1:
return elemlsub
elif rcount > k + 1:
return elemrsub
else:
return None
EDIT 3
Some people in the comments highligted that provided pseudocode solves not for the most frequent, but for the item which is present more that 50% of occurences. So indeed your output for your example is correct. There is a good chance that your code already works as is.
EDIT 4
If you want to return None when there is a tie, I suggest this:
def majority_element(a):
n = len(a)
if n == 1:
return a[0]
if n == 0:
return None
sorted_counts = sorted([(a.count(elem), elem) for elem in set(a)], key=lambda x: x[0])
if len(sorted_counts) > 1 and sorted_counts[-1][0] == sorted_counts[-2][0]:
return None
return sorted_counts[-1][1]
I'm learning the following codes.
def merge(left, right, compare):
"""Assumes left and right are sorted lists and compare defines an ordering on the elements.
Returns a new sorted (by compare) list containing the same elements as (left + right) would contain."""
result = []
i, j = 0, 0
while i < len(left) and j < len(right):
if compare(left[i], right[j]):
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
while (i < len(left)):
result.append(left[i])
i += 1
while (j < len(right)):
result.append(right[j])
j += 1
return result
def mergeSort(L, compare = lambda x, y: x < y):
"""Assumes L is a list, compare defines an ordering on elements of L
Returns a new sorted list with the same elements as L"""
if len(L) < 2:
return L[:]
else:
middle = len(L)//2
left = mergeSort(L[:middle], compare) # line A
right = mergeSort(L[middle:], compare) # line B
return merge(left, right, compare)
The book asked me to give an example L = [2,1,4,5,3]
Then type mergeSort(L) in the console turns out to be [1,2,3,4,5]
My questions lie in the middle of mergeSort.
Why "left" and "right" should return a sorted list (from the definition of function merge) after the above steps. Can anyone explain in details for what have happened when # line A & # line B are executed?
I substitute:
"left = mergeSort(L[:middle], compare)" into "left = mergeSort(L[:2], compare)".
However, whenever I run mergeSort(L), Python always tells me 'Kernel died, restarting' after this substitution. Why the output is so different in this case when middle == 2? What's wrong when I substitute 'middle' into an integer?
NOTE: all of the above codes are from Figure 10.5 of the book Introduction to Computation and Programming Using Python
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 getting the right output on my "Majority Element" divide and conquer algorithm implementation in Python 3.
This should be relatively correct; however, it would still appear that I'm missing something or it is slightly off and I cannot figure out why that is.
I've tried some debugging statement and different things. It looks like on the particular case listed in the comment above the code, it's resolving -1 for "left_m" and 941795895 for "right_m" when it does the recursive calls. When it compares the element at each index to those variables, the counter will obviously never increment.
Am I going about this the wrong way? Any help would be greatly appreciated.
Thanks.
# Input:
# 10
# 2 124554847 2 941795895 2 2 2 2 792755190 756617003
# Your output:
# 0
#
# Correct output:
# 1
def get_majority_element(a, left, right):
if left == right:
return -1
if left + 1 == right:
return a[left]
left_m = get_majority_element(a, left, (left + right - 1)//2)
right_m = get_majority_element(a, (left + right - 1)//2 + 1, right)
left_count = 0
for i in range(0, right):
if a[i] == left_m:
left_count += 1
if left_count > len(a)//2:
return left_m
right_count = 0
for i in range(0, right):
if a[i] == right_m:
right_count += 1
if right_count > len(a)//2:
return right_m
return -1
if __name__ == '__main__':
input = sys.stdin.read()
n, *a = list(map(int, input.split()))
if get_majority_element(a, 0, n) != -1:
print(1)
else:
print(0)
When counting the appearance of left and right major elements, your loops go over the range(0, right). Instead, they should be going over the range(left, right). Starting from 0 may, and will cause returning incorrect major elements in the smaller subproblems.
Also, in addition to the problem of having incorrect starting indices in ranges your for loops cover, you seem to have a problem in your recursive call arguments, probably due to your intuition causing you to overlook some details. Throughout the get_majority_element function, you treat parameter right to be the first index that is not in the list, as opposed to right being the index of the rightmost element in the list.
However, in your first recursive call, you give the third argument as if it is the last element included in that list. If right is the index of the first element not in that list, it should actually be the same with the second parameter of the second recursive call you're making in the following line. So, the third argument of the first recursive call you're making is less than it should be, by 1, causing you to overlook 1 element each time you recursively go down.
Thirdly, you have an error in the if statements following the for loops, similar to the problem you had with loop ranges. You are dividing the occurances of the element for all len(a) elements, although you should only care about the subproblem you are currently working on. So, you should divide it by the number of elements in that subproblem, rather than len(a). (i.e. (right - left)//2)
You can find the working code below, and look here in order to observe it's execution.
def get_majority_element(a, left, right):
if left == right:
return -1
if left + 1 == right:
return a[left]
left_m = get_majority_element(a, left, (left + right - 1)//2 + 1)
right_m = get_majority_element(a, (left + right - 1)//2 + 1, right)
left_count = 0
for i in range(left, right):
if a[i] == left_m:
left_count += 1
if left_count > (right-left)//2:
return left_m
right_count = 0
for i in range(left, right):
if a[i] == right_m:
right_count += 1
if right_count > (right-left)//2:
return right_m
return -1
if __name__ == '__main__':
input = sys.stdin.read()
n, *a = list(map(int, input.split()))
print("n=" + str(n))
if get_majority_element(a, 0, len(a)) != -1:
print(1)
else:
print(0)
I am trying to use Boyers and Moore's algorithm to find the majority element among a list. I am using a inbuilt function, count; so, if the majority element is greater than half size of the list then it gives output of 1, otherwise 0. You can find more in this link about Boyers and Moore's Algorithm on finding majority Algorithm information here
# Uses python3
import sys
def get_majority_element(a,n):
maximum = a[0]
amount = 1
for i in (a[1:]):
if not maximum == i:
if amount >= 1:
amount = amount - 1
else:
maximum = i
amount = 1
else:
amount = amount + 1
output = a.count(maximum)
if output > n//2:
return 1
return 0
if __name__ == '__main__':
input = sys.stdin.read()
n, *a = list(map(int, input.split()))
print (get_majority_element(a,n))
I have been looking at this for the past couple hours and can still not understand where I have messed up. I keep getting Index out of bounds errors like below:
Each small edit or change i have done, has run me into another error, then i end back up here after trying to simplify my code.
def quickSort(alist):
firstList = []
secondList = []
thirdList = []
if(len(alist) > 1):
#pivot = pivot_leftmost(alist)
#pivot = pivot_best_of_three(alist)
pivot = pivot_ninther(alist)
#pivot = pivot_random(alist)
for item in alist:
if(item < pivot):
firstList.append(item)
if(item == pivot):
secondList.append(item)
if(item > pivot):
thirdList.append(item)
sortedList = quickSort(firstList) + secondList + quickSort(thirdList)
return sortedList
else:
print("list:", alist)
print("sorted, nothing to do") #debug
print("") #debug
return alist
def pivot_ninther(alist):
listLength = int(len(alist))
third = int(listLength / 3)
leftList = alist[:third]
midlist = alist[third:(third * 2)]
lastlist = alist[(third * 2):(third * 3)]
leftBest = pivot_best_of_three(leftList)
midBest = pivot_best_of_three(midlist)
lastBest = pivot_best_of_three(lastlist)
pivots = [leftBest, midBest, lastBest]
return pivot_best_of_three(pivots)
I am pretty sure a fresh pair of eyes can easily find it, but i have been lookig at it for hours. Thanks!
UPDATE: (My Best_of_three function)
def pivot_best_of_three(alist):
leftmost = 0
middle = int(len(alist) / 2)
rightmost = len(alist) - 1
if (alist[leftmost] <= alist[middle] <= alist[rightmost] or alist[rightmost] <= alist[middle] <= alist[leftmost]):
return alist[middle]
elif (alist[middle] <= alist[leftmost] <= alist[rightmost] or alist[rightmost] <= alist[leftmost] <= alist[middle]):
return alist[leftmost]
else:
return alist[rightmost]
The IndexError occurs when pivot_best_of_three tries to find the rightmost member of a list of zero items. The simple way to fix that is to simply not pass it such lists. :)
Here are slightly modified versions of those functions. I've tested these versions with lists of various lengths, down to length zero, and they appear to function correctly.
def pivot_ninther(alist):
listLength = len(alist)
if listLength < 3:
return alist[0]
third = listLength // 3
leftList = alist[:third]
midlist = alist[third:-third]
lastlist = alist[-third:]
leftBest = pivot_best_of_three(leftList)
midBest = pivot_best_of_three(midlist)
lastBest = pivot_best_of_three(lastlist)
pivots = [leftBest, midBest, lastBest]
return pivot_best_of_three(pivots)
def pivot_best_of_three(alist):
leftmost = alist[0]
middle = alist[len(alist) // 2]
rightmost = alist[-1]
if (leftmost <= middle <= rightmost) or (rightmost <= middle <= leftmost):
return middle
elif (middle <= leftmost <= rightmost) or (rightmost <= leftmost <= middle):
return leftmost
else:
return rightmost
As you can see, I've simplified pivot_best_of_three so it doesn't index alist multiple times for the same value.
But it can be simplified further by using a simple sorting network:
def sort3(a, b, c):
if c < b: b, c = c, b
if b < a: a, b = b, a
if c < b: b, c = c, b
return a, b, c
def pivot_best_of_three(alist):
leftmost = alist[0]
middle = alist[len(alist) // 2]
rightmost = alist[-1]
return sort3(leftmost, middle, rightmost)[1]
Try a smaller count (<= 20) and check to see what happens in pivot_ninther() when third == 0 (at the deepest level of recursion)? Seems like it would create empty arrays and then try to index them.
The code should check to make sure length >= 9 before calling pivot_ninther(), then >= 3 if calling ...best_of_three(). If just one or two items, pick one.
Suggestion, after you get the quicksort to work, back up the source code and rather than make new arrays, the pivot function should work with the original array and first / middle / last indexes.
You can use swaps to simplify finding the median of 3. This will help in cases like starting with a reversed order array.
// median of 3
i = lo, j = (lo + hi)/2, k = hi;
if (a[k] < a[i])
swap(a[k], a[i]);
if (a[j] < a[i])
swap(a[j], a[i]);
if (a[k] < a[j])
swap(a[k], a[j]);
pivot = a[j];
wiki article:
http://en.wikipedia.org/wiki/Quicksort#Choice_of_pivot