Generate 2D array in different ways - python

This is a DP problem, which I solve using 2D array in python.
The problem is the way I generate the 2D array.
Standard solution:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1) for i in range(c + 1)]
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 14
My code:
def getFloor(F, c, d):
if d == 0 or c == 0:
return 0
if c == 1:
return d
if F[c][d] == -1:
F[c][d] = getFloor(F, c, d-1) + getFloor(F, c-1, d-1) + 1
return F[c][d]
def getMaxFloor(c,d):
F = [[-1] * (d + 1)] * (c+1)
ans = getFloor(F, c, d)
return ans
print(getMaxFloor(3,4)) #prints 15, instead of the correct answer 14
I check both of the arrays F when both are initialized, which returns true.
What's the problem?

I'm guessing the problem is that when you multiply it, you are just creating duplicates or references to the same list element. So if you change one, you change the other. Whereas if you use the for loop, it creates separate unlinked instances so that when one gets changed it does not affect the other. (You would have to do a lot of tracing back, etc. to figure out exactly why the answer is off by exactly 1.) But this is really the only difference between the codes so it must be the problem. Hope this helps.
For example:
l = [1,2,3]
a = [2]
l.append(a)
a[0] = 4
print l
>>>[1, 2, 3, [4]]
Notice that the last element in l is [4] instead of [2].

Related

can anyone optimize my python code for "Pythagorean triplets"?

I have written a code to find Pythagorean triplets but it is not optimized
it took 5-6 minutes for the algorithm to find answer for big numbers...
my teacher said it should take less than 3 secs...
num = int(input())
def main(n):
for x in range(1, n):
for y in range(1, x):
for z in range(1, y):
if x + y + z == n:
if x * x == y * y + z * z or y * y == x * x + z * z or z * z == x * x + y * y:
a = f'{z} {y} {x}'
print(a)
return
else:
print('Impossible')
for example if you enter 12, you'll get 3,4,5
if you enter 30 , the answer will be 5,12,13
The sum of these three numbers must be equal to the number you entered.
can anyone please help me ?
Note the proof for the parametric representation of primitive pythagorean triples. In the proof, the author states:
We can use this proof to write an optimized algorithm:
def p(num):
a, b, c = 1, 1, 0
n = 0
while c < num:
for m in range(1, n):
a = 2 * m * n
b = n ** 2 - m ** 2
c = n ** 2 + m ** 2
if c >= num:
return "Impossible!"
elif a + b + c == num:
return b, a, c
n = n + 1
print(p(12)) # >>> (3, 4, 5)
print(p(30)) # >>> (5, 12, 13)
print(p(31)) # >>> Impossible!
You're doing a lot of repeated and unnecessary work. You know that A^2 + B^2 = C^2 and you know that C > B > A. It doesn't matter if you want to say C > A > B because any solution you find with that would be satisfied with C > B > A. For instance take 12 and solution 3, 4, 5. It doesn't actually matter if you say that A=3 and B=4 or A=4 and B=3. Knowing this we can adjust the loops of each for loop.
A can go from 1 to num, that's fine. Technically it can go to a bit less since you are adding another value to it that has to be at least 1 as well.
B then can go from A+1 to num since it needs to be greater than it.
So what about C? Well it doesnt' need to go from 1 since that's not possible. In fact we only care about A + B + C = num, so solve for C and you get C = num - A - B. That means you don't need to use a loop to find C since you can just solve for it. Knowing this you can do something like so:
In [142]: def find_triplet(num):
...: for a in range(1, num-1):
...: for b in range(a+1, num):
...: # A^2 + B^2 = C^2
...: # And A+B+C = N
...: c = num - a - b
...: if c > 0:
...: if a*a + b*b == c*c:
...: print(f'{a} {b} {c}')
...: else:
...: break
...:
In [143]: find_triplet(30)
5 12 13
So why check to see if C > 0 and break otherwise? Well, if you know C = num - A - B and you are incrementing B, then once B becomes too large, C is going to continue to get more and more negative. Because of that you can check if C > 0 and if it's not, break out of that inner loop to have A increment and B reset.
The approach you discussed takes O(n^3) complexity.
An efficient solution is to run two loops, where first loop runs from x = 1 to n/3, second loop runs from y = x+1 to n/2. In second loop, we check if (n – x – y) is equal to (x * x + y * y):
def pythagoreanTriplet(n):
# Considering triplets in
# sorted order. The value
# of first element in sorted
# triplet can be at-most n/3.
for x in range(1, int(n / 3) + 1):
# The value of second element
# must be less than equal to n/2
for y in range(x + 1,
int(n / 2) + 1):
z = n - x - y
if (x * x + y * y == z * z):
print(x, " ", y, " ", z)
return
print("Impossible")
# Driver Code
n = int(input())
pythagoreanTriplet(n)
PS: Time complexity = O(n^2)

3Sum function debugging

I have been asked to fix this chunk of code. It is to do with sets and the 3Sum problem. I have used print statements and i am very close to the answer, but i get an IndexingError (list index out of range). Any help would be great
def count_c(A, B, C):
"""Counts the number of pairs a in A and b in B so that a + b == c
nb. Assumes that A and B are sorted
"""
rv = 0
n = len(A)
m = len(B)
#t = len(C)
AL, BL, CL = list(A), list(B), list(C)
# i and j are "fingers" on A and B
i, j = 0, m-1
while i < n and j >= 0:
for c in CL:
a, b = AL[i], BL[j] #correct
print ('a,b = ', (a,b))
s = a + b #correct
print('s = ', s)
print ('i , j =', (i,j))
if s == c:
# found a pair that works
rv = rv + 1 #correct
# start again with a smaller b
j = j - 1 #correct
elif s > c:
# too big. decrease the b contribution
j = j - 1
else:
# means s < c, increase the a contribution
i = i + 1
return rv
def three_sum(A, B, C):
"""Solves 3SUM+"""
return count_c(A,B,C)
IndexingError (list index out of range)

Finding Greatest Common Divisor through iterative solution (python 3)

I am trying to find the great common divisor by using a function and solving it iteratively. Though, for some reason, I am not sure why I am not getting the right output.
The greatest common divisor between 30 & 15 should be 15, however, my output is always giving me the wrong number. I have a strong feeling that my "if" statement is strongly incorrect. Please help!
def square(a,b):
'''
x: int or float.
'''
c = a + b
while c > 0:
c -= 1
if a % c == 0 and b % c == 0:
return c
else:
return 1
obj = square(30,15)
print (obj)
You should return a value only if you finished iterating all numbers and found none of them a divisor to both numbers:
def square(a, b):
c = a + b
while c > 0:
if a % c == 0 and b % c == 0:
return c
c -= 1
return 1
However, the last return will be unneeded in this case, as c would go from a + b to 1, and mod 1 will always bring a common divisor, so the loop will always terminate with 1, for the worst case.
Also, a number greater than a and b can not be a common divisor of them. (x mod y for y > x yields x), and gcd is the formal name for the task, so I would go with
def gcd(a, b):
for c in range(min(a, b), 0, -1):
if a % c == b % c == 0:
return c
for iterational solution.
You might be interested to know that there is a common recursive solution to the GCD problem based on the Euclidian algorighm.
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
print(gcd(30, 15))
# 15

Tail recursion to loop

I as working on a program that given a and b, computes the last 5 digits of a^b. I currently have it working as long as b is sufficiently low, but if b is large (>1000) this will crush the stack. Is there a way I can make this an iterative function? I have tried converting to iterative, but I can't figure it out.
def pow_mod(a,b):
if b == 0:
return 1
elif b == 2:
return a*a % 10000
return ((b%2*(a-1) + 1) * pow_mod(a,b//2)**2) % 10000
In order to do this computation, iteratively, you start with an answer=a, and then square it repeatedly (and multiply by a if b is odd). To exit the loop, divide b by 2 each time, and check for when b>1.
def pow_mod(a,b):
if b == 0:
return 1
c = 1;
while b > 1:
if b % 2:
c *= a
a *= a
b //= 2
a %= 10000
c %= 10000
return a * c % 10000
Use a while loop instead of recursion, to adjust b the same way that you do in the recursive call.
def pow_mod(a, b):
result = 1
while b > 0:
result = (b%2*(a-1) + 1) * result**2) % 10000
b = b//2
return result
The trick is to store the result in a temporary variable and then pass it to each function call.
lst = []
while b:
lst.insert(0, b)
b = b//2
def _pow_mod(a, b, answer):
if b == 2:
return a*a % 10000;
else:
return ((b%2*(a-1) + 1) * answer **2) % 10000
answer = 1 # b = 0 case
for b in lst:
answer = _pow_mod(a, b, answer)
Complete Code:
# Original recursive solution
def pow_mod_orig(a, b):
if b == 0:
return 1
elif b == 2:
return a*a % 10000
return ((b%2*(a-1) + 1) * pow_mod_orig(a,b//2)**2) % 10000
# Iterative solution
def pow_mod(a, b):
lst = []
while b:
lst.insert(0, b)
b = b//2
def _pow_mod(a, b, answer):
if b == 2:
return a*a % 10000;
else:
return ((b%2*(a-1) + 1) * answer **2) % 10000
answer = 1 # b = 0 case
for b in lst:
answer = _pow_mod(a, b, answer)
return answer
for i in range(1000):
assert(pow_mod_orig(3, i) == pow_mod(3, i))

changing base of a number to a given number

I must write a recursive function that gets a number(n) in the 10 base and converts it to a given number base(k) and return a list which its components are the final number digits,for example f(5, 3) must result [1, 2] which 5 in base 3 is 12, or f(22, 3) must result [2, 1, 1].
Here's the code I tried:
def cb(n, k):
b = []
if n == 0:
b.append(0)
if n < k:
b.append(n)
if n == k:
b.append(10)
else:
a = n // k
b.append(n - ((n // k) * k))
if a < k:
b.append(a)
else:
cb(a, k)
return b
print(cb(22, 3))
Actually I thought a lot on it but since I'm not so good at writing codes I couldn't go any further. I appreciate your help and modifications to my code .
If you think in terms of recursion the base case is when n < k for which the answer is n and to get the last digit of the n you do n%k so the recusive case is cb(n//k,k)+[n%k].
The code will look like this :
def cb(n, k):
if n < k:
return [n]
else:
return cb(n//k, k) + [n%k]
print(cb(22, 3))
you were very close, the only thing that you needed to do was change:
else:
cb(a, k)
to:
else:
b.extend(cb(a, k))
however, your output is going to be:
>>> cb(22, 3)
[1, 1, 2]
which is the reverse of what you want, since 22 in base 3 is 211. you can fix this by either reversing the list [1,1,2][::-1] == [2,1,1] or replace all your calls to append and your new call to extend to instead add at the beginning of the list like: b.insert(0,element) or b = cb(a,k) + b
The biggest problem is that you aren't doing anything with the results of the recursive call, so they never go in your list. I think you are also complicating this too much. Something like this should work:
def cb(n,k):
if n > 0:
q = n // k
r = n - q * k
b = cb(q, k)
b.append(r)
else:
b = [0]
if b[0] == 0 and len(b) > 1:
b = b[1:]
return b
I think if you don't do the last part, then you always get a 0 on the front? You could also simplify it further by just testing to see if it is less than the radix, which gives an even simpler solution
def cb(n,k):
if n < k:
return [n]
else:
q = n // k
r = n - q * k
b = cb(q, k)
b.append(r)
return b

Categories

Resources