Setting Enumerate Value to a Variable changes the output of a function - python

I'm new to the enumeration function, I've only just started to use it. In this code block, I'm enumerating "height" multiple times:
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
if len(height) == 2:
return (min(height))
maxArea = -1
for i, a in enumerate(height):
maxIndex, maxDistance = i, 0
for j, s in enumerate(height):
distance = abs(j-i)
if distance>maxDistance and s>=a:
maxIndex, maxDistance = j, distance
area = abs(maxIndex - i) * a
maxArea = max(area,maxArea)
return maxArea
I thought a way to optimize this was to set enumerate(height) to a variable to decrease the amount of times the height was put into the enumerate function:
class Solution(object):
def maxArea(self, height):
"""
:type height: List[int]
:rtype: int
"""
if len(height) == 2:
return (min(height))
maxArea = -1
enumeratedHeight = enumerate(height)
for i, a in enumeratedHeight:
maxIndex, maxDistance = i, 0
for j, s in enumeratedHeight:
distance = abs(j-i)
if distance>maxDistance and s>=a:
maxIndex, maxDistance = j, distance
area = abs(maxIndex - i) * a
maxArea = max(area,maxArea)
return maxArea
I tested this new function on this case [1,8,6,2,5,4,8,3,7]. The before function correctly answered 49, but this one returns 8?
(this code is to solve Container With Most Water on Leetcode, I know it's inefficient, but I've been told to write inefficient code if I can't find an efficient solution)

Related

how can I Optimize cuckoo hashing

I have a python code which implements cuckoo hashing.
I'm working on code for a hash table where collisions are corrected using cuckoo hashing. But it is taking a lot of time if there are more collisions.
I have used mmh3 family for hashing
so, is there a way to optimize this code and cuckoo hashing technique?
If yes kindly elaborate
from random import randint
import math
import mmh3
#parameters
from parameters import output_bits, number_of_hashes
mask_of_power_of_2 = 2 ** output_bits - 1
log_no_hashes = int(math.log(number_of_hashes) / math.log(2)) + 1
#The hash family used for Cuckoo hashing relies on the Murmur hash family (mmh3)
def location(seed, item):
'''
:param seed: a seed of a Murmur hash function
:param item: an integer
:return: Murmur_hash(item_left) xor item_right, where item = item_left || item_right
'''
item_left = item >> output_bits
item_right = item & mask_of_power_of_2
hash_item_left = mmh3.hash(str(item_left), seed, signed=False) >> (32 - output_bits)
return hash_item_left ^ item_right
def left_and_index(item, index):
'''
:param item: an integer
:param index: a log_no_hashes bits integer
:return: an integer represented as item_left || index
'''
return ((item >> (output_bits)) << (log_no_hashes)) + index
def extract_index(item_left_and_index):
'''
:param item_left_and_index: an integer represented as item_left || index
:return: index extracted
'''
return item_left_and_index & (2 ** log_no_hashes - 1)
def reconstruct_item(item_left_and_index, current_location, seed):
'''
:param item_left_and_index: an integer represented as item_left || index
:param current_location: the corresponding location, i.e. Murmur_hash(item_left) xor item_right
:param seed: the seed of the Murmur hash function
:return: the integer item
'''
item_left = item_left_and_index >> log_no_hashes
hashed_item_left = mmh3.hash(str(item_left), seed, signed=False) >> (32 - output_bits)
item_right = hashed_item_left ^ current_location
return (item_left << output_bits) + item_right
def rand_point(bound, i):
'''
:param bound: an integer
:param i: an integer less than bound
:return: a uniform integer from [0, bound - 1], distinct from i
'''
value = randint(0, bound - 1)
while (value == i):
value = randint(0, bound - 1)
return value
class Cuckoo():
def __init__(self, hash_seed):
self.number_of_bins = 2 ** output_bits
self.recursion_depth = int(8 * math.log(self.number_of_bins) / math.log(2))
self.data_structure = [None for j in range(self.number_of_bins)]
self.insert_index = randint(0, number_of_hashes - 1)
self.depth = 0
self.FAIL = 0
self.hash_seed = hash_seed
def insert(self, item): #item is an integer
current_location = location( self.hash_seed[self.insert_index], item)
current_item = self.data_structure[ current_location]
self.data_structure[ current_location ] = left_and_index(item, self.insert_index)
if (current_item == None):
self.insert_index = randint(0, number_of_hashes - 1)
self.depth = 0
else:
unwanted_index = extract_index(current_item)
self.insert_index = rand_point(number_of_hashes, unwanted_index)
if (self.depth < self.recursion_depth):
self.depth +=1
jumping_item = reconstruct_item(current_item, current_location, self.hash_seed[unwanted_index])
self.insert(jumping_item)
else:
self.FAIL = 1

recursion error while using dfs to find connected components in image

As the title says I am trying to find all connected components in an image using recursive dfs.
I based the principle algorithm on the pseudo over here https://www.programiz.com/dsa/graph-dfs
What I get is a recursion depth exceedet error.
Usually I would troubleshoot this by checking the base case for the specific recursion, but I cant seem to find the issue.
Since every pixel is either zero or will be marked as visited at some point in time, I feel the recursion should terminate at some point.
Are there other ways for troubleshooting such recursion errors?
import cv2
import numpy as np
class Image:
def __init__(self, path):
self.img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
self.n, self.m = self.img.shape
self.visited = {(i, j): False for i in range(self.n)
for j in range(self.m)}
self.components = []
def threshold(self):
self.img[self.img >= 200] = 255
self.img[self.img < 200] = 0
def neighbours(self, px):
(i, j) = px
corners = [(i+x, j+y) for x in range(-1, 2) for y in range(-1, 2)
if (i+x, j+y) != (i, j)
and (0 <= i+x < self.n)
and (0 <= j+y < self.m)]
return corners
def dfs(self):
self.threshold()
component = 0
for i in range(self.n):
for j in range(self.m):
if not self.visited.get((i, j)) and self.img[i][j] == 255:
self.components.append([(i, j)])
self.explore((i, j), component)
component += 1
def explore(self, px, component):
self.visited[px] = True
self.components[component].append(px)
for neigh in self.neighbours(px):
if not self.visited.get(neigh) and self.img[neigh[0]][neigh[1]] == 255:
self.explore(neigh, component)
img = Image("dots.png")
img.dfs()
Solved
I had to set the maximum recursion depth
import sys
sys.setrecursionlimit(new_limit)

Issue with python __eq__ method in checking if 2 lists are equal

I have a python program in which I have a class called Vector and an empty list inside of that class which is being populated runtime.
Here is the init:
def __init__(self,n):
self.vector = [];
self.n = n;
for x in range(n):
self.vector.append(False);
And here is the eq:
def __eq__(self, other):
t = True
for x in range(self.n):
if self.vector[x] != other.vector[x]:
t = False;
return t
however, when I try to check if 2 objects of this type are equal, I always get true, even though I changed values inside of vector in Vector class.
Here is the code where I do the above:
vectors = []
n = tmp.size();
k = calculateCombinationCount(n,int(n/2))
for i in range(k):
for j in range(0,n-1):
if (tmp.vector[j] != tmp.vector[j+1]):
t = True
for x in vectors:
if x == tmp:
t = False;
if t:
vectors.append(tmp)
tmp.printVector();
tmp.swap(j,j+1);
I would appreciate any help that you can provide. Thank you :)
EDIT:
def swap(self,i,j):
tmp = self.vector[i]
self.vector[i] = self.vector[j]
self.vector[j] = tmp
def calculateCombinationCount(n,r):
k = factorial(n)/(factorial(int(r))*factorial(int(n-r)))
return int(k)
Right so I've updated your code to be much more pythonic (I can tell you come from another language, Java?).
from math import factorial
class Vector:
def __init__(self, size):
self.size = size
self.vector = [False] * size
def __eq__(self, other):
"""
Same if self.size == other.size
"""
assert self.size == other.size, (self.size, other.size)
return self.vector == other.vector
def print_vector(self):
print(self.vector)
def swap(self, i, j):
"""
More efficient and pythonic
"""
self.vector[i], self.vector[j] = self.vector[j], self.vector[i]
def calculate_combination_count(n, r):
"""
This is slow, I'd replace it with scipy.special.comb
https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.comb.html#scipy.special.comb
"""
return factorial(n) // (factorial(r) * factorial(n-r))
tmp = Vector(10)
vectors = []
n = tmp.size
k = calculate_combination_count(n, n // 2)
for i in range(k):
for j in range(0, n-1):
if tmp.vector[j] != tmp.vector[j + 1]:
if not any(vec == tmp for vec in vectors): # much more efficient
vectors.append(tmp)
tmp.print_vector()
tmp.swap(j, j + 1)
else: # Just to prove why it doesn't work
print('tmp.vector is all False: {}'.format(not all(tmp.vector)))
This prints out tmp.vector is all False: True repeatedly. I think this is your problem.
If you

Optimize finding diameter of binary tree in Python

I'm wondering how I can optimally find the diameter (or longest path between any two leaf nodes) of a binary tree. I have the basic solution below, but the second solution requires passing pointers. How can I do something like this in Python?
def find_tree_diameter(node):
if node == None:
return 0
lheight = height(node.left)
rheight = height(node.right)
ldiameter = find_tree_diameter(node.left)
rdiameter = find_tree_diameter(node.right)
return max(lheight+rheight+1, ldiameter, rdiameter)
def find_tree_diameter_optimized(node, height):
lheight, rheight, ldiameter, rdiameter = 0, 0, 0, 0
if node == None:
# *height = 0;
return 0
ldiameter = diameterOpt(root.left, &lheight)
rdiameter = diameterOpt(root.right, &rheight)
# *height = max(lheight, rheight) + 1;
return max(lh + rh + 1, max(ldiameter, rdiameter));
Python supports multiple return values, so you don't need pointer arguments like in C or C++. Here's a translation of the code:
def diameter_height(node):
if node is None:
return 0, 0
ld, lh = diameter_height(node.left)
rd, rh = diameter_height(node.right)
return max(lh + rh + 1, ld, rd), 1 + max(lh, rh)
def find_tree_diameter(node):
d, _ = diameter_height(node)
return d
The function diameter_height returns the diameter and the height of the tree, and find_tree_diameter uses it to just compute the diameter (by discarding the height).
The function is O(n), no matter the shape of the tree. The original function is O(n^2) in the worst case when the tree is very unbalanced because of the repeated height calculations.
Simple Python 3 solution
def findDepth(root):
if root is None:
return 0
return 1 + max(findDepth(root.left), findDepth(root.right))
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
if root is None:
return 0
left = findDepth(root.left)
right = findDepth(root.right)
ldia = self.diameterOfBinaryTree(root.left)
rdia = self.diameterOfBinaryTree(root.right)
return max(left+right, max(ldia, rdia))

Python 2-dimensional array is behaving strangely

I've been attempting to port a program I've written in C++ to Python. Specifically, it is a program for generating heightmaps which can be exported to 3D models, and which ideally, when viewed, would look like realistic terrain.
The HeightMap class wraps a two-dimensional array of float values. For now I've kept it as integers because it prints nicer, and I haven't had a chance to implement any other features. The glitch I'm having is that when I call set(self, x, y, value), which simply sets the value at x, y to value, with the code "self.rows[y][x] = value", it seems to change the entire column, visiting each member of self.rows and setting the xth member of that array to value.
Here is my code. I am about 90% sure the mistake is somewhere in the 2-array's initialization.
def filledArray(length, value) :
result = []
for i in range(1, length) :
result.append(value)
return result
def resizeArray(array, newLength, nullValue) :
if newLength == len(array) :
return array
result = []
for i in range(0, newLength) :
if i < len(array) :
result.append(array[i])
else :
result.append(nullValue)
return result
class HeightMap:
"""A class that wraps a 2D array for generating height maps"""
def __init__(self) :
self.width = 0
self.height = 0
self.rows = []
def __init__(self, initWidth, initHeight) :
self.clear(initWidth, initHeight);
def clear(self, initWidth, initHeight) :
self.width = initWidth
self.height = initHeight
self.rows = filledArray(initHeight, filledArray(initWidth, 0))
def setHeight(self, newHeight) :
if self.height == newHeight :
return
self.rows = resizeArray(self.rows, newHeight, filledArray(self.width, 0))
def setWidth(self, newWidth) :
if self.width == newWidth :
return
for i in range(0, len(self.rows)) :
self.rows[i] = resizeArray(self.rows[i], newWidth, 0);
self.width = newWidth
def get(self, x, y) :
return self.rows[y][x]
def set(self, x, y, value) :
self.rows[y][x] = value
def add(self, x, y, value) :
self.rows[y][x] += value
def multiply(self, x, y, value) :
self.rows[y][x] *= value
Your problem is that when you call filledArray(initHeight, filledArray(initWidth, 0)) the second argument is passed by reference (this is always the case with python objects). Inside filledArray you need to make a copy of value for each. This will require adding a little bit of additional logic to your function, something along the lines of:
if type(value) == list:
value = list(value)
Or you could do the slightly less pythonic:
type(value)(value)
to create a copy.

Categories

Resources