Assume there are two variables, k and m, each already associated with a positive integer value and further assume that k's value is smaller than m's. Write the code necessary to compute the number of perfect squares between k and m. (A perfect square is an integer like 9, 16, 25, 36 that is equal to the square of another integer (in this case 3*3, 4*4, 5*5, 6*6 respectively).) Associate the number you compute with the variable q. For example, if k and m had the values 10 and 40 respectively, you would assign 3 to q because between 10 and 40 there are these perfect squares: 16, 25, and 36,.
**If I want to count the numbers between 16 and 100( 5,6,7,8,9 =makes 5)and write code in terms of with i and j, my code would be as follows but something goes wrong. I want to get the result,5 at last. how can I correct it?
k=16
m=100
i=0
j=0
q1=0
q2=0
while j**2 <m:
q2=q2+1
while i**2 <k:
q1=q1+1
i=i+1
j=j+1
print(q2-q1)
Your probably don't want to loop for this. If k and m are very far apart it will take a long time.
Given k < m, you want to compute how many integers l such that k < l^2 < m. The smallest possible such integer is floor( sqrt(k) +1 ) and the largest possible such integer is ceil(sqrt(m)-1). The number of such integers is:
import math
def sq_between(k,m):
return math.ceil(m**0.5-1) - math.floor(k**0.5+1) +1
This allows for
sq_between(16,100)
yielding:
5
Here is another version of your function that seems to do to what you ask for.
k = 16
m = 100
perfect_squares = []
for i in range(m):
if i**2 < k:
continue
if i**2 > m:
break
perfect_squares.append(i**2)
print(perfect_squares)
You code is mixing up everything in the second while loop. If you explain a bit further what you are trying to do there, I will probably be able to explain why your idea is not working.
I would change your code as follows in order to make it work:
k = 10
m = 40
i = 0
q = 0
while i ** 2 < m:
if i ** 2 > k:
print(i)
q += 1
i += 1
print (q)
By utilizing the fact that each square number can get expressed via square = sum from i = 1 to n (2 * i + 1) there is an easy way of speedup the above algorithm - but the algorithm will become much longer then ...
Related
We are given a number N and we have to find pairs i and j where i^3=j^2
For example, let N=50 so for this we will have 3 pairs (1,1),(4,8),(9,27)
basically, we have to find pairs where the cube of one number is the same as the square of the other number in a given pair
the constraint is
1<=N<10^6
1<=i,j<N
Naive approach use 2 for loops iterate through each element and get those pairs where cube is equal to sum time complexity is O(n*2)
def get_pair(N):
for i in range(1,N):
for j in range(1,N):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
what will be an optimal way to solve this problem with a better time complexity?
Since you're working with integers, if there exists some number M = i^3 = j^2 for i and j between 1 and N, then that means there exists a k such that M = k^6. To find i and j, simply compare the representations of M:
(1) M = k^6 = i^3 = (k^2)^3 therefore i = k^2
(2) M = k^6 = j^2 = (k^3)^2 therefore j = k^3
Since j is always greater than or equal to i, you only need to check if 1 < k^3 < N. In other words, k should be less than the cube root of N.
k
M = k^6
i = k^2
j = k^3
2
64
4
8
3
729
9
27
4
4,096
16
64
5
15,625
25
125
6
46,656
36
216
...
...
...
...
97
8.329x10^11
9409
912,673
98
8.858x10^11
9604
941,192
99
9.415x10^11
9801
970,299
Note that 100 isn't a valid candidate for k because that would make j less than or equal to N instead of strictly less than N (if we're going with N = 10^6).
So to get the list of tuples that satisfy your problem, find the values of k such that 1 < k^3 < N and return its square and cube in a tuple.
import math
from typing import List, Tuple
N: int = 10**6
pairs: List[Tuple[int, int]] = [(k * k, k * k * k) for k in range(2, math.ceil(N**(1 / 3)))]
print(pairs)
This is a list comprehension, a shorthand for a for-loop.
I'm basically asking Python to generate a list of tuples over an index k that falls in the range defined as range(2, math.ceil(N**(1 / 3)). That range is exactly the first column of the table above.
Then, for every k in that range I make a tuple of which the first item is k^2 and the second item is k^3, just like the last two columns of the table.
Also threw in the typing library in there for good measure. Clear code is good code, even for something as small as this. Python can figure out that pairs is a list of tuples without anyone telling it, but this way I've explicitly enforced that variable to be a list of tuples to avoid any confusion when someone tries to give it a different value or isn't sure what the variable contains.
Another naive approach could be to use the "basic" values ?
def get_pair(N):
for i in range(N):
if(i**3 > MAX):
break # Limit to the max you want, and i**3 > i**2 if i > 1
print(i**2, i**3)
Time complexity seems to be O(n) (Not an expert, so correct me if i'm wrong)
This is made so that the first element cubed == second element squared:
first = a^2
second = a^3
first^3 = a^(2*3) = a^6
second^2 = a^(3*2) = a^6
You can use itertool's combinations_with_replacement function.
from itertools import combinations_with_replacement as combinations
def get_pair(N):
for i, j in combinations(range(1,N), 2):
if i*i*i==j*j:
print(i,j)
N=50
get_pair(N)
You do this with one loop (and minimal iterations) if you know that that pairs (x, y) are always y = x * i, this means you can use:
def get_pair(N):
i = 1
a = 1
while a * i < N:
b = a * i
print(a,b)
i += 1
a = i**2
N=50
get_pair(N)
This gets all 3 pairs:
1 1
4 8
9 27
In only 3 total iterations.
I am trying to convert the below for loop to Python.
for (i = 5; i < n; i = i*5):
I am not sure how to make use of the Range function when i want the i value to be set to the multiple of 5. For example, 1st time I want the i to be 5, then followed by 25, then followed by 125 and it should go on.
The following is what i have tried:
i = 5
for i in range (i, n+1, i*5)
The problem with the above being, the value of i getting incremented by 25, making it to 30 whereas i want the i to be 25 in the second iteration. It is pretty easy when using the while loop. But I am seeing if there is a way to implement the same in the for loop. Please help. Thanks in advance.
I am not sure how to make use of the Range function when i want the i value to be set to the multiple of 5
It will not work that way. range can only create arithmetic sequences; multiplying every time creates a geometric sequence.
What you can do is take advantage of the fact that the i values are successive powers of 5; so make a loop over the desired exponent values, and compute i inside the loop:
# Computing the `limit` in terms of `n` is left as an exercise.
# Just in case you were already computing `n` in terms of an existing `limit`,
# in which case you could just use it directly ;)
for j in range(limit):
i = 5**j
There is a theorem in computer science that states that any "C-style" for loop can be transformed into an equivalent while loop. This is one of those cases where the transformation is desirable:
i = 5
while i < n:
# Loop body goes here
i *= 5
You can hide the loop logic behind a generator:
def multrange(start, stop, ratstep):
i = start
while i < stop:
yield i
i *= ratstep
list(multrange(5, 10000, 5))
#[5, 25, 125, 625, 3125]
You can define your own range function using yield!
def range(i, j, k):
while i * k < j:
i *= k
yield i
for i in range(5, 2000, 5):
print(i)
Output:
25
125
625
Most Python programmers would just use a while loop:
i = 5
while i < n:
....
i = i * 5
If you really, really want a for loop:
import itertools
for i in itertools.takewhile(lambda x: x < n, (5 ** i for i in itertools.count(1))):
... whatever ...
I would very much like to generate n random integer numbers between two values (min, max) whose sum is equal to a given number m.
Note: I found similar questions in StackOverflow; however, they do not address exactly this problem (use of Dirichlet function and thus numbers between 0 and 1).
Example: I need 8 random numbers (integers) between 0 and 24 where the sum of the 8 generated numbers must be equal to 24.
Any help is appreciated. Thanks.
Well, you could use integer distribution which naturally sums to some fixed number - Multinomial one.
Just shift forth and back, and it should work automatically
Code
import numpy as np
def multiSum(n, p, maxv):
while True:
v = np.random.multinomial(n, p, size=1)
q = v[0]
a, = np.where(q > maxv) # are there any values above max
if len(a) == 0: # accept only samples below or equal to maxv
return q
N = 8
S = 24
p = np.full((N), 1.0/np.float64(N))
mean = S / N
start = 0
stop = 24
n = N*mean - N*start
h = np.zeros((stop-start), dtype=np.int64)
print(h)
for k in range(0, 10000):
ns = multiSum(n, p, stop-start) + start # result in [0...24]
#print(np.sum(ns))
for v in ns:
h[v-start] += 1
print(h)
this is a case of partition number theory . here is solution .
def partition(n,k,l, m):
if k < 1:
raise StopIteration
if k == 1:
if n <= m and n>=l :
yield (n,)
raise StopIteration
for i in range(l,m+1):
for result in partition(n-i,k-1,i,m):
yield result+(i,)
n = 24 # sum value
k = 8 # partition size
l = 0 # range min value
m = 24 # range high value
result = list(partition(n,k,l,m ))
this will give all the combinations that satisfy the conditions.
ps this is quite slow as this is giving all the cases for that partition size.
This is one possible solution which is based on this answer. it seems the dirichlet method is only functional for between 0 and 1. Full credit should be given to the original answer. I will be happy to delete it once you comment that it served your purpose.
Don't forget to upvote the original answer.
target = 24
x = np.random.randint(0, target, size=(8,))
while sum(x) != target:
x = np.random.randint(0, target, size=(8,))
print(x)
# [3 7 0 6 7 0 0 1]
I'm a stumped on how to speed up my algorithm which sums multiples in a given range. This is for a problem on codewars.com here is a link to the problem
codewars link
Here's the code and i'll explain what's going on in the bottom
import itertools
def solution(number):
return multiples(3, number) + multiples(5, number) - multiples(15, number)
def multiples(m, count):
l = 0
for i in itertools.count(m, m):
if i < count:
l += i
else:
break
return l
print solution(50000000) #takes 41.8 seconds
#one of the testers takes 50000000000000000000000000000000000000000 as input
# def multiples(m, count):
# l = 0
# for i in xrange(m,count ,m):
# l += i
# return l
so basically the problem ask the user return the sum of all the multiples of 3 and 5 within a number. Here are the testers.
test.assert_equals(solution(10), 23)
test.assert_equals(solution(20), 78)
test.assert_equals(solution(100), 2318)
test.assert_equals(solution(200), 9168)
test.assert_equals(solution(1000), 233168)
test.assert_equals(solution(10000), 23331668)
my program has no problem getting the right answer. The problem arises when the input is large. When pass in a number like 50000000 it takes over 40 seconds to return the answer. One of the inputs i'm asked to take is 50000000000000000000000000000000000000000, which a is huge number. That's also the reason why i'm using itertools.count() I tried using xrange in my first attempt but range can't handle numbers larger than a c type long. I know the slowest part the problem is the multiples method...yet it is still faster then my first attempt using list comprehension and checking whether i % 3 == 0 or i % 5 == 0, any ideas guys?
This solution should be faster for large numbers.
def solution(number):
number -= 1
a, b, c = number // 3, number // 5, number // 15
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
return 3*asum + 5*bsum - 15*csum
Explanation:
Take any sequence from 1 to n:
1, 2, 3, 4, ..., n
And it's sum will always be given by the formula n(n+1)/2. This can be proven easily if you consider that the expression (1 + n) / 2 is just a shortcut for computing the average, or Arithmetic mean of this particular sequence of numbers. Because average(S) = sum(S) / length(S), if you take the average of any sequence of numbers and multiply it by the length of the sequence, you get the sum of the sequence.
If we're given a number n, and we want the sum of the multiples of some given k up to n, including n, we want to find the summation:
k + 2k + 3k + 4k + ... xk
where xk is the highest multiple of k that is less than or equal to n. Now notice that this summation can be factored into:
k(1 + 2 + 3 + 4 + ... + x)
We are given k already, so now all we need to find is x. If x is defined to be the highest number you can multiply k by to get a natural number less than or equal to n, then we can get the number x by using Python's integer division:
n // k == x
Once we find x, we can find the sum of the multiples of any given k up to a given n using previous formulas:
k(x(x+1)/2)
Our three given k's are 3, 5, and 15.
We find our x's in this line:
a, b, c = number // 3, number // 5, number // 15
Compute the summations of their multiples up to n in this line:
asum, bsum, csum = a*(a+1) // 2, b*(b+1) // 2, c*(c+1) // 2
And finally, multiply their summations by k in this line:
return 3*asum + 5*bsum - 15*csum
And we have our answer!
recently I became interested in the subset-sum problem which is finding a zero-sum subset in a superset. I found some solutions on SO, in addition, I came across a particular solution which uses the dynamic programming approach. I translated his solution in python based on his qualitative descriptions. I'm trying to optimize this for larger lists which eats up a lot of my memory. Can someone recommend optimizations or other techniques to solve this particular problem? Here's my attempt in python:
import random
from time import time
from itertools import product
time0 = time()
# create a zero matrix of size a (row), b(col)
def create_zero_matrix(a,b):
return [[0]*b for x in xrange(a)]
# generate a list of size num with random integers with an upper and lower bound
def random_ints(num, lower=-1000, upper=1000):
return [random.randrange(lower,upper+1) for i in range(num)]
# split a list up into N and P where N be the sum of the negative values and P the sum of the positive values.
# 0 does not count because of additive identity
def split_sum(A):
N_list = []
P_list = []
for x in A:
if x < 0:
N_list.append(x)
elif x > 0:
P_list.append(x)
return [sum(N_list), sum(P_list)]
# since the column indexes are in the range from 0 to P - N
# we would like to retrieve them based on the index in the range N to P
# n := row, m := col
def get_element(table, n, m, N):
if n < 0:
return 0
try:
return table[n][m - N]
except:
return 0
# same definition as above
def set_element(table, n, m, N, value):
table[n][m - N] = value
# input array
#A = [1, -3, 2, 4]
A = random_ints(200)
[N, P] = split_sum(A)
# create a zero matrix of size m (row) by n (col)
#
# m := the number of elements in A
# n := P - N + 1 (by definition N <= s <= P)
#
# each element in the matrix will be a value of either 0 (false) or 1 (true)
m = len(A)
n = P - N + 1;
table = create_zero_matrix(m, n)
# set first element in index (0, A[0]) to be true
# Definition: Q(1,s) := (x1 == s). Note that index starts at 0 instead of 1.
set_element(table, 0, A[0], N, 1)
# iterate through each table element
#for i in xrange(1, m): #row
# for s in xrange(N, P + 1): #col
for i, s in product(xrange(1, m), xrange(N, P + 1)):
if get_element(table, i - 1, s, N) or A[i] == s or get_element(table, i - 1, s - A[i], N):
#set_element(table, i, s, N, 1)
table[i][s - N] = 1
# find zero-sum subset solution
s = 0
solution = []
for i in reversed(xrange(0, m)):
if get_element(table, i - 1, s, N) == 0 and get_element(table, i, s, N) == 1:
s = s - A[i]
solution.append(A[i])
print "Solution: ",solution
time1 = time()
print "Time execution: ", time1 - time0
I'm not quite sure if your solution is exact or a PTA (poly-time approximation).
But, as someone pointed out, this problem is indeed NP-Complete.
Meaning, every known (exact) algorithm has an exponential time behavior on the size of the input.
Meaning, if you can process 1 operation in .01 nanosecond then, for a list of 59 elements it'll take:
2^59 ops --> 2^59 seconds --> 2^26 years --> 1 year
-------------- ---------------
10.000.000.000 3600 x 24 x 365
You can find heuristics, which give you just a CHANCE of finding an exact solution in polynomial time.
On the other side, if you restrict the problem (to another) using bounds for the values of the numbers in the set, then the problem complexity reduces to polynomial time. But even then the memory space consumed will be a polynomial of VERY High Order.
The memory consumed will be much larger than the few gigabytes you have in memory.
And even much larger than the few tera-bytes on your hard drive.
( That's for small values of the bound for the value of the elements in the set )
May be this is the case of your Dynamic programing algorithm.
It seemed to me that you were using a bound of 1000 when building your initialization matrix.
You can try a smaller bound. That is... if your input is consistently consist of small values.
Good Luck!
Someone on Hacker News came up with the following solution to the problem, which I quite liked. It just happens to be in python :):
def subset_summing_to_zero (activities):
subsets = {0: []}
for (activity, cost) in activities.iteritems():
old_subsets = subsets
subsets = {}
for (prev_sum, subset) in old_subsets.iteritems():
subsets[prev_sum] = subset
new_sum = prev_sum + cost
new_subset = subset + [activity]
if 0 == new_sum:
new_subset.sort()
return new_subset
else:
subsets[new_sum] = new_subset
return []
I spent a few minutes with it and it worked very well.
An interesting article on optimizing python code is available here. Basically the main result is that you should inline your frequent loops, so in your case this would mean instead of calling get_element twice per loop, put the actual code of that function inside the loop in order to avoid the function call overhead.
Hope that helps! Cheers
, 1st eye catch
def split_sum(A):
N_list = 0
P_list = 0
for x in A:
if x < 0:
N_list+=x
elif x > 0:
P_list+=x
return [N_list, P_list]
Some advices:
Try to use 1D list and use bitarray to reduce memory footprint at minimum (http://pypi.python.org/pypi/bitarray) so you will just change get / set functon. This should reduce your memory footprint by at lest 64 (integer in list is pointer to integer whit type so it can be factor 3*32)
Avoid using try - catch, but figure out proper ranges at beginning, you might found out that you will gain huge speed.
The following code works for Python 3.3+ , I have used the itertools module in Python that has some great methods to use.
from itertools import chain, combinations
def powerset(iterable):
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
nums = input("Enter the Elements").strip().split()
inputSum = int(input("Enter the Sum You want"))
for i, combo in enumerate(powerset(nums), 1):
sum = 0
for num in combo:
sum += int(num)
if sum == inputSum:
print(combo)
The Input Output is as Follows:
Enter the Elements 1 2 3 4
Enter the Sum You want 5
('1', '4')
('2', '3')
Just change the values in your set w and correspondingly make an array x as big as the len of w then pass the last value in the subsetsum function as the sum for which u want subsets and you wl bw done (if u want to check by giving your own values).
def subsetsum(cs,k,r,x,w,d):
x[k]=1
if(cs+w[k]==d):
for i in range(0,k+1):
if x[i]==1:
print (w[i],end=" ")
print()
elif cs+w[k]+w[k+1]<=d :
subsetsum(cs+w[k],k+1,r-w[k],x,w,d)
if((cs +r-w[k]>=d) and (cs+w[k]<=d)) :
x[k]=0
subsetsum(cs,k+1,r-w[k],x,w,d)
#driver for the above code
w=[2,3,4,5,0]
x=[0,0,0,0,0]
subsetsum(0,0,sum(w),x,w,7)