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))
Related
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)
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)
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
I am solving this problem in SPOJ and it states that :
Problem statement is simple. Given A and B you need to calculate
S(A,B) .
Here, f(n)=n, if n is square free otherwise 0. Also f(1)=1.
Input
The first line contains one integer T - denoting the number of test
cases.
T lines follow each containing two integers A,B.
Output
For each testcase output the value of S(A,B) mod 1000000007 in a
single line.
Constraints
`T <= 1000
1 <= A,B <= 1000000`
Example
Input:
3
42 18
35 1
20 25
Output:
306395
630
128819
I wrote this code for this problem (if I got the the problem right) :
def gcd(a,b): #gcd(a,b)
if b==0:
return a
else:
return gcd(b,a%b)
# print gcd(42,18)
import math
def issquarefree(n): #sqare free number check
i=2
s=i*i
if (n==1 or n==2) or n==3:
return True
while s<=n:
if n%s==0:
i=-1
break
else:
i+=1
s=i*i
if i==-1:return False
else:
return True
for i in range(int(raw_input())): #main program
a,b=map(int,raw_input().split())
g=gcd(a,b)
sa=(a*(a+1))/2 #see below
sb=(b*(b+1))/2 #see below
gc=issquarefree(g)
s=0
if gc== False:
print 0
elif gc==True:
s+=sa*sb*g
print s%1000000007
here I found that so applying this to the problem # S(A,B) I wrote this as (multiplication of sum of first A and B numbers ) multiplied by f(n) which is gcd(a,b) or 0.
But I am not getting the expected output to this problem so is my code wrong or I got the problem wrong
my output vs expected
3
35 1
42 18
20 25
630 630
926478 306395
341250 128819
Writing out the G(a, b) = f(gcd(a, b)) (so that you can use the cited formula) is incorrect since the function is not constant. The proper solution is this:
for i in range(int(raw_input())):
A, B = map(int, raw_input().split())
# proper algorithm
s = 0
for a in xrange(1, A):
for b in xrange(1, B):
s += a * b * G(a, b)
print s % 1000000007
You obviously have to implement G function properly (as returning 0 or gcd(a, b)).
Careful analysis of G might give some optimization insight but it is definitely not a trivial one if any.
Here is a simple optimization:
import fractions
DIVISOR = 1000000007
def is_not_square_free(a):
counter = 1
factor = 1
while factor < a:
counter += 1
factor = counter * counter
if a % factor == 0:
return True
return factor == a
def F(n):
if n == 1:
return 1
if is_not_square_free(n):
return 0
return n
_CACHE = {}
def G(a, b):
a = a % DIVISOR
b = b % DIVISOR
key = (a, b) if a > b else (b, a)
if key not in _CACHE:
_CACHE[key] = (a * b * F(fractions.gcd(a, b))) % DIVISOR
return _CACHE[key]
def S(A, B):
s = 0
for a in range(1, A+1):
for b in range(1, B+1):
s += G(a, b)
return s
for _ in range(int(raw_input())):
A, B = map(int, raw_input().split())
print(S(A, B) % DIVISOR)
def gcd(a, b):
returns greatest common divisor of a and b'''
return gcd(b % a, a) if a and b else max(a, b)
print test gcd should print 6,5, 7, and 9'''
print gcd(48,18)
print gcd(10,5)
print gcd(14,21)
print gcd (9,0)
I was wondering if I could calculate the logarithm of a number based on a number relative to a base (for example, log base 2 of 16) without actually using log(). I managed to do it, but I don't believe it is very efficient.
This is my code in Python:
def myLog(x,b):
exp=0
ans=b**exp
while x!=ans:
ans=b**exp
if ans==x:
return exp
exp=exp+1
So I could give it myLog(16,2) and it should return 4. And indeed it does, however I believe it is not the most efficient way, so how could I fix it and make my code more efficient, not just in this case, but in most of them?
Try recursion:
def func(a, b, ans=0):
if a/b == 1:
return ans + 1
else: return func(a/b, b, ans+1)
In [26]: func(16, 2)
Out[26]: 4
In [27]: func(8, 2)
Out[27]: 3
In [28]: func(16,4)
Out[28]: 2
Here's my two cents worth:
def myLog(x,b):
exp = 0
ans = 1
while ans<x:
ans *= b
exp += 1
if ans == x:
return exp
else:
raise ValueError("can't find a suitable exponent")
In [10]: myLog(16,2)
Out[10]: 4
Hope this helps
You're not taking into account if someone gives a negative value such as myLog(-1,2) or if it is 1 myLog(1,2), then you compute ans before the loop which you know it always be 0 because you put exp = 0, then in the loop you compute it again without before changing the exp.
logarithm python
Assumes:
x: a positive integer
b: a positive integer; b >= 2
returns: log_b(x), or, the logarithm of x relative to a base b.
Seems the shortest way is:
def myLog(x, b):
ans = 0
while b <= x:
ans += 1
x /= b
return ans
Or recursively:
def myLog(x, b):
if (b > x): return 0
else: return 1 + myLog(x/b, b)
Because it is an endless loop:
def myLog(x,b):
exp = 0
ans = b**exp
while x != ans:
ans = b**exp
if ans>x:
return -1
if ans == x:
return exp
exp = exp+1
See also:
What algorithm is used by computers to calculate logarithms?
Taylor series
This version adds support for non-integer outputs:
def log(a, b):
b = float(b)
a = float(a)
g = a
n = 0
i = 1
while b**i != 1:
while g >= b**i:
g /= b**i
n += i
i /= b
return n
def log(a, b):
b = float(b)
a = float(a)
g = a
n = 0
i = 1
while b**i != 1:
while g >= b**i:
g /= b**i
n += i
i /= b
return n
Does not work for all numbers. log(5,10) returns 0.00000 when it should be 0.69897