Python Memoization failing on Leetcode - python

The Scenario:
I am doing a question on Leetcode called nth Ugly Number. The algorithm is to find the nth number whose prime factors include only 1, 2, 3, and 5.
I created a solution which was accepted and passed all the tests. Then, I wanted to memoize it for practice with memoization with python - however, something has gone wrong with the memoization. It works for my own personal tests, but Leetcode does not accept the answer.
The memoized code is detailed below:
class Solution:
uglyNumbers = [1, 2, 3, 4, 5]
latest2index = 2
latest3index = 1
latest5index = 1
def nthUglyNumber(self, n: int) -> int:
while len(self.uglyNumbers) <= n:
guess2 = self.uglyNumbers[self.latest2index] * 2
guess3 = self.uglyNumbers[self.latest3index] * 3
guess5 = self.uglyNumbers[self.latest5index] * 5
nextUgly = min(guess2, guess3, guess5)
if(nextUgly == guess2):
self.latest2index += 1
if(nextUgly == guess3):
self.latest3index += 1
if(nextUgly == guess5):
self.latest5index += 1
self.uglyNumbers.append(nextUgly)
return self.uglyNumbers[n-1]
The only change I made when memoizing was to make uglyNumbers, latest2index, etc. to be class members instead of local variables.
The Problem:
When I submit to LeetCode, it claims that the solution no longer works. Here is where it breaks:
Input 12 /// Output 6 /// Expected 16
However, when I test the code myself and provide it with input 12, it gives the expected output 16. It does this even if I call nthUglyNumber with a bunch of different inputs before and after 12, so I have no idea why the test case breaks upon being submitted to LeetCode
Here's the testing I performed to confirm that the algorithm appears to work as expected:
# This code goes inside Class Solution
def nthUglyNumber(self, n: int) -> int:
print("10th: " + str(self.nthUgliNumber(10)))
print("11th: " + str(self.nthUgliNumber(11)))
print("12th: " + str(self.nthUgliNumber(12)))
print("9th: " + str(self.nthUgliNumber(9)))
print("14th: " + str(self.nthUgliNumber(14)))
print("10th: " + str(self.nthUgliNumber(10)))
print("11th: " + str(self.nthUgliNumber(11)))
print("12th: " + str(self.nthUgliNumber(12)))
return self.nthUgliNumber(n)
def nthUgliNumber(self, n: int) -> int:
# The regular definition of nthUglyNumber goes here
What I want to know
Is there some edge case in Python memoization that I am not seeing that's causing the code to trip up? Or is it fully Leetcode's fault? I know my algorithm works without memoization, but I want to understand what's going wrong so I gain a better understanding of Python and so that I can avoid similar mistakes in the future.
I appreciate the help!

I believe leetcode is probably running all tests in parallel on multiple threads using separate instances of the Solution class. Since you are storing nthUgliNumber as a class variable, instances may be updating it (and the 3 indexes) in a conflicting manner.
From leetcode's perspective, each test is not expected to have side effects that would impact other tests. So, parallel execution in distinct instances is legitimate. Caching beyond the scope of the test case is likely undesirable as it would make performance measurements inconsistent and dependent on the order and content of the test cases.

Related

Brute Force Created In Python | Numerical Only | Up to 4 Digits

Thank you very much for taking the time to read this. I am a tadpole when it comes to write python and right now I just written the framework to create a brute force algo to sort up to 3 digits worth of numbers. Am I in the right direction?
I am assuming the web app actually reveal the number of digits it is send to your email. I first learn about this from TryHackMe.
Now it can randomly create up to 4 digit numbers as seen in BookFace and the above can crack the code as seen using their example. My question is am I doing it in the right way? Because I seen other people's sample of bruteforce and they use a lot of function. Am I being too long winded?
import random
digits = 4 #reveal the number of digits
i=0
z=0
x="" #init password to nothing
#generate random password up to 4 digits
while i < digits:
z = random.randint(0,9)
print(z)
x = str(x) + str(z)
i+=1
y = 1
print("Code Random Generated: " + x)
if digits == 1:
while y!=int(x):
print(y)
y+=1
elif digits == 2:
while y!=int(x):
if len(str(y)) == 1:
print("0" + format(y))
elif len(str(y)) == 2:
print(y)
y+=1
elif digits == 3:
while y!=int(x):
if len(str(y)) ==1:
print("00" + format(y))
elif len(str(y)) == 2:
print("0" + format(y))
elif len(str(y)) == 3:
print(y)
y+=1
elif digits == 4:
while y!=int(x):
if len(str(y)) ==1:
print("000" + format(y))
elif len(str(y)) == 2:
print("00" + format(y))
elif len(str(y)) == 3:
print("0" + format(y))
elif len(str(y)) == 4:
print(y)
y+=1
if y !=0:
print("Reset Code Revealed: " + format(y))
You are sort of asking for a code review, not for a problem's solution. This is what Code Review Stack Exchange is for.
Anyway, let's look at my own solution to the problem :
"""
An humble try at cracking simple passwords.
"""
import itertools
import random
from typing import Callable, Iterable, Optional
def generate_random_numerical_password(ndigits: int) -> str:
return "".join(str(random.randint(0, 9)) for _ in range(ndigits))
def guesses_generator(ndigits: int) -> Iterable[str]:
yield from ("".join(digits) for digits in itertools.product("0123456789", repeat=ndigits))
PasswordOracle = Callable[[str], bool]
def cracker(ndigits: int, oracle: PasswordOracle) -> Optional[str]:
for guess in guesses_generator(ndigits):
if oracle(guess):
return guess
else:
return None
if __name__ == "__main__":
NDIGITS = 4 # difficulty
print(f"the difficulty (number of digits) is set to {NDIGITS}")
password = generate_random_numerical_password(NDIGITS)
print(f"the password to crack is {password!r}")
password_oracle = lambda guess: guess == password # do not use `is`, see Python's string interning
if match := cracker(NDIGITS, password_oracle):
print("Cracked!")
else:
print("Error, not found")
Some differences :
The different parts of the program are clearly delimited using functions (password creation and cracking).
The guess generation is generalized : if the number of digits become 5, you will have to write another (tedious and error-prone) elif.
The "flow" of the program is made very clear in the "main" part : generate a password and the corresponding oracle, call the cracker and check if a result was found. There is very few lines to read, and using descriptive names helped too.
The names come from the domain ("cracking") : "guess", "difficulty", "generator" instead of abstract ones like "x" and "y".
Some language knowledge is used : standard types operations (str-joining instead of concatenation), generators (yield from), libraries (itertools.product), syntax (walrus oparetor if match := cracker(...), ...
There is more documentation : comments, docstring at the top of the module, type annotations, ... all of these helping to understand how the program works.
My question is am I doing it in the right way? Because I seen other people's sample of bruteforce and they use a lot of function. Am I being too long winded?
I did not do use functions on purpose to do like the others people, but because I see things in a different way than you, which I will try to explain.
In the end, both your solution and mine solve the initial problem "crack a four-digit password". In this way, they are not much different. But there could be other ways to consider :
Will the problem change ? Could the password be 5 digits, or contain alphabetic characters, or special characters ? In such cases, how long will it take to adapt the script ? This is the malleability of the code.
How clear is the code ? If I have a bug to fix, how long will it take me to find where it comes from ? What if it is someone new to Python ? Or someone that knows Python well but never saw the code ? This is the maintainability of the code.
How easy is it to test the code ? What can be tested ? This is teastability.
How fast is the code ? How much memory does it uses ? This is performance ?
Can the program crash ? What if the program is given bad inputs ? Could it cause an infinite loop ? This is program-safety.
...
Depending on how your objectives about malleability, maintainability, testability, performance, safety, ... (other qualities of a program), but also depending on the context. who is writing the code ? Who will read it later ? How much experienced they are ? How much time do they have to finish writing it ? Will it be run only once then thrown away or will it be deployed on millions of devices ?
All of that affects how you write it. If I was in your shoes (beginner to Python, writing a run-once-then-forget script) I would have done the same as you. The difference is the context and the objectives. I wrote my code as an example to show you the difference. But neither is good nor bad.
You are not bad at running just because you are slower than an Olympic athlete. You can only be bad relative to a context and objectives. In Physical Education class, you are graded on your running speed according to the average for your age and the progress you made.
Seeing things in their perspective is a very useful skill, not just for programming.
Whan you compare your code to other's, yours seem less "clever", less "clean", less "elegant". But you are comparing apples to oranges. You are not the others. If your solution was accepted (correct and fast enough) that's a good start at your level.
My years of professionnal experience working with several other people on tens-of-thousand-lines codebases that have to be maintained for 20 years are a different set of contexts and objectives than you learning the language in fun ways (TryHackMe). Neither is objectively bad, both are subjectively good.
TL;DR : your code is fine for a beginner, you still have lots to learn if you want to, and keep having fun !

Python - Using two interdependent classes and a for loop

My question is basically the following: I have two classes:
Class 1 that does something in a loop (web scraping)
Class 2 that has different functions to automize things someone has to do in this loop and similar loops in the future.
The idea is to abstract Class 1 as much as possible.
Example: Class 2 has a function that "pauses like a human" after certain iterations
(excerpt)
def pause_like_human(self):
''' Pausing long every x-th iteration or else short '''
# every 20th iteration - wait for 5-10 minutes before continuing
if self.index_no % self.index_counter == 0:
timestamp = time.localtime()
return print("Let's wait " + str(self.waiting_time_long) + " seconds! The time is: "\
+ str(timestamp.tm_hour) + ":" + str(timestamp.tm_min) + ":"\
+ str(timestamp.tm_sec)), time.sleep(self.waiting_time_long)
else:
return print("Let's continue! ... after " + str(self.waiting_time_short) + " seconds..."), time.sleep(self.waiting_time_short)
Now my problem is that I would need to import "index_no" from the loop I am using in class 2... over and over again.
(index_no is in this loop:)
for index_no, city in enumerate(self.df['column'][len(self.dic)-1:], start = len(self.dic)-1):
To me it sounds like this would be very inefficient - does someone have a better idea?
So the answer for me specifically seems to be that I simply abstract the code even more. This will turn my "complicated" loop into a very easy loop and my two classes into one class.
Class 1 turns to a longer list with links, but actually well prepared.
Class 2 turns into a more generalised class with most of the functionality of the former class 1 inherited already.
I wouldnt mind leaving this post open if someone comes up with a general help or hints...

How to successfully conduct a Unit Test in Python?

So I am trying to run a Unit Test in which only one correct solution passes and every other incorrect solutions need to fail. But, the thing is the Unit Test has to account for a broad spectrum of test cases even negative values. How can I do this in which only one solution passes and every other fails? I heard of people doing this efficiently by using hash tables in which the input is the key and the output is the value.
What I did below apparently isn't good enough of a Unit Test and is marked incorrect.
Unit_Test/lecture/MainObject.py
def computeShippingCost(input):
if (0 < input <= 30):
return 5
elif (input > 30):
return ((input - 30) * 0.25) + 5
Unit_Test/tests/Testing.py
from lecture.MainObject import computeShippingCost
class Testing(object):
def Test(self):
assert computeShippingCost(20) == 3 #incorrect
assert computeShippingCost(-30) == -8 #incorrect
assert computeShippingCost(40) == -20 #incorrect
assert computeShippingCost(50) == 10 #correct
From your example and description I take it that there might be a very fundamental misconception about how a test should look. Every test somehow stimulates its subject (the system under test, aka SUT), and then verifies that the result meets the expectation.
On a very abstract level, a test looks like this:
def myTest():
<Prepare the SUT for the test>
<Stimulate the SUT>
<check if the result matches the expectation>
The intention is, that a failing test will indicate that there is a bug in the SUT. Correctly implemented code shall not lead to a failing test. (*)
In your code example, you have stimulated the SUT and checked the result in the following way:
assert computeShippingCost(20) == 3 #incorrect
From the implementation of computeShippingCost it is clear that the result in this case would be 5 and not 3. There are now two possibilities:
A) computeShippingCost is implemented correctly. Then, the expectation in this case should be 5. An assertion against anything else than 5 will fail. This violates the above goal (*), because you will have a failing test although the code is implemented correctly.
B) computeShippingCost has a bug, and it actually should deliver 3 in this situation. Then, this assertion represents a useful test, and the fact that it fails indicates to you that your function has a bug.

Curious about effect of recursion of a method

I have written an instance method which uses recursion to find a certain solution. It works perfectly fine except the time when I'm exiting the if-elif block. I call the function itself inside IF block. Also, I have only one return statement. The output from the method is weird for me to understand. Here is the code and the output:
def create_schedule(self):
"""
Creates the day scedule for the crew based on the crew_dict passed.
"""
sched_output = ScheduleOutput()
assigned_assignements = []
for i in self.crew_list:
assigned_assignements.extend(i.list_of_patients)
rest_of_items = []
for item in self.job.list_of_patients:
if item not in assigned_assignements:
rest_of_items.append(item)
print("Rest of the items are:", len(rest_of_items))
if len(rest_of_items) != 0:
assignment = sorted(rest_of_items, key=lambda x: x.window_open)[0]
# print("\nNext assignment to be taken ", assignment)
output = self.next_task_eligibility(assignment, self.crew_list)
if len(output) != 0:
output_sorted = sorted(output, key=itemgetter(2))
crew_to_assign = output_sorted[0][1]
assignment.eta = output_sorted[0][4]
assignment.etd = int(assignment.eta) + int(assignment.care_duration)
crew = next((x for x in self.crew_list if x.crew_number == crew_to_assign), None)
self.crew_list.remove(crew)
crew.list_of_patients.append(assignment)
crew.time_spent = assignment.etd
self.crew_list.append(crew)
self.create_schedule()
else:
print("*" * 80, "\n", "*" * 80, "\nWe were not able to assign a task so stopped.\n", "*" * 80, "\n", "*" * 80)
sched_output.crew_output = self.crew_list
sched_output.patients_left = len(rest_of_items)
elif not rest_of_items:
print("Fully solved.")
sched_output.crew_output = self.crew_list
sched_output.patients_left = 0
print("After completely solving coming here.")
return sched_output
This was the output:
Rest of the items are: 10
Rest of the items are: 9
Rest of the items are: 8
Rest of the items are: 7
Rest of the items are: 6
Rest of the items are: 5
Rest of the items are: 4
Rest of the items are: 3
Rest of the items are: 2
Rest of the items are: 1
Rest of the items are: 0
Fully solved.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
After completely solving coming here.
What I don't understand is that as soon as my list rest_of_items is empty, I assign data to sched_output and return it. However, print statement is being executed for the same number of time as recursion was done. How can I avoid this?
My output is perfectly fine. All I want to do is understand the cause of this behaviour and how to avoid it.
The reason it's printing out 11 times is that you always call print at the end of the function, and you're calling the function 11 times. (It's really the same reason you get Rest of the items are: … 11 times, which should be a lot more obvious.)
Often, the best solution is to redesign things so instead of doing "side effects" like print inside the function, you just return a value, and the caller can then do whatever side effects it wants with the result. In that case, it doesn't matter that you're calling print 11 times; the print will only happen once, in the caller.
If that isn't possible, you can change this so that you only print something when you're at the top of the stack. But in many recursive functions, there's no obvious way to figure that out without passing down more information:
def create_schedule(self, depth=0):
# etc.
self.create_schedule(depth+1)
# etc.
if not depth:
print('After completely solving come here.')
returns sched_output
The last resort is to just wrap the recursive function, like this:
def _create_schedule(self):
# etc.
self._create_schedule()
# etc.
# don't call print
return sched_output
def create_schedule(self):
result = self._create_schedule()
print('After completely solving come here.')
return result
That's usually only necessary when you need to do some one-time setup for the recursive process, but here you want to do some one-time post-processing instead, which is basically the same problem, so it can be solved the same way.
(Of course this is really just the first solution in disguise, but it's hidden inside the implementation of create_schedule, so you don't need to change the interface that the callers see.)
As you call your create_schedule function within itself before the function finishes, once it has gotten to the end and doesn't need to call itself again, each function ends, and hits the "After completely solving coming here.", at the end of the function.
This means that each function, after calling itself, is still running - just stuck at the line where it calls itself - until they have all completed, which is when the paused functions can finish their task, printing out your statement.
You have print("After completely solving coming here.") at the end of your recursive function. That line will be executed once for each recursion.
Consider this simple example, which recreates your issue:
def foo(x):
print("x = {x}".format(x=x))
if x > 1:
foo(x-1)
print("Done.")
Now call the function:
>>> foo(5)
x = 5
x = 4
x = 3
x = 2
x = 1
Done.
Done.
Done.
Done.
Done.
As you can see, on the final call to foo(x=0), it will print "Done.". At that point, the function will return to the previous call, which will also print "Done." and so on.

Python Set Birthday

So I am trying to make a program that creates the probability of a bunch of people in a room to have the same birthday... I can't figure out how to create the function. Here is what I have so far
def birthday():
mySet = set()
x = 1
for item in mySet:
if item in mySet:
return x
else:
mySet().append() # don't know what to do here.
Edit:
Alright so what I am trying to accomplish is to make a function using a set that stores birthdays using numbers 1 through 365...For example, if you randomly pick a room with 30 people in it, they may not have the same birthday. Although, if you have twins in the same room, you only need 2 people
in the room to have the same birthday. So eventually I want a parameter that tests this function several times and averages it all up. Unfortunately I can't figure out how to make this. I want x to be a counter of how many people are in the room and when there is a match the loop stops and it stops. I also don't know what to append to.
Is there a reason why you're trying to simulate this rather than using the closed form solution to this problem? There's a pretty decent approximation that's fast and easy to code:
import math
def closed_form_approx_birthday_collision_probability(num_people):
return 1 - math.exp(-num_people * (num_people - 1) / (2 * 365.0))
You could also implement an very good "exact" solution (in quotes because some fidelity is lost when converting to float):
import operator
import functools
import fractions
def slow_fac(n):
return functools.reduce(operator.mul, range(2, n+1), 1)
def closed_form_exact_birthday_collision_probability(num_people):
p_no_collision = fractions.Fraction(slow_fac(365), 365 ** num_people * slow_fac(365 - num_people))
return float(1 - p_no_collision)
To do a simulation, you'd do something like this. I'm using a list rather than a set because the number of possibilities is small and this avoids some extra work that using a set would do:
import random
def birthday_collision_simulate_once(num_people):
s = [False] * 365
for _ in range(num_people):
birthday = random.randint(0, 364)
if s[birthday]:
return True
else:
s[birthday] = True
return False
def birthday_collision_simulation(num_people, runs):
collisions = 0
for _ in range(runs):
if birthday_collision_simulate_once(num_people):
collisions += 1
return collisions / float(runs)
The numbers I get from the simulation and the closed form solution look similar to the table at http://en.wikipedia.org/wiki/Birthday_problem
>>> closed_form_approx_birthday_collision_probability(20)
0.40580512747932584
>>> closed_form_exact_birthday_collision_probability(20)
0.41143838358058
>>> birthday_collision_simulation(20, 100000)
0.41108
Of course the simulation with that many runs is closer to the actual 41.1%, it's much slower to calculate. I'd choose one of the closed form solutions, depending on how accurate it needs to be.

Categories

Resources