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))
Related
example of a valley:
9,6,5,4,10,13,40,55,68
The list must be strictly decreasing until one point and then after the list must be strictly increasing. Then it is considered as a valley.
constraints:
Use two pointer approach
Guys, I have come up with this code:
def isValley(n,j,n1):
i = 0
res = False
while(i<j):
if (n[i]>n[i+1]) and (n[j]>n[j-1]):
n1.append(1)
else:
n1.append(0)
res = n1.count(n1[0]) == len(n1)
i+=1
j-=1
print(n1)
if res:
if(n1[0] == 1):
print("Valley")
else:
print("Not a valley")
else:
print("Not a valley")
n = list(map(int,input("Enter the numbers : ").split()))
n1 = []
j = len(n)-1
print(n)
isValley(n,j,n1)
my code is working only when the no of elements on the left side of the element is equal to
the number of elements on the right side of the element.
please correct this and come up with a code that even satisfies irrespective of the number
of elements left of the element and right of the element.
hint:
I think i have issue while making comparisions
(Use Two pointer Approach only)
Please help me out guys
I think you can just iterate from left to right (and from right to left), while the elements are strictly decreasing (increasing). Then it's a valley if and only if the pointers end up at the same location
def isValley(array):
N = len(array)
front_i = 0
back_i = N-1
while front_i < N-1 and array[front_i] > array[front_i + 1]:
front_i += 1
while back_i > 0 and array[back_i] > array[back_i - 1]:
back_i -= 1
is_valley = (front_i == back_i)
return is_valley
print(isValley([9,6,5,4,10,13,40,55,68])) # prints True
You can check that there is a strictly negative gradient followed by a strictly positive gradient. One way of doing this (using numpy) is:
import numpy as np
def isValley(array):
d = np.diff(array)
return (
np.array_equal(
np.concatenate((np.argwhere(d < 0), np.argwhere(d > 0))).flatten(),
np.arange(len(array) - 1)
)
)
I have an sort algorithm
def partition(competitors, left, right):
pivot = competitors[left]
i = left + 1
j = right - 1
while True:
if (i <= j and competitors[j] > pivot):
j -= 1
elif (i <= j and competitors[i] < pivot):
i += 1
elif (competitors[j] > pivot) or (competitors[i] < pivot):
continue
if i <= j:
competitors[i], competitors[j] = competitors[j], competitors[i]
else:
competitors[left], competitors[j] = competitors[j], competitors[left]
return j
def quick_sort(competitors, left, right):
if ((right - left) > 1):
p = partition(competitors, left, right)
quick_sort(competitors, left, p)
quick_sort(competitors, p + 1, right)
def transformation(competitors):
competitors[1] = - int(competitors[1])
competitors[2] = int(competitors[2])
return [competitors[1], competitors[2], competitors[0]]
if __name__ == '__main__':
number = int(input())
competitors = [transformation(input().split()) for _ in range(number)]
quick_sort(competitors, left=0, right=len(competitors))
print(*(list(zip(*competitors))[2]), sep="\n")
Here
pivot = competitors[left]
Reviewer said that i can get a pivot by divide first and last index in array.
I was try many options and one of that is
pivot = competitors[left // right]
But output is wrong
Here description of task
**
Let's get two pointers left and right, which appear on the left and right ends of the segment, respectively. Then we will move the left pointer to the right until it triggers an alarm on the element smaller than the pivot. Similarly, we move the right pointer to the left while it is on the element that exceeds the reference one.As a result, it turns out that to the left of left all elements exactly belong to the first group, and to the right of right - to the second. Elements with pointers are out of order. Let's swap them (most programming languages use the swap() function) and advance pointers to the next elements. We will repeat this action until left and right collide.
**
Input:
5
alla 4 100
gena 6 1000
gosha 2 90
rita 2 90
timofey 4 80
Output:
gena
timofey
alla
gosha
rita
And my output is: gena
timofey
alla
<rita>
<gosha>
Please help me to figure out how solve this algorithm
So this is a new algorithm, I was update it with pivot = competitors[(left + right) // 2] string
def partition(competitors, left, right):
if right <= left:
return
pivot = (left + right) // 2
part = competitors[pivot]
begin = left
end = right
while begin <= end:
while part > competitors[begin]:
begin += 1
while part < competitors[end]:
end -= 1
if begin <= end:
competitors[begin], competitors[end] = competitors[
end], competitors[begin]
begin += 1
end -= 1
partition(competitors, left, end)
partition(competitors, begin, right)
def quick_sort(competitors):
partition(competitors, 0, len(competitors) - 1)
return [line[2] for line in competitors]
if __name__ == '__main__':
n = int(input())
competitors = [None] * n
for x in range(n):
login, Pi, Fi = input().split()
competitors[x] = (-int(Pi), int(Fi), login)
result = quick_sort(competitors)
print(*result, sep="\n")
I'm trying to make a recursive function, which calculates the biggest sub-palindrome.
For example the biggest sub.Pal. for "character" is "carac".
So far I've achieved my goal but only with a global variable "length" where i'm adding my values, but it would be nice if someone could show me how to do this with only recursive calls. I first tried to give the function a second parameter (length=0) and to add the value to it when i'm calling the function,but i'm not getting it to work properly.
Here's my Code:
length = 0
def subpalindrom(s):
global length
if len(s) == 1:
length += 1
return True, length
if len(s) == 0:
return True, length
elif s[0] != s[-1]:
for i in range(len(s) - 1, int(len(s) / 2) - 1, -1): # search right half, if there is smth. equal
if s[0] == s[i]:
length += 2
return subpalindrom(s[1:i]) # if smth. is equal slice it, add length
elif i == int(len(s) / 2):
# if index i is at half of the string and nothing was found, continue with next val on left half
return subpalindrom(s[1:])
else:
length += 2
return subpalindrom(s[1:-1])
print(subpalindrom("character"))
And if anyone could tell me how i can see which time complexity this function has it would be more than great. I would say that it is O(log n) but it's just a guess.
Edit: T(n) = T(n-2) + n/2 ?
T(n-2) for recursive calls (because we slice 2 elements away) and + n/2 because of the for loop?
Thank you for your Time !
Sry for the late share,but if anyone is interested, here is how i handled it:
def subpalindrom(l, r, w):
if l == r:
return 1
if l > r:
return 0
if w[l] == w[r]:
return 2 + subpalindrom(l + 1, r - 1, w)
else:
return max(subpalindrom(l + 1, r, w), subpalindrom(l, r - 1, w))
print(subpalindrom(0, len("character")-1, "character"))
I am following the Stanford course "Algorithms: Design and Analysis, Part 1", while trying implement an in place randomized selection algorithm in Python (i.e. selection based on quick sort), I believe my partition function is correct, but I just cannot figure out why the selection part keeps failing, any suggestion is greatly appreciated. My code is as follows:
import random
def random_selection(nums, start, end, i):
if end == start:
return nums[start]
elif start < end:
pivot = partition(nums, start, end)
if pivot == i:
return nums[pivot]
elif pivot < i:
# original code suffering from logic error with indices, fixed by changing 'i - pivot' into 'i'
# return random_selection(nums, pivot + 1, end, i - pivot)
return random_selection(nums, pivot + 1, end, i)
elif pivot > i:
return random_selection(nums, start, pivot - 1, i)
else:
return False
def partition(nums, start, end):
pivot_value = nums[start]
left = start + 1
right = end
done = False
while not done:
while left <= right and nums[left] < pivot_value:
left += 1
while left <= right and nums[right] > pivot_value:
right -= 1
if left > right:
done = True
else:
nums[left], nums[right] = nums[right], nums[left]
nums[start], nums[right] = nums[right], nums[start]
return right
test = range(10)
for i in range(10):
random.shuffle(test)
print random_selection(test, 0, len(test)-1, i)
Below are the results I am receiving with the test case:
0
1
None
3
4
None
5
4
8
None
The problem is you need to decide whether your indices are based on 0, or based on start.
Most of the code uses indices based on 0, except the recursive call to random_selection:
return random_selection(nums, pivot + 1, end, i - pivot)
which adjusts the i index to i - start (i.e. assuming the indices are based on start).
Changing this to:
return random_selection(nums, pivot + 1, end, i)
should give the expected results.
Okay. I give up. I've been trying to implement the median of medians algorithm but I am continually given the wrong result. I know there is a lot of code below, but I can't find my error, and each chunk of code has a fairly process design. Quicksort is what I use to sort the medians I get from the median of medians pivot selection. Should be a straightforward quicksort implementation. getMean simply returns the mean of a given list.
getPivot is what I use to select the pivot. It runs through the list, taking 5 integers at a time, finding the mean of those integers, placing that mean into a list c, then finding the median of c. That is the pivot I use for the dSelect algorithm.
The dSelect algorithm is simple in theory. The base case returns an item when the list is 1 item long. Otherwise, much like in quickSort, I iterate over the list. If the number I am currently on, j, is less than the pivot, I move it to the left of the list, i, and increment i. If it is larger, I move it to the right of the list, i + 1, and do not increment i. After this loops through the entire list, I should have the pivot in its proper index, and print statements indicate that I do. At this point, I recurse to the left or the right depending on whether the pivot is greater than or less than the position I am trying to find.
I am not sure what other print statements to test at this point, so I'm turning to anyone dedicated enough to take a stab at this code. I know there are related topics, I know I could do more print statements, but believe me, I've tried. What should be a simple algo has got me quite stumped.
def quickSort(m, left, right):
if right - left <= 1:
return m
pivot = m[left]
i = left + 1
j = left + 1
for j in range(j, right):
if m[j] < pivot:
m[j], m[i] = m[i], m[j]
i += 1
elif m[j] == pivot:
m[j], m[i] = m[i], m[j]
print m
m[left], m[i-1] = m[i-1], m[left]
m = quickSort(m, left, i-1)
m = quickSort(m, i, right)
print m
return m
def getMedian(list):
length = len(list)
if length <= 1:
return list[0]
elif length % 2 == 0:
i = length/2
return list[i]
else:
i = (length + 1)/2
return list[i]
def getPivot(m):
c = []
i = 0
while i <= len(m) - 1:
tempList = []
j = 0
while j < 5 and i <= len(m) - 1:
tempList.append(m[i])
i = i + 1
j = j + 1
tempList = quickSort(tempList, 0, len(tempList) - 1)
c.append(getMedian(tempList))
c = quickSort(c, 0, len(c) - 1)
medianOfMedians = getMedian(c)
return medianOfMedians
def dSelect(m, position):
pivot = getPivot(m)
i = 0
j = 0
if len(m) <= 1:
return m[0]
for j in range(0, len(m)):
if m[j] < pivot:
m[j], m[i] = m[i], m[j]
i += 1
elif m[j] == pivot:
m[j], m[i] = m[i], m[j]
print "i: " + str(i)
print "j: " + str(j)
print "index of pivot: " + str(m.index(pivot))
print "pivot: " + str(pivot) + " list: " + str(m)
if m.index(pivot) == position:
return pivot
elif m.index(pivot) > position:
return dSelect(m[0:i], position)
else:
return dSelect(m[i:], position - i)
The biggest issue is with this line here:
i = (length + 1)/2
if list = [1, 2, 3, 4, 5, 6, 7] the answer should be 4 which is list[3]. Your version looks like the following:
i = (7 + 1) / 2
and so i is equal to 4 instead of 3. Similar problem with the even length list part although that shouldn't be as big of an issue.