I have written a code based on the two pointer algorithm to find the sum of two squares. My problem is that I run into a memory error when running this code for an input n=55555**2 + 66666**2. I am wondering how to correct this memory error.
def sum_of_two_squares(n):
look=tuple(range(n))
i=0
j = len(look)-1
while i < j:
x = (look[i])**2 + (look[j])**2
if x == n:
return (j,i)
elif x < n:
i += 1
else:
j -= 1
return None
n=55555**2 + 66666**2
print(sum_of_two_squares(n))
The problem Im trying to solve using two pointer algorithm is:
return a tuple of two positive integers whose squares add up to n, or return None if the integer n cannot be so expressed as a sum of two squares. The returned tuple must present the larger of its two numbers first. Furthermore, if some integer can be expressed as a sum of two squares in several ways, return the breakdown that maximizes the larger number. For example, the integer 85 allows two such representations 7*7 + 6*6 and 9*9 + 2*2, of which this function must therefore return (9, 2).
You're creating a tuple of size 55555^2 + 66666^2 = 7530713581
So if each element of the tuple takes one byte, the tuple will take up 7.01 GiB.
You'll need to either reduce the size of the tuple, or possibly make each element take up less space by specifying the type of each element: I would suggest looking into Numpy for the latter.
Specifically for this problem:
Why use a tuple at all?
You create the variable look which is just a list of integers:
look=tuple(range(n)) # = (0, 1, 2, ..., n-1)
Then you reference it, but never modify it. So: look[i] == i and look[j] == j.
So you're looking up numbers in a list of numbers. Why look them up? Why not just use i in place of look[i] and remove look altogether?
As others have pointed out, there's no need to use tuples at all.
One reasonably efficient way of solving this problem is to generate a series of integer square values (0, 1, 4, 9, etc...) and test whether or not subtracting these values from n leaves you with a value that is a perfect square.
You can generate a series of perfect squares efficiently by adding successive odd numbers together: 0 (+1) → 1 (+3) → 4 (+5) → 9 (etc.)
There are also various tricks you can use to test whether or not a number is a perfect square (for example, see the answers to this question), but — in Python, at least — it seems that simply testing the value of int(n**0.5) is faster than iterative methods such as a binary search.
def integer_sqrt(n):
# If n is a perfect square, return its (integer) square
# root. Otherwise return -1
r = int(n**0.5)
if r * r == n:
return r
return -1
def sum_of_two_squares(n):
# If n can be expressed as the sum of two squared integers,
# return these integers as a tuple. Otherwise return <None>
# i: iterator variable
# x: value of i**2
# y: value we need to add to x to obtain (i+1)**2
i, x, y = 0, 0, 1
# If i**2 > n / 2, then we can stop searching
max_x = n >> 1
while x <= max_x:
r = integer_sqrt(n-x)
if r >= 0:
return (i, r)
i, x, y = i+1, x+y, y+2
return None
This returns a solution to sum_of_two_squares(55555**2 + 66666**2) in a fraction of a second.
You do not need the ranges at all, and certainly do not need to convert them into tuples. They take a ridiculous amount of space, but you only need their current elements, numbers i and j. Also, as the friendly commenter suggested, you can start with sqrt(n) to improve the performance further.
def sum_of_two_squares(n):
i = 1
j = int(n ** (1/2))
while i < j:
x = i * i + j * j
if x == n:
return j, i
if x < n:
i += 1
else:
j -= 1
Bear in mind that the problem takes a very long time to be solved. Be patient. And no, NumPy won't help. There is nothing here to vectorize.
Related
I have a problem for an assignment I am working on, where I have to write a recursive function in python which returns the balanced code of size k, which is defined as the list of all binary strings of length 2k that contain an equal number of 0s in each half of the string. It is only allowed to accept one parameter, k. I have so far found a way to return a list of all possible binary strings of length 2k, but am having trouble reducing the list to only those that meet the criteria. This is my code so far:
def balanced_code(k):
if k >= 0:
if k == 0:
return ['']
else:
L = []
x = balanced_code(k - 1)
for i in range(0, len(x)):
L.append('00' + x[i])
L.append('01' + x[i])
L.append('10' + x[i])
L.append('11' + x[i])
return L
else:
return
My plan was after the for loop, I would check each item in L for the criteria mentioned (number of 0s equal in each half of the string), but quickly realized that this didn't give the right result as it would reduce L during every call, and I only want to reduce it once all calls to the function have been made. Is there any way I could track what recursion level the code is on or something like that so that I only reduce the list once all calls have been made?
How recursive does this have to be? Where does the recursion need to be?
If this were me, I'd write a recursive function:
def all_strings_of_length_k_with_n_zeros(k, n):
... you should be able to write this easily as recursion
And then
def balanced_code(k):
result = []
for zeros in range(0, k + 1):
temp = all_strings_of_length_k_with_n_zeros(k, zeros)
for left, right in itertools.product(temp, temp):
result.append(left + right)
return result
It's strange that your instructor is asking you to write some code recursively that can be written straightforwardly without recursion. (The function I left as an exercise to the reader could be written using itertools.combinations).
You can approach the recursion by adding "0" and "1" bits on each side of the k-1 results. The bits need to be added last on the right side and at every position on the left side. Since this is going to produce duplicates, using a set to return the strings will ensure distinct results.
def balancedCodes(k):
if not k: return {""}
return { code[:pos]+bit+code[pos:]+bit for code in balancedCodes(k-1)
for pos in range(k)
for bit in ("0","1") }
for bc in sorted(balancedCodes(3)): print(bc)
000000
001001
001010
001100
010001
010010
010100
011011
011101
011110
100001
100010
100100
101011
101101
101110
110011
110101
110110
111111
The 111111 result is a case of having no zeroes on each side
One way to solve this recursively without creating duplicates is by using what's described by The On-Line Encyclopedia of Integer Sequences® as the "1's-counting sequence: number of 1's in binary expansion of n (or the binary weight of n)" (sequence A000120), which can be formulated as a recurrence relation (see the function, f, below). Although we could "unpack" the sequence into our result at every stage for a self-contained recursive answer, it seemed superfluous so I left the unpacking of the sequence as a separate function we can call on the result.
def str_tuple(a, b, k):
return "{0:0{align}b}{1:0{align}b}".format(a, b, align=k)
def unpack(seq, k):
bitcounts = [[] for _ in range(k + 1)]
products = []
for n, i in enumerate(seq):
for n0 in bitcounts[i]:
products.extend([str_tuple(n0, n, k), str_tuple(n, n0, k)])
products.append(str_tuple(n, n, k))
bitcounts[i].append(n)
return products
def f(n):
if n == 1:
return [0, 1]
seq_l = f(n - 1)
seq_r = list(map(lambda x: x + 1, seq_l))
return seq_l + seq_r
k = 3
print(f(k))
print(unpack(f(k), k))
Output:
[0, 1, 1, 2, 1, 2, 2, 3]
['000000', '001001', '001010', '010001', '010010',
'011011', '001100', '100001', '010100', '100010',
'100100', '011101', '101011', '101101', '011110',
'110011', '101110', '110101', '110110', '111111']
This question already has answers here:
Python: Generate random number between x and y which is a multiple of 5 [duplicate]
(4 answers)
Closed 3 years ago.
I want to generate a random number from range [a,b] that is dividsible by N (4 in my case).
I have the solution, but is there a better (more elegant) way to do it?
result = random.randint(a, b)
result = math.ceil(result / 4) * 4
Solutions from here:
Python: Generate random number between x and y which is a multiple of 5
doesn't answer my question since I'll have to implement something like:
random.randint(a, b) * 4;
I'll have to divide original range by 4 and it's less readable then my original solution
A generic solution and an example
import random
def divisible_random(a,b,n):
if b-a < n:
raise Exception('{} is too big'.format(n))
result = random.randint(a, b)
while result % n != 0:
result = random.randint(a, b)
return result
# get a random int in the range 2 - 12, the number is divisible by 3
print(divisible_random(2,12,3))
The first thing coming to my mind is creating a list of all the possible choices using range in the given interval, followed by randomly choosing one value using choice.
So, in this case, for a given a and b,
random.choice(range(a + 4 - (a%4), b, 4))
If a is a perfect multiple of 4, then
random.choice(range(a, b, 4))
Would give you the required random number.
So, in a single generic function, (as suggested in comments)
def get_num(a, b, x):
if not a % x:
return random.choice(range(a, b, x))
else:
return random.choice(range(a + x - (a%x), b, x))
where x is the number whose multiples are required.
As the others have pointed out, your solution might produce out of range results, e.g. math.ceil(15 / 4) * 4 == 16. Also, be aware that the produced distribution might be very far from uniform. For example, if a == 0 and b == 4, the generated number will be 4 in 80% of the cases.
Aside from that, it seems good to me, but in Python, you can also just use the integer division operator (actually floor division, so it's not equivalent to your examlpe):
result = random.randint(a, b)
result = result // 4 * 4
But a more general albeit less efficient method of generating uniform random numbers with specific constraints (while also keeping the uniform distribution) is generating them in a loop until you find a good one:
result = 1
while result % 4 != 0:
result = random.randint(a, b)
Use random.randrange with a step size of n, using a+n-(a%n) as start if a is non-divisible by n, else use a as start
import random
def rand_n(a, b,n):
#If n is bigger than range, return -1
if n > b-a:
return -1
#If a is divisible by n, use a as a start, using n as step size
if a%n == 0:
return random.randrange(a,b,n)
# If a is not divisible by n, use a+n-(a%n) as a start, using n as step size
else:
return random.randrange(a+n-(a%n),b, n)
So currently I am trying to implement finite fields using only polynomials. So like, I don't want to be operating on binary numbers using operations such as AND. Instead I want to make the whole thing with polynomials.
I have got very far with this, having multiplication (not necessary to include here), addition, etc working. The issue is when I modulo by my prime polynomial, I am having to convert polynomials to integers to compare the size of them. I want to avoid doing this, is there a way to get around this issue and to do the modulo differently?
import collections
from math import log
import itertools
def XorAsPolynomial(a,b): #basically, we merge the terms of 2 polynomials together, and if a term repeats an even number of times, remove all of them, and if its an odd number of times, remove all but 1. this is the same as xor
c = a+b
counter=collections.Counter(c)
Values = list(counter.values())
Keys = list(counter.keys())
for i in range(len(Values)):
if (Values[i])%2 == 0:
for q in range(Values[i]):
del c[c.index(Keys[i])]
if (Values[i])%2 == 1:
for q in range(Values[i]-1):
del c[c.index(Keys[i])]
return c
def MultAsPolys(a,b,k):
c = []
d = []
if len(a) < len(b):
a,b = b,a
for i in range(len(b)):
for s in range(len(a)):
c.append((a[s]+b[i])) #So far we have done multiplication without collecting any like terms. This is important
counter=collections.Counter(c)
Values = list(counter.values())
Keys = list(counter.keys())
for i in range(len(Values)): #basically, now we pretend we collected the terms, but modulo them by 2. So "3x" becomes "x", and "2x" becomes 0
if (Values[i])%2 == 0: #of course, we never did actually collect the terms in the list since this wouldnt keep data about how many "x"s we have.
for q in range(Values[i]): # So instead what we have done is, we have counted how many of each term we have in the list and modulo'd that number by 2,
del c[c.index(Keys[i])] # we have then just removed all terms like it in cases where there was an even number of them, and we have removed all but 1 term when there was an odd number
if (Values[i])%2 == 1:
for q in range(Values[i]-1):
del c[c.index(Keys[i])]
return c
def ModuloAsPolynomial(t,b): #this is the modulo operation, the focus of the question
for i in range(len(b)):
b[i] = b[i] + 64
for i in range(65):
tt = XorAsPolynomial(t , b)
if (PolyToInt(tt)) < (PolyToInt(t)): #THIS is the line in particular thats an issue. It works, but I want to be able to do this line without having the "IntToPoly" part. This is because the next part of this project will involve things that will break this code if i do it like this.
t = tt #basically, instead of seeing if tt is less than t, i need another way of doing it that keeps both as polynomials
for i in range(len(b)):
b[i] = b[i] - 1
return t
def IntToPoly(bInt): #turns numbers into polynomial lists
exp = 0
poly = []
while bInt:
if bInt & 1:
poly.append(exp)
exp += 1
bInt >>= 1
return poly[::-1]
def PolyToInt(a): #turns polynomial lists back into numbers
k = 0
for i in range(len(a)):
k = k+(2**a[i])
#k = round(k.real,8) + (round(k.imag,8)*1j) #ignore that
return k
def Test():
PrimePolynomial = [8, 6, 5, 3, 0] #this is our prime polynomial. In decimal form it is 361
TenSquared = [12, 10, 4] #this is the number we are doing the modulo on. In decimal form its 5136, which is 10^2 using our multiplication method outlined in the function ModuloAsPolynomial
output = ModuloAsPolynomial(TenSquared,PrimePolynomial) #the output is [6, 4, 1], which is 82 as a decimal number. This is the intended output
#Sorry if their are any spelling errors here. I am dyslexic and this has no spell check
The result would be the same as the code works in its current state, but I need it to work in this other way before I can move on.
The modulo function is just a divide that doesn't keep the quotient, but does keep the remainder, source_polynomial (dividend) % field_polynomial (divisor). I don't see the need to converting to int for compare. I don't know python, but the logic would be something like this (assuming that exponents are always kept in decreasing order, largest to smallest). The xor should just merge the two sets of exponents (keeping them in descending order), except that duplicate exponents would be dropped instead of copied (since xor would zero the 1 bit coefficient for these exponents).
while(true){
e = dividend[0] - divisor[0] // e = exponent of dividend - exponent of divisor
if(e < 0)break; // break if dividend < divisor
temp = divisor;
for(i = 0; i < len(divisor); i++) // create "shifted" copy of divisor
temp[i] += e;
dividend = dividend xor temp; // "subtract" temp from dividend
// this reduces size of dividend
if(len(dividend) == 0)break; // break if dividend == 0
}
I am trying to make a program that returns the sum of all integers in a list, bigger than n or equal to n. For example,
>>>floorSum([1,3,2,5,7,1,2,8], 4)
20
Here is the code I came up with:
def floorSum(l,n):
if len(l)>0:
if l[0]<n:
floorSum(l[1:],n)
else:
s=l[0]+floorSum(l[1:],n)
return s
I am getting: UnboundLocalError: local variable 's' referenced before assignment.
Any ideas?
you forgot to initialize s to zero
def floorSum(l,n):
s = 0
if len(l) > 0:
if l[0] < n:
s = floorSum(l[1:], n)
else:
s = l[0] + floorSum(l[1:], n)
else:
return 0
return s
As others pointed out, you neglected to initialize s for all cases and check for a length of zero.
Here's an alternative approach:
def floorSum(l, n):
if len(l) > 1:
mid = len(l) // 2 # Python 3 integer division
return floorSum(l[:mid], n) + floorSum(l[mid:], n)
if len(l) == 1 and l[0] >= n:
return l[0]
return 0
This version will divide the list into halves at each step, so although it doesn't do any less work the depth of the recursion stack is O(log(len(l))) rather than O(len(l)). That will prevent stack overflow for large lists.
Another benefit of this approach is the additional storage requirements. Python is creating sublists in both versions, but in your original version the additional storage required for the sublists is (n-1) + (n-2) + ... + 1, which is O(n2). With the successive halving approach, the additional storage requirement is O(n log n), which is substantially lower for large values of n. Allocating and freeing that additional storage may even impact the run time for large n. (Note, however, that this can be avoided in both algorithms by passing the indices of the range of interest as arguments rather than creating sublists.)
Thanks I solved the problem!
Forgot to put s=0
Python is a wonderful language that allows you to do that in a single line with list comprehension.
s = sum([value for value in l if value >= n])
Another way is to use filter
s = sum(filter(lambda e: e >= n, l))
The first one basically says:
"Create a new list from the elements of l, so that they are all greater or equal to n. Sum that new list."
The second one:
"Filter only the elements that are greater or equal to n. Sum over that."
You can find ample documentation on both of these techniques.
If you found the answer useful, mark it as accepted
For the following problem on SingPath:
Given an input of a list of numbers and a high number,
return the number of multiples of each of
those numbers that are less than the maximum number.
For this case the list will contain a maximum of 3 numbers
that are all relatively prime to each
other.
Here is my code:
def countMultiples(l, max_num):
counting_list = []
for i in l:
for j in range(1, max_num):
if (i * j < max_num) and (i * j) not in counting_list:
counting_list.append(i * j)
return len(counting_list)
Although my algorithm works okay, it gets stuck when the maximum number is way too big
>>> countMultiples([3],30)
9 #WORKS GOOD
>>> countMultiples([3,5],100)
46 #WORKS GOOD
>>> countMultiples([13,25],100250)
Line 5: TimeLimitError: Program exceeded run time limit.
How to optimize this code?
3 and 5 have some same multiples, like 15.
You should remove those multiples, and you will get the right answer
Also you should check the inclusion exclusion principle https://en.wikipedia.org/wiki/Inclusion-exclusion_principle#Counting_integers
EDIT:
The problem can be solved in constant time. As previously linked, the solution is in the inclusion - exclusion principle.
Let say you want to get the number of multiples of 3 less than 100, you can do this by dividing floor(100/3), the same applies for 5, floor(100/5).
Now to get the multiplies of 3 and 5 that are less than 100, you would have to add them, and subtract the ones that are multiples of both. In this case, subtracting multiplies of 15.
So the answer for multiples of 3 and 5, that are less than 100 is floor(100/3) + floor(100/5) - floor(100/15).
If you have more than 2 numbers, it gets a bit more complicated, but the same approach applies, for more check https://en.wikipedia.org/wiki/Inclusion-exclusion_principle#Counting_integers
EDIT2:
Also the loop variant can be speed up.
Your current algorithm appends multiple in a list, which is very slow.
You should switch the inner and outer for loop. By doing that you would check if any of the divisors divide the number, and you get the the divisor.
So just adding a boolean variable which tells you if any of your divisors divide the number, and counting the times the variable is true.
So it would like this:
def countMultiples(l, max_num):
nums = 0
for j in range(1, max_num):
isMultiple = False
for i in l:
if (j % i == 0):
isMultiple = True
if (isMultiple == True):
nums += 1
return nums
print countMultiples([13,25],100250)
If the length of the list is all you need, you'd be better off with a tally instead of creating another list.
def countMultiples(l, max_num):
count = 0
counting_list = []
for i in l:
for j in range(1, max_num):
if (i * j < max_num) and (i * j) not in counting_list:
count += 1
return count