How to stop a Python program when it reaches a certain point? - python

I want to create a function so that it will find the integer a so that a <= n.
If n is 99, then the program will return a = 3.
This is because the function is finding the sums of the consecutive cubes.
So, 1 + 8 + 27 + 64 = 100, which is more than 99. But 1 + 8 + 27 is less than 99, so a = 3 is the correct answer.
I was trying to do something like:
cubes = 0
for i in xrange(1, 1+x)
cubes += i*i*i
while cubes <= n
but I am very confused. How should I proceed?

First replace the for loop with a while loop:
cubes, i = 0, 0
while cubes <= n:
i += 1
cubes += i ** 3
Then, after the loop, subtract the last cube because you'll have gone over the limit n:
cubes -= i ** 3
i still has the final value it had in the loop.
Alternatively, you can do everything in one loop, by first computing the new value of cubes as a temporary variable, then only updating cubes if you've not gone over the limit:
cubes, i = 0, 0
while True: # infinite loop
i += 1
new_cubes = cubes + i ** 3
if new_cubes > n:
break
else:
cubes = new_cubes

Using itertools.count and a for-loop:
from itertools import count
def solve(n, pow):
total = 0
for i in count(1):
if total + i**pow > n:
return i-1
total += i**pow
Demo:
>>> solve(99, 3)
3
>>> solve(50, 2)
4

Here's how I'd do it.
def cubes(n=1):
while True:
yield n ** 3
n += 1
def sum(array):
total = 0
for item in array:
total += item
yield total
def sum_cubes_lt(n):
for i, sum in enumerate(sum(cubes()):
if sum > n:
return i
# prints '3'
print sum_cubes_lt(99)

Related

Is there a way to make this reverse factorial code run more efficiently

I am just starting to learn python and made a program where it calculates the factorial number based on the factorial.
For example if I give the program the number 120 it will tell me it's factorial is 5
anyways my question is how can I make this code more efficient and faster.
Num = int(input())
i=0
for i in range(0,Num):
i = i + 1
x = Num/i
Num = x
if (x==1):
print(i)
Multiplications are much faster than divisions. You should try to reach the number with a factorial instead of dividing it iteratively:
def unfactorial(n):
f,i = 1,1
while f < n:
i += 1
f *= i
return i if f == n else None
unfactorial(120) # 5
A few things you can do:
Num = int(input())
i=0 # your for loop will initialize i, you don't need to do this here
for i in range(0,Num):
i = i + 1 # your for loop will increment i, no need to do this either
x = Num/i # you don't need the extra variable 'x' here
Num = x
if (x==1):
print(i)
You can rewrite this to look something like:
for index in range(1, number): # start range at 1
number /= index # this means; number = number / index
if number==1:
return index
Compute the factorials in ascending order until you reach (or exceed) the factorial you are looking for, using the previous factorial to efficiently compute the next.
def reverse_factorial(num):
i = 1
while num > 1:
i += 1
num /= i
return i
print(reverse_factorial(int(input())))

Is it possible to have a recursive solution for this Divide and Conquer problem?

I have written a code which simulate a lottery by calculating, amongst a list of intervals of consecutive integers, the sum of the number of intervals in which a given number is present. Since this can be described as a "Divide and Conquer" algorithm, I would like to know if it is possible to draw a recursive solution for it.
def lottery_sort(segments, bets):
segments = [(segments[2*i], segments[2*i + 1])
for i in range(len(segments) // 2)]
s_open = [i[0] for i in segments]
s_open.sort()
s_close = [i[1] for i in segments]
s_close.sort()
bets = sorted([bet for bet in bets])
res = []
count = 0
o = 0
c = 0
size = len(segments)
for bet in bets:
while o < size and s_open[o] <= bet:
o += 1
count += 1
while c < size and s_close[c] < bet:
c += 1
count -= 1
res.append(count)
return res

Sum of N numbers in Fibonacci

I am trying to implement the total sum of N whole numbers in Fibonacci
def fibo(n):
if n<2:
return 1
else:
res = fibo(n-1) + fibo(n-2)
sum = sum + res
return res, sum
n=7
sum = 0
for i in range(1, n):
print(fibo(i))
print("Suma", sum)
#example: if n=7 then print : 1,1,2,3,5,8,13 and sum is 32
The error I have is, when I put sum = sum + res
Doesnt print & run the program
Currently, how could you implement the total sum?
You simply need to calculate sum in the for loop, not in the fibo(n).
Here take a look:
def fibo(n):
if n<2:
return 1
else:
res = fibo(n-1) + fibo(n-2)
return res
n=7
sum = 0
for i in range(0, n):
r = fibo(i)
sum += r
print(r)
print("Suma", sum)
I used r in order to call fibo once in each loop.
Let me first point out that the sum of the first 7 terms of the Fibonacci sequence is not 32. That sum is 33. Now to the problem. Here is how I would solve the problem. I would first define the function that calculates the n th term of the Fibonacci sequence as follows:
def fibo(n):
if n in [1,2]:
return 1
else:
res = fibo(n-1) + fibo(n-2)
return res
Then I would define a function to calculate the sum of the first n terms of the Fibonacci sequence as follows.
def sum_fibo(n):
res = [fibo(i) for i in range(1, n+1)]
print(res)
return sum(res)
So if I do
[In] sum_fibo(7)
I get
[1, 1, 2, 3, 5, 8, 13]
out >>> 33
NOTE: In defining the functions above, I have assumed that the input of the function is always going to be a positive integer though the Fibonacci can be extended to cover all real and complex numbers as shown on this wiki page.
actually i don't think this needs to be that complicated the fibonacci sequence is very interesting in a maltitude of ways for example, if you want the sum up the 7th fibonacci number, then have checked what the 9th fibonacci number - 1 is? Now how do we find the n'th fibonacci number?
p = (1+5**.5)/2
q = (1-5**.5)/2
def fibo(n):
return 1/5**.5*(p**n-q**n)
and now we can can find the sum up to any number in one calculation! for example for 7
fibo(9)- 1
output
33
and what is the actual answer
1+1+2+3+5+8+13=33
summa summarum: the fibonachi number that is two places further down the sequence minus 1 is the sum of the fibonachi numbers up to the number
def sumOfNFibonacciNumbers(n):
# Write your code here
i = 1
sum = 2
fib_list = [0, 1, 1]
if n == 1:
return 0
if n == 2:
return 1
if n == 3:
return 2
for x in range(1,n-2):
m = fib_list[-1] + fib_list[-2]
fib_list.append(m)
sum = sum + m
return sum
result = sumOfNFibonacciNumbers(10)
print(result)
Made some modifications to your code:
def fibo(n):
print(1)
counter = 1
old_num = 0
new_num = 1
sum_fib = 1
while counter < n:
fib = old_num + new_num
print(fib)
if counter < n:
old_num = new_num
new_num = fib
sum_fib = sum_fib + fib
counter = counter + 1
print('sum:' + str(sum_fib))
#fibo(5)
First of all, the line sum = sum + res makes no sense because you never defined sum in the first place.
So, your function should look like
def fibo(n):
if n<2:
return 1
else:
return fibo(n-1) + fibo(n-2)
Second, you can get the sum by simply
sum_ = 0
for i in range(0, n):
sum_ += fibo(i)
Or maybe
sum_ = sum(fibo(i) for i in range(0, n))
Notice that the latter would only work if you have not overridden the built-in function named sum
You are referring the variable sum before assignment.
You may want to use the variable sum inside the for loop and assign the fibo to it.
def fibo(n):
if n<2:
return 1
else:
return fibo(n-1) + fibo(n-2)
n=7
sum = 0
for i in range(1, n):
sum += fibo(i)
print(fibo(i))
print("suma", sum)
Considering the start of the Fibonacci series with 1 rather than 0.
def fib(no_of_elements):
elements, start = [], 1
while start <= no_of_elements:
if start in [1, 2]:
elements.append(1)
elif start >= 3:
elements.append(elements[start-2]+elements[start-3])
start += 1
return elements, sum(elements)
print(fib(8))
Output:
([1, 1, 2, 3, 5, 8, 13, 21], 54)

Down to zero problem - getting time exceeded error

Trying to solve hackerrank problem.
You are given Q queries. Each query consists of a single number N. You can perform 2 operations on N in each move. If N=a×b(a≠1, b≠1), we can change N=max(a,b) or decrease the value of N by 1.
Determine the minimum number of moves required to reduce the value of N to 0.
I have used BFS approach to solve this.
a. Generating all prime numbers using seive
b. using prime numbers I can simply avoid calculating the factors
c. I enqueue -1 along with all the factors to get to zero.
d. I have also used previous results to not enqueue encountered data.
This still is giving me time exceeded. Any idea? Added comments also in the code.
import math
#find out all the prime numbers
primes = [1]*(1000000+1)
primes[0] = 0
primes[1] = 0
for i in range(2, 1000000+1):
if primes[i] == 1:
j = 2
while i*j < 1000000:
primes[i*j] = 0
j += 1
n = int(input())
for i in range(n):
memoize= [-1 for i in range(1000000)]
count = 0
n = int(input())
queue = []
queue.append((n, count))
while len(queue):
data, count = queue.pop(0)
if data <= 1:
count += 1
break
#if it is a prime number then just enqueue -1
if primes[data] == 1 and memoize[data-1] == -1:
queue.append((data-1, count+1))
memoize[data-1] = 1
continue
#enqueue -1 along with all the factors
queue.append((data-1, count+1))
sqr = int(math.sqrt(data))
for i in range(sqr, 1, -1):
if data%i == 0:
div = max(int(data/i), i)
if memoize[div] == -1:
memoize[div] = 1
queue.append((div, count+1))
print(count)
There are two large causes of slowness with this code.
Clearing an array is slower than clearing a set
The first problem is this line:
memoize= [-1 for i in range(1000000)]
this prepares 1 million integers and is executed for each of your 1000 test cases. A faster approach is to simply use a Python set to indicate which values have already been visited.
Unnecessary loop being executed
The second problem is this line:
if primes[data] == 1 and memoize[data-1] == -1:
If you have a prime number, and you have already visited this number, you actually do the slow loop searching for prime factors which will never find any solutions (because it is a prime).
Faster code
In fact, the improvement due to using sets is so much that you don't even need your prime testing code and the following code passes all tests within the time limit:
import math
n = int(input())
for i in range(n):
memoize = set()
count = 0
n = int(input())
queue = []
queue.append((n, count))
while len(queue):
data, count = queue.pop(0)
if data <= 1:
if data==1:
count += 1
break
if data-1 not in memoize:
memoize.add(data-1)
queue.append((data-1, count+1))
sqr = int(math.sqrt(data))
for i in range(sqr, 1, -1):
if data%i == 0:
div = max(int(data/i), i)
if div not in memoize:
memoize.add(div)
queue.append((div, count+1))
print(count)
Alternatively, there's a O(n*sqrt(n)) time and O(n) space complexity solution that passes all the test cases just fine.
The idea is to cache minimum counts for each non-negative integer number up to 1,000,000 (the maximum possible input number in the question) !!!BEFORE!!! running any query. After doing so, for each query just return a minimum count for a given number stored in the cache. So, retrieving a result will have O(1) time complexity per query.
To find minimal counts for each number (let's call it down2ZeroCounts), we should consider several cases:
0 and 1 have 0 and 1 minimal counts correspondingly.
Prime number p doesn't have factors other than 1 and itself. Hence, its minimal count is 1 plus a minimal count of p - 1 or more formally down2ZeroCounts[p] = down2ZeroCounts[p - 1] + 1.
For a composite number num it's a bit more complicated. For any pair of factors a > 1,b > 1 such that num = a*b the minimal count of num is either down2ZeroCounts[a] + 1 or down2ZeroCounts[b] + 1 or down2ZeroCounts[num - 1] + 1.
So, we can gradually build minimal counts for each number in ascending order. Calculating a minimal count of each consequent number will be based on optimal counts for lower numbers and so in the end a list of optimal counts will be built.
To better understand the approach please check the code:
from __future__ import print_function
import os
import sys
maxNumber = 1000000
down2ZeroCounts = [None] * 1000001
def cacheDown2ZeroCounts():
down2ZeroCounts[0] = 0
down2ZeroCounts[1] = 1
currentNum = 2
while currentNum <= maxNumber:
if down2ZeroCounts[currentNum] is None:
down2ZeroCounts[currentNum] = down2ZeroCounts[currentNum - 1] + 1
else:
down2ZeroCounts[currentNum] = min(down2ZeroCounts[currentNum - 1] + 1, down2ZeroCounts[currentNum])
for i in xrange(2, currentNum + 1):
product = i * currentNum
if product > maxNumber:
break
elif down2ZeroCounts[product] is not None:
down2ZeroCounts[product] = min(down2ZeroCounts[product], down2ZeroCounts[currentNum] + 1)
else:
down2ZeroCounts[product] = down2ZeroCounts[currentNum] + 1
currentNum += 1
def downToZero(n):
return down2ZeroCounts[n]
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
q = int(raw_input())
cacheDown2ZeroCounts()
for q_itr in xrange(q):
n = int(raw_input())
result = downToZero(n)
fptr.write(str(result) + '\n')
fptr.close()

Euler Project No. 2 with Python

Can somebody tell me why this should be wrong?
#Each new term in the Fibonacci sequence is generated
#by adding the previous two terms. By starting with 1 and 2,
#the first 10 terms will be:
#1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
#Find the sum of all the even-valued terms in the sequence
#which do not exceed four million.
sum=2
list = [1,2]
for x in range(2,100):
a = list[x-2]+list[x-1]
print(a)
list.append(a)
if a % 2 == 0:
sum += a
print('sum', sum)
if sum >= 4000000:
break
Here's a completely different way to solve the problem using a generator and itertools:
def fib():
a = b = 1
while 1:
yield a
a, b = b, a + b
import itertools
print sum(n for n in itertools.takewhile(
lambda x: x <= 4000000, fib()) if n % 2 == 0)
Output:
4613732
So your code, even though it is wrong (see other answers), happens to give the correct answer.
replace
sum += a
print('sum', sum)
if sum >= 4000000:
break
with
if a > 4000000:
break
sum += a
print('sum', sum)
You should compare "a" with 4000000, not "sum", like Daniel Roseman said.
The question asked for the sum of even terms which do not exceed four million. You're checking if the sum doesn't exceed 4m.
I'm trying to solve the same problem - although I understand the logic to do it, I don't understand why this works (outputs the right sum)
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
l.append(n)
print n
And then then moment I put in the modulo function, it doesn't output anything at all anymore.
limit = 4000000
s = 0
l = [1,2]
while l[-1]<limit:
n = l[-1]+l[-2]
if n % 2 == 0 :
l.append(n)
print n
I'm sure this is fairly simple...thanks!
This is the code I used. It is very helpful and teaches you about generators.
def fib():
x,y = 0,1
while True:
yield x
x,y = y, x+y
def even(seq):
for number in seq:
if not number % 2:
yield number
def under_a_million(seq):
for number in seq:
if number > 4000000:
break
yield number
print sum(even(under_a_million(fib())))
-M1K3
Keep it simple and it should take you less than 0.1 seconds.
from datetime import datetime
x, y = 1, 1
total = 0
for i in xrange (1, 100):
x = x + y
if x % 2 == 0 and x <= 4000000:
total += x
y = y + x
if y % 2 == 0 and x <= 4000000:
total += y
print total
starttime = datetime.now()
print datetime.now() - starttime

Categories