why is my code producing one more than it should? - python

I am trying to solve the following problem:
Your task is to construct a building which will be a pile of n cubes. The cube at the bottom will have a volume of n^3, the cube above will have volume of (n-1)^3 and so on until the top which will have a volume of 1^3.
You are given the total volume m of the building. Being given m can you find the number n of cubes you will have to build?
The parameter of the function findNb (find_nb, find-nb, findNb) will be an integer m and you have to return the integer n such as n^3 + (n-1)^3 + ... + 1^3 = m if such a n exists or -1 if there is no such n.
Examples:
findNb(1071225) --> 45
findNb(91716553919377) --> -1
Here is my code:
def find_Nb(m):
n = 1
while n <= m // 2:
total_n = 0
for i in range(0, n):
total_n += (n - i) ** 3
n += 1
if total_n == m:
return n
break
else:
return -1
For some reason, the output produces (n+1) in the case where total_n ==m.
So for example, if we do m = 100, the output should be 4; but the above code produces 5; any idea why this is?
Or as per the example, when I run m=1071225 into the code I should get an output of 45, but my code produces 46.

this is the code that I wrote and it works but when I first tried it I had the same problem as you. I fixed it by putting the n = i before i+=1 so that n has the right value so I think you too have to make a copy of n before you say n += 1 and to return that value.
def findN(m):
sum = 0
i = 1
while sum < m:
sum += i ** 3
n = i
i += 1
if sum == m:
return n
else:
return -1
print(findN(1071225))

Related

Finding sum of a fibonacci consistent subarray

We have an input integer let's say 13. We can find consistent subarray of fibonacci numbers that sums to 10 - [2,3,5]. I need to find next number that is not a sum of consistent subarray. In this case this number will be 14. I have this code, but the catch is, it can be optimized to not iterate through all of the N's from starting Left Pointer = 1 and Right Pointer = 1 but somehow "import" from previous N and i have no clue how to do it so maybe someone smarter might help.
def fib(n):
if n == 1: return 1
if n == 2: return 1
return fib(n-1) + fib(n-2)
def fibosubarr(n):
L_pointer = 1
R_pointer = 2
sumfibs = 1
while sumfibs != n:
if sumfibs > n and L_pointer < R_pointer:
sumfibs -= fib(L_pointer)
L_pointer += 1
elif sumfibs < n and L_poiner < R_pointer:
sumfibs += fib(R_pointer)
R_pointer += 1
else: return False
return True
n = int(input())
while fibosubarr(n):
n += 1
print(n)
Here's a technique called "memoizing". The fib function here keeps track of the current list and only extends it as necessary. Once it has generated a number, it doesn't need to do it again.
_fib = [1,1]
def fib(n):
while len(_fib) <= n:
_fib.append( _fib[-2]+_fib[-1] )
return _fib[n]
With your scheme, 200000 caused a noticeable delay. With this scheme, even 2 billion runs instantaneously.
To get the next subarray sum, you only need one call of the function -- provided you keep track of the least sum value that was exceeding n.
I would also use a generator for the Fibonacci numbers:
def genfib():
a = 1
b = 1
while True:
yield b
a, b = b, a + b
def fibosubarr(n):
left = genfib()
right = genfib()
sumfibs = next(right)
closest = float("inf")
while sumfibs:
if sumfibs > n:
closest = min(sumfibs, closest)
sumfibs -= next(left)
elif sumfibs < n:
sumfibs += next(right)
else:
return n
return closest
Now you can do as you did -- produce the next valid sum that is at least the input value:
n = int(input())
print(fibosubarr(n))
You could also loop to go from one such sum to the next:
n = 0
for _ in range(10): # first 10 such sums
n = fibosubarr(n+1)
print(n)

python Find the sum of all multiples of n below m

Find the sum of all multiples of n below m
Keep in Mind n and m are natural numbers (positive integers) m is
excluded from the multiples
sumMul(2, 9) ==> 2 + 4 + 6 + 8 = 20
sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30
sumMul(4, -7) ==> "INVALID"
I did sum of list using range(n, m, n) using n as step.
I also tried modulus to avoid range 3 args error.
I can pass many tests but cannot pass all of them.
I have tried lots of logic but to no avail. What I am doing wrong?
CODEWARS: https://www.codewars.com/kata/57241e0f440cd279b5000829/train/python
MY CODE:
def sum_mul(n, m):
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n == 0 and m == 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
Your code fails if n == 0 as then the number % n checks in the list comprehension fail, so you should check that before trying to compute the sum. Also, you could use a range with step and just do sum(range(n, m, n)). However, both ways might be too slow for some test cases with very large m.
You can do this in O(1) with the following observations:
there are (m-1) // n multiples of n below m
the sum of natural numbers from 1 to n is n*(n+1)//2
Combine those two to get the result.
Example for sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30:
(13-1) // 3 == 4 so we know there are 4 multiples of 3 below 13
those are 3 + 6 + 9 + 12 == 3 * (1 + 2 + 3 + 4)
with (2) we know 1 + 2 + 3 + 4 == 4*5//2 == 10
so the result is 10 * 3 == 30
Putting that into code and handling the special cases is left as an exercise to the interested reader.
You have one main problem, that is you should prevent the situation when n==0 and you divide it in your list comprehension. It will raise zero division error. so you should check before the validation that n is not equal to zero.
Second thing is that you need to check whether n or m are negatives, as the exercise declared both n and m should be positives.
def sum_mul(n, m):
if n==0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n < 0 and m <= 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
You can just compute that result mathematically using integer divisions:
def sum_mul(n, m):
if n<1 or n>m: return "INVALID"
return m//n*(m//n+1)//2*n
First you get the number of multiple of n in m (which is merely dividing m by n ignoring the remainder) : m//n
Multiples of n will be nx1, nx2, nx3, ... up to the number of multiples. Factorizing the sum of those by n we get: n(1+2+3+ ... m//n).
The sum of numbers from 1 up to a given number x is obtained by x(x+1)/2. In this case x is the number of multiples m//n
Putting it all together we get n * x * (x+1) /2 where x is m//n, so:
n * (m//n) * (m // n + 1) // 2
You should comprove all cases before call sum function.
Like this:
def sum_mul(n, m):
if n == 0 or m == 0:
return 'INVALID'
if n == m:
return n - m
if n<0 or m<0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
return sum(my_list)
In fact, you dont't need to create if elif structure because you are using returns, so next instruction after return not executed.

Why does a change in multiplication sign in factorial to addition sign give such an output?

Question: Why is the output 11 not 12?
i+4+i+3+i+2 = 1+4+1+3+1+2 = 12
Code:
def factorial(n):
i = 1
while n >= 1:
#I changed the signs from * to + after getting the factorial from * method.
i = i * n --> i = i + n
n = n - 1
return i
print factorial(4)
11
To get expected i+4 + i+3 + i+2 and result 12 you need
def factorial(n):
result = 0
i = 1
while n > 1:
result += i + n
n = n - 1
return result
print(factorial(4))
I add to new variable result so I don't change i and it is 1 all the time.
I also use > instead of >= so it ends after i+2 and it doesn't add i+1
def factorial(n):
i = 1
while n >= 1:
#I changed the signs from * to + after getting the factorial from * method.
print(i)
i = i + n
n = n - 1
return i
print(factorial(4))
If you print i, you will find i has changed after first loop.
So the output should be 1+4+3+2+1=11
(Posted on behalf of the question author).
Tips from me to solve the problem: 1. understand the concept of loop 2. try to print the answer on your own - i=5, n=3, i=8, n=2, i=10, n=1, i=11

Python : Primes in numbers

Given a positive number n > 1 find the prime factor decomposition of n. The result will be a string with the following form :
"(p1**n1)(p2**n2)...(pk**nk)"
with the p(i) in increasing order and n(i) empty if n(i) is 1.
Example: n = 86240 should return "(2**5)(5)(7**2)(11)"
This is my code , but i have problem with time for n>250000
def primeFactors(n):
a=""
i=2
while i<=n:
#part of identifying if number i is prime
w1=5
w2=2
gg=0
while w1*w1<=i:
if i%w1==0:
gg=1
break
w1+=w2
w2=6-w2
#checking if previous loop has been broken
if gg:
i+=1
continue
#countig how many thimes we can divide n on i
c=0
for j in range(1,n):
if n%i!=0: break
c+=1
n=n//i
#if we can divide n on i only once
if c==1:
a+="("+str(i)+")"
elif c>1:
a+="("+str(i)+"**"+str(c)+")"
i+=1
return a
is there a way to fix this problem?
The problem isn't prime factorization, which the program does, it's getting Python to do it for very large numbers in a very small amount of time. Specifically, my understanding is we need to be able to calculate:
for n in range(10 ** 9, 10 ** 9 + 10):
print(n, '=', primeFactors(n))
in <= 120ms or less, i.e. <= 12ms per number. The OP's code doesn't get past 10 ** 9 + 4 before milliseconds turn into seconds, seconds into minutes. My first impression of your code is you need to separate your prime logic from the rest of the code, to make it understandable, and then clean up and optimize both parts of the code. My rewrite of your program:
def generate_primes(n):
""" generate real primes """
yield(2)
primes = [(2, 4)]
for m in range(3, n, 2):
for prime, square in primes:
if square > m:
yield(m)
primes.append((m, m * m))
break
if m % prime == 0:
break
def primeFactors(n):
string = ""
i = 2
for i in generate_primes(int(n ** 0.5) + 1):
# counting how many times we can divide n on i
c = 0
while True:
product, remainder = divmod(n, i)
if remainder != 0:
break
n = product
c += 1
# if we can divide n on i only once
if c == 1:
string += f"({i})"
elif c > 1:
string += f"({i}**{c})"
if n > 1: # final prime factor greater than square root
string += f"({n})"
return string
I swapped in a prime generator to avoid redundant calculations. This optimized version can achieve 32ms per large number factored in the above test. Still not good enough. So let's try #JamesKPolk's suggestion and use pseudoprimes:
def generate_primes(n):
""" generate 5-rough pseudoprimes """
if n >= 2:
yield(2)
if n >= 3:
yield(3)
if n >= 5:
m = 1
x = 4
while m < n:
m += x
yield(m)
x = 6 - x
The tradeoff here is that we will test more divisors than we really need, but we can generate these divisors much faster. This change achieves our goal of <= 12ms per large number factored, on my machine anyway.
OUTPUT
> time python3 test.py
1000000000 = (2**9)(5**9)
1000000001 = (7)(11)(13)(19)(52579)
1000000002 = (2)(3)(43)(983)(3943)
1000000003 = (23)(307)(141623)
1000000004 = (2**2)(41**2)(148721)
1000000005 = (3)(5)(66666667)
1000000006 = (2)(500000003)
1000000007 = (1000000007)
1000000008 = (2**3)(3**2)(7)(109**2)(167)
1000000009 = (1000000009)
0.106u 0.010s 0:00.11 100.0% 0+0k 0+0io 0pf+0w
>

Python - maximum number of terms added of a series such that sum < 5?

Hi I was asked the following:
Consider the series
Total = 1/1 + 1/2 + 1/3 + 1/4 + 1/5 .... + 1/N
What is the maximum number of terms added (i.e. the value of N) such that Total < 5.0?
(write a few lines of Python code stopping when the sum is just less than 5.0)
So far thats what i did:
m = 5
n= 0
u = 1
sum_serie = 0
for u in range(1,100):
u = 1/(n+1)
n= n+1
while u < m:
sum_serie = sum_serie + u
print(sum_serie)
print(n)
it doesn't work. could someone explain? is there an easier way of doing it?
thanks
This is perhaps the corrected version:
m = 5
n = 0
sum_series = 0
while sum_series < m:
u = 1. / (n + 1)
sum_series = sum_series + u
n = n + 1
print(sum_series)
print(n)
which prints:
5.00206827268
83
First your while loop should have the condition sum_serie < m and parts u = 1. / (n + 1) and n = n + 1 should be within that loop as shown. The for loop doesn't do what you need so it has been removed.
To loop to the number just below the limit, just check the limit as a loop condition (here in a while) and change the value inside the loop. Something like;
limit = 5
n = 0
sum_serie = 0
while sum_serie + 1./(n+1) < limit:
sum_serie += 1./(n+1)
n += 1
print(sum_serie)
print(n)
For your data, you get the output;
4.9900200799090815
82

Categories

Resources