The following is a class of heap. I am trying to sort the heap but i have a problem with my max_heapify function. I have inserted the values [10, 9, 7, 6, 5, 4, 3] and my heap sort prints the given output. The given output and expected output is given below the class
class of heap
class Heap(object):
def __init__(self):
self.A = []
def insert(self, x):
self.A.append(x)
def Max(self):
"""
returns the largest value in an array
"""
return max(self.A)
def extractMax(self):
"""
returns and remove the largest value from an array
"""
x = max(self.A)
self.A.remove(x)
self.max_heapify(0)
return x;
def parent(self, i):
"""
returns the parent index
"""
i+=1
i = int(i/2)
return i
def left(self, i):
"""
returns the index of left child
"""
i = i+1
i = 2*i
return i
def right(self, i):
"""
returns the index of right child
"""
i+=1;
i = 2*i + 1
return i
def heap_size(self):
"""
returns the size of heap
"""
return len(self.A)
def max_heapify(self, i):
"""
heapify the array
"""
l = self.left(i)
r = self.right(i)
if(l < self.heap_size() and self.A[l] > self.A[i]):
largest = l
else:
largest = i
if(r < self.heap_size() and self.A[r] > self.A[largest]):
largest = r
if largest != i:
temp = self.A[i]
self.A[i] = self.A[largest]
self.A[largest] = temp
self.max_heapify(largest)
def build_max_heap(self):
n = len(self.A)
n = int(n/2)
for i in range(n, -1, -1):
self.max_heapify(i)
def heap_sort(self):
"""
sorts the heap
"""
while self.heap_size() > 0:
self.build_max_heap()
temp = self.A[0]
n = len(self.A) - 1
self.A[0] = self.A[n]
self.A[n] = temp
x = self.A.pop()
print(x)
self.max_heapify(0)
h = Heap()
h.insert(10)
h.insert(9)
h.insert(7)
h.insert(6)
h.insert(5)
h.insert(4)
h.insert(3)
h.heap_sort()
given output
10
7
6
5
4
3
9
expected output
10
9
7
6
5
4
3
It looks like you're trying to build a max-heap with the root at A[0]. If that's correct, then your left, right, and parent index calculations are not correct. You have:
def parent(self, i):
"""
returns the parent index
"""
i+=1
i = int(i/2)
return i
def left(self, i):
"""
returns the index of left child
"""
i = i+1
i = 2*i
return i
def right(self, i):
"""
returns the index of right child
"""
i+=1;
i = 2*i + 1
return i
So if i=0, the left child would be 2, and the right child would be 3. Worse, given i=3, parent will return 2. So you have the case where parent(right(i)) != i. That's never going to work.
The correct calculations are:
left = (2*i)+1
right = (2*i)+2
parent = (i-1)/2
I don't know why your extractMax is calling max(self.A). You already know that the maximum element is at A[0]. To extract the maximum item, all you need to do is:
returnValue = save value at self.A[0]
take last item in the array and place at self.A[0]
decrease length of array
maxHeapify(0)
I've used pseudo-code because I'm not particularly comfortable with Python.
The loop inside your heapSort method is seriously non-optimum. You're calling self.build_max_heap at each iteration. You don't need to do that. If extractMax is working correctly, all you have to do is:
while self.heap_size() > 0:
temp = self.extractMax()
print temp
Now, if you want to sort the array in-place, so that self.A itself is sorted, that's a bit more tricky. But it doesn't look like that's what you're trying to do.
Related
The task:
Write a function that receives 3 lists and returns an array. The first list contains n integers, their values range between 0 and 10^9. "numbers".
The second list is a low-range list, which contains the lower end of a range, it contains q integers. "low".
The third list is a high-range list, which contains the higher end of a range, it contains q integers. "high".
The function should return a list that contains the number of integers in the first list, that fall in its range, given by the low-range and high-range lists.
In the returned list, at index i, there should be the number of integers in "numbers" which are bigger or equal to low[i] and smaller or equal to high[i].
You can only import math, no other imports are allowed
the list may not be sorted
Examples:
count_range([12,13,14,15,17],[14],[14]) should return [1]
count_range([12,13,14,15,17],[14,15],[14,18]) should return [1,2]
count_range([12,13,14,15,17],[12],[17]) should return [5]
This is my solution but it's not efficient enough, I need ways to optimize it or solve it differently without having to import any external packages.
def binarySearch(data, val):
highIndex = len(data) - 1
lowIndex = 0
while highIndex > lowIndex:
index = math.ceil((highIndex + lowIndex) / 2)
sub = data[index]
if sub > val:
if highIndex == index:
return sorted([highIndex, lowIndex])
highIndex = index
else:
if lowIndex == index:
return sorted([highIndex, lowIndex])
lowIndex = index
return sorted([highIndex, lowIndex])
def count_range(numbers, low, high):
numbers.sort()
result = []
low_range_dict = {}
high_range_dict = {}
for i in range(len(numbers)):
if numbers[i] not in low_range_dict:
low_range_dict[numbers[i]] = i
high_range_dict[numbers[i]] = i
for i in range(len(low)):
low_r = low[i]
high_r = high[i]
if low_r not in low_range_dict:
low_range_dict[low_r] = binarySearch(numbers, low_r)[0]
high_range_dict[low_r] = low_range_dict[low_r]
low_index = low_range_dict.get(low_r)
if high_r not in high_range_dict:
high_range_dict[high_r] = binarySearch(numbers, high_r)[0]
low_range_dict[high_r] = high_range_dict[high_r]
high_index = high_range_dict.get(high_r)
if low_r in numbers or low_r < numbers[0]:
low_index -= 1
result.append(high_index - low_index)
return result
If we could use any module from the standard library, we could do write a very simple solution.
from bisect import bisect_left
from functools import lru_cache, partial
def count_range(numbers, lows, highs):
index = lru_cache()(partial(bisect_left, sorted(numbers)))
return [index(hi + 1) - index(lo) for (lo, hi) in zip(lows, highs)]
But we can write our own (simplified) equivalent of partial, lru_cache and bisect_left, so the imports are not needed.
It is less complicated than your original code, and should probably run faster, but I don't know how big the difference is.
We'll use a simpler bisect function for the binary search. And we don't need two different memoization dictionaries for high and low range.
# This bisect is based on the reference implementation in the standard library.
# in cpython this is actually implemented in C, and is faster.
def bisect_left(a, x):
"""Return the index where to insert item x in list a, assuming a is sorted."""
lo, hi = 0, len(a)
while lo < hi:
mid = (lo + hi) // 2
if a[mid] < x:
lo = mid + 1
else:
hi = mid
return lo
def count_range(numbers, lows, highs):
numbers.sort()
# instead of both low_range_dict and high_range_dict
# we only need a single memoization dictionary.
# We could also use #functools.cache from the standard library
memo = {}
def index(val):
"""Memoized bisect"""
if not val in memo:
memo[val] = bisect_left(numbers, val)
return memo[val]
return [index(hi + 1) - index(lo) for (lo, hi) in zip(lows, highs)]
I am trying to find to the largest numeric palindrome that is a product of two numbers in a given range. First, I've written a simple function to check if the number is indeed a palindrome:
import math
def check_palindrome(n):
if n == 0: //O is a palindrome
return True
else:
check = [0]
i = 1 //Find the power of the number
while (n/i) >= 10:
i = i*10
m = n
j = 0
while i >= 1: //Add each digit to a list
j = math.floor(m/i)
check.append(j)
m = m-(j*i)
i = i/10
length = len(check)
if length == 1: //One digit number is always a palindrome
return True
else:
i = 1 //Check if list is a palindrome
while i <= length/2:
if check[i] != check[-i]:
return False
i += 1
return True
Next, I've implemented a priority queue and declared a class that contains a factor, the current number in the given range that is being multiplied by that factor, and functions for returning the value of this product and moving to the next lowest number.
import heapq
class PriorityQueue:
def __init__(self):
self.items = []
def push(self, priority, x):
heapq.heappush(self.items, (-priority, x))
def pop(self):
_, x = heapq.heappop(self.items)
return x
def empty(self):
return not self.items
class Products:
def __init__(self, factor, current):
self.f = factor
self.c = current
def value(self):
return self.f*self.c
def move(self):
self.c -= 1
Finally, the main function, which fills the priority queue with Product classes containing each factor between min and max and initially set to multiply by itself, given priority by the magnitude of its product, then pops the Product with the highest product and checks if it is a palindrome and if not requeues it with the number the factor is being multiplied by set one lower and continues to check the next highest Product until it finds a palindrome.
def max_palindrome(maximum, minimum):
q = PriorityQueue()
i = maximum
while i >= minimum:
p = Products(i, i)
q.push(p.value(), p)
i -= 1
check = False
while not check:
p = q.pop()
check = check_palindrome(p.value())
if not check and p.c > minimum:
p.move()
q.push(p.value(), p)
return p.value()
My problem is that max_palindrome() returns the correct answer up to (329,0), but range with a maximum of 330 or greater returns the error:
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
max_palindrome(330,0)
File "C:\Users\Alec Collins\Documents\Euler\problem 4.py", line 67, in max_palindrome
p = q.pop()
File "C:\Users\Alec Collins\Documents\Euler\problem 4.py", line 52, in pop
_, x = heapq.heappop(self.items)
TypeError: unorderable types: Products() < Products().
Clearly something is up with the priority queue so the pop is not working but I have no idea what. Any ideas?
When a heap has two items with the same priority*, it compares their values using the "less than" operator to determine their comparative order. But your Products class doesn't implement that operator.
Try implementing __lt__ for your class.
class Products:
def __init__(self, factor, current):
self.f = factor
self.c = current
def value(self):
return self.f*self.c
def move(self):
self.c -= 1
def __lt__(self, other):
return self.value() < other.value()
(*this is something of a simplification; the heap algorithm does not have a native conception of "priority". But the outcome is the same; when you store two-element tuples in a heap, the second elements of each tuple are only compared when the first elements are equal, because that's how tuple comparison always works in Python.)
I am trying to convert a number to a linked list (e.g. 617 to 7->1->6)
here is my code:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# #param l1: the first list
# #param l2: the second list
# #return: the sum list of l1 and l2
def addLists(self, l1, l2):
# write your code here
num_1 = num_2 = 0
counter = 1
# convert each linked list to an integer
while l1 != None:
num_1 += l1.val * counter
l1 = l1.next
counter *= 10
# reset counter
counter = 1
while l2 != None:
num_2 += l2.val * counter
l2 = l2.next
counter *= 10
# perform the addition
my_sum = num_1 + num_2
# convert the sum back to a linked list
# initialize head
sum_head = ListNode(my_sum % 10)
sum_node = sum_head
my_sum //= 10
while my_sum != 0:
sum_node.next = ListNode(my_sum % 10)
sum_node = sum_node.next
my_sum //= 10
# return the the linked list
return sum_head
I coded this part and this piece of code works. I just don't understand why the "sum_head" is able to link to the second node "sum_node".
Here is an example in Python:
a = <Object>
b = a
b is just a reference to a, is this correct?
Say convert 617 to 7->1->6. Followed my code, the head is 7 and the rest of the linked list is 7->1->6. How can the head knows that the next node is 1?
The first two variables aren't "linked" in the linked-list sense. They are the same object. This might be clearer if it is substituted for an equivalent expression:
sum_head = ListNode(my_sum % 10)
sum_node = sum_head
# ==
sum_node = sum_head = ListNode(my_sum % 10)
# So: sum_node.next is sum_head.next
Why do we need two variables pointing to to the same object? Because in the following lines, we change what the sum_node points to. It will become the .next of the object it previously was. Since there is no way to go back, we need to keep a reference of the head to return it.
I am trying to code this problem:
This problem is about sequences of positive integers a1,a2,...,aN. A
subsequence of a sequence is anything obtained by dropping some of the
elements. For example, 3,7,11,3 is a subsequence of
6,3,11,5,7,4,3,11,5,3 , but 3,3,7 is not a subsequence of
6,3,11,5,7,4,3,11,5,3 .
Given a sequence of integers your aim is to find the length of the longest fully dividing subsequence of this sequence.
A fully dividing sequence is a sequence a1,a2,...,aN where ai divides
aj whenever i < j. For example, 3, 15, 60, 720 is a fully dividing
sequence.
My code is:
n=input()
ar=[]
temp=0
for i in range (0,n):
temp=input()
ar.append(temp)
def best(i):
if i==0:
return (1)
else:
ans =1
for j in range (0,i):
if (ar[j]%ar[i]==0):
ans=max(ans,(best(j)+1))
return (ans)
an=[]
for i in range (0,n):
temp=best(i)
an.append(temp)
print max(an)
the input was
9
2
3
7
8
14
39
145
76
320
and I should get 3 (because of 2, 8, 320) as output but I am getting 1
As j < i, you need to check whether a[j] is a divider of a[i], not vice versa. So this means you need to put this condition (and only this one, not combined with the inverse):
if (ar[i]%ar[j]==0):
With this change the output for the given sample data is 3.
The confusion comes from the definition, in which i < j, while in your code j < i.
This solves your problem without using any recursion :)
n = int(input())
ar = []
bestvals = []
best_stored = []
for x in range(n):
ar.append(int(input()))
best_stored.append(0)
best_stored[0] = 1
for i in range(n):
maxval = 1
for j in range(i):
if ar[i] % ar[j] == 0:
maxval = max(maxval,(best_stored[j])+1)
best_stored[i] = maxval
print(max(best_stored))
For the graph theory solution I alluded to in a comment:
class Node(object):
def __init__(self, x):
self.x = x
self.children = []
def add_child(self, child_x):
# Not actually used here, but a useful alternate constructor!
new = self.__class__(child_x)
self.children.append(new)
return new
def how_deep(self):
"""Does a DFS to return how deep the deepest branch goes."""
maxdepth = 1
for child in self.children:
maxdepth = max(maxdepth, child.how_deep()+1)
return maxdepth
nums = [9, 2, 3, 7, 8, 14, 39, 145, 76, 320]
nodes = [Node(num) for num in nums]
for i,node in enumerate(nodes):
for other in nodes[i:]:
if other.x % node.x == 0:
node.children.append(other)
# graph built, rooted at nodes[0]
result = max([n.how_deep() for n in nodes])
I am trying to figure out how to print the lowest k values in a binary search tree. I an having trouble stopping the method
code:
def kthSmallestBST(node,k, count):
if node == None or count == k:
return
else:
kthSmallestBST(node.left, k, count)
count += 1
print node.data
kthSmallestBST(node.right, k, count)
count += 1
kthSmallestBST(BST, 3, 0)
Currently my output simply printed the whole tree inorder
It's a rather "functional programming" solution, but one way is to generate (lazily) the nodes in the tree in order, and then using itertools to just take the first k.
def inorder(tree):
if not tree: return
for node in inorder(tree.left): yield node
yield tree
for node in inorder(tree.right): yield node
def least(tree, k):
return itertools.islice(inorder(tree), k)
If you're using Python 3, you can use "yield from" to make this solution shorter.
Changes to the value of count don't propagate back up to the caller. You need to return the new count:
def kthSmallestBST(node,k, count):
if node is None or count >= k:
return 0
else:
count += kthSmallestBST(node.left, k, count)
if count < k:
print node.data
count += 1
count += kthSmallestBST(node.right, k, count)
return count
Also note you don't need both k and count. You can get rid of count, decrement k instead of incrementing count, and compare k against 0 (instead of against count). Here's what you get:
def kthSmallestBST(node, k):
if node is None or k <= 0:
return 0
k = kthSmallestBST(node.left, k)
if k > 0:
print node.data
k -= 1
k = kthSmallestBST(node.right, k)
return k
You need to change things around a bit so you know how many elements were found during the recursive call. Have the function return the number of elements it found an add them up. Also you need to check the count between the recursive calls and the current node's element.
Something like:
def kthSmallestBST(node, k, count):
if node == None or count == k:
return 0
else:
count += kthSmallestBST(node.left, k, count)
if(count == k)
return count
print node.data
count += 1
count += kthSmallestBST(node.right, k, count)
return count
import unittest
class BST(object):
def __init__(self, key):
self.key = key
self.left = None
self.right = None
def get_kth_smallest_keys(node, k):
"""Return, as a list, `k` smallest keys in a binary search tree rooted at `node`.
"""
smallest = []
_get_kth_smallest_keys(node, k, smallest)
return smallest
def _get_kth_smallest_keys(node, k, smallest):
"""A helper function. Appends nodes to the given list, `smallest`, and stop
when k reaches 0.
Returns the number of nodes appended to said list.
"""
if node is None or k == 0:
return 0
# first, recurse left, and we get the number of nodes appended to the list by that call
nk = _get_kth_smallest_keys(node.left, k, smallest)
# if that number already reduces our counter to zero, we fail fast, returning that same number
if k - nk <= 0:
return nk
# otherwise, we can still append this node's key to the list
smallest.append(node.key)
# then we recurse right, with a counter that is less 1 (our append) and less nk (appended by the left recurse)
nnk = _get_kth_smallest_keys(node.right, k - 1 - nk, smallest)
# our return value is the sum of our append (1) and the appends from both recurse calls
return nk + 1 + nnk
class BSTTest(unittest.TestCase):
def test_smallest_keys(self):
root = BST(10)
root.left = BST(6)
root.right = BST(15)
root.left.right = BST(8)
root.right.right = BST(20)
self.assertEquals(get_kth_smallest_keys(root, 0), [])
self.assertEquals(get_kth_smallest_keys(root, 1), [6])
self.assertEquals(get_kth_smallest_keys(root, 3), [6, 8, 10])
self.assertEquals(get_kth_smallest_keys(root, 5), [6, 8, 10, 15, 20])
self.assertEquals(get_kth_smallest_keys(root, 6), [6, 8, 10, 15, 20])
if __name__ == '__main__':
unittest.main()