Python Project Euler digit fifth powers - python

Here is the problem:
Surprisingly there are only three numbers that can be written as the
sum of fourth powers of their digits:
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
As 1 = 1^4 is not a sum it is not included.
The sum of these numbers is 1634 + 8208 + 9474 = 19316.
Find the sum of all the numbers that can be written as the sum of
fifth powers of their digits.
And here is my code:
summ = 0
digit_sum = 0
i = 0
while i < 1000000:
j = list(str(i))
for x in j:
digit = int(x) ** 5
digit_sum += digit
if digit_sum == i:
summ += i
print(i)
else:
digit_sum = 0
i += 1
print(summ)
Can anyone find out that why I miss a value 4151 which should be one of the correct answer?

The problem in your code is you forgot to reset the digit_sum when you got an answer.
Put digit_sum = 0 before j = list(str(i)). You also start with i = 0. I suggest to start with i = 10 since the first 2 digit number is 10.
use this:
[i for i in range(10, 1000000) if i == sum(int(d) ** 5 for d in str(i))]
equivalent with:
[4150, 4151, 54748, 92727, 93084, 194979]
using sum:
sum(i for i in range(10, 1000000) if i == sum(int(d) ** 5 for d in str(i)))
equivalent with:
443839

4150 is also in solutions. The digit_sum is not set to 0 before 4151 step. You should set digit_sum = 0 in each step.
summ = 0
i = 10
while i < 1000000:
digit_sum = 0
j = list(str(i))
for x in j:
digit = int(x) ** 5
digit_sum += digit
if digit_sum == i:
summ += i
print(i)
i += 1
print(summ)

The answer to your question is that you don't reset digit_sum every time, only when digit_sum != i. If you remove the else statement, it should work correctly.
if digit_sum == i:
summ += i
print(i)
digit_sum = 0
i += 1

Related

Excluding a digit in a for loop

Hi I would like to exclude any number that contains a 7 from the range of 1-1000 in my for loop.
This is the code I have so far
sum = 0
for i in range(1,1001):
if #digit contains a 7:
continue
sum = sum + 1/i
return sum
Here's one way to do it by isolating each of the 3 possible digits in your range:
sum = 0
for i in range(1,1001):
if 7 not in (i-10*(i//10), i//10-10*(i//100), i//100-10*(i//1000)):
sum = sum + 1/i
print(sum)
Output:
6.484924087833117
UPDATE: To generalize for an arbitrary top number other than 1001, you could do this:
sum = 0
top = 1001
tens, temp = [1], 1001
while temp > 0:
tens.append(tens[-1] * 10)
temp //= 10
for i in range(1,top):
digits = [i // tens[j] - 10 * (i // tens[j + 1]) for j in range(len(tens) - 1)]
if 7 not in digits:
sum = sum + 1/i
print(sum)
As suggested in comments by #Lukas Schmid, this also works and may be preferable (it's certainly easier to read):
sum = 0
top = 1001
tens, temp = [1], 1001
while temp > 0:
tens.append(tens[-1] * 10)
temp //= 10
for i in range(1,top):
digits = [i // tens[j] % 10 for j in range(len(tens) - 1)]
if 7 not in digits:
sum = sum + 1/i
print(sum)
One of the simplest way to achieve that without using lots of maths, is to treat the number as a string and compare it to the char '7':
sum = 0
for i in range(1, 1000):
if '7' in str(i):
continue
sum += 1/i
return sum
Also, note that the return statment should be outside the for loop.

if condition is not working - python program

I want to write progarm, The function accepts two integers n, m as arguments Find the sum of all numbers in range from 1 to m(both inclusive) that are not divisible by n. Return difference between sum of integers not divisible by n with the sum of numbers divisible by n.
In my case, if is not working.
n = int(input("num "))
m = int(input("limit "))
for i in range(1, m+1):
sum1 = 0
sum2 = 0
if i % n == 0:
sum1 += i
else:
sum2 += i
print(f"{sum1} and {sum2}")
print(abs(sum2-sum1))
Take sum1 = 0 and sum2 = 0 outside the for loop; currently you are resetting those values at each iteration, so that it does not keep the sum.
n, m = 2, 10
sum1 = 0
sum2 = 0
for i in range(1, m+1):
if i % n == 0:
sum1 += i
else:
sum2 += i
print(f"{sum1} and {sum2}")
print(abs(sum2-sum1))
Output:
30 and 25
5
Bring your sum1 and sum2 outside of the loop, you're resetting them every time
not_n = []
with_n = []
def inputts(n, m):
# code
for x in range(1, m+1):
if x % n == 0:
with_n.append(x)
else:
not_n.append(x)
# now sum
nott_n = sum(not_n)
withh_n = sum(with_n)
#now substraction
subb=(withh_n-nott_n)
print(abs(subb))
inputts(5,100)

Optimizing the algorithm for brute force numbers in the problem

How many pairs (i, j) exist such that 1 <= i <= j <= n, j - i <= a?
'n' and 'a' input numbers.
The problem is my algorithm is too slow when increasing 'n' or 'a'.
I cannot think of a correct algorithm.
Execution time must be less than 10 seconds.
Tests:
n = 3
a = 1
Number of pairs = 5
n = 5
a = 4
Number of pairs = 15
n = 10
a = 5
Number of pairs = 45
n = 100
a = 0
Number of pairs = 100
n = 1000000
a = 333333
Number of pairs = 277778388889
n = 100000
a = 555555
Number of pairs = 5000050000
n = 1000000
a = 1000000
Number of pairs = 500000500000
n = 998999
a = 400000
Number of pairs = 319600398999
n = 898982
a = 40000
Number of pairs = 35160158982
n, a = input().split()
i = 1
j = 1
answer = 0
while True:
if n >= j:
if a >= (j-i):
answer += 1
j += 1
else:
i += 1
j = i
if j > n:
break
else:
i += 1
j = i
if j > n:
break
print(answer)
One can derive a direct formula to solve this problem.
ans = ((a+1)*a)/2 + (a+1) + (a+1)*(n-a-1)
Thus the time complexity is O(1). This is the fastest way to solve this problem.
Derivation:
The first a number can have pairs of (a+1)C2 + (a+1).
Every additional number has 'a+1' options to pair with. So, therefore, there are n-a-1 number remaining and have (a+1) options, (a+1)*(n-a-1)
Therefore the final answer is (a+1)C2 + (a+1) + (a+1)*(n-a-1) implies ((a+1)*a)/2 + (a+1) + (a+1)*(n-a-1).
You are using a quadratic algorithm but you should be able to get it to linear (or perhaps even better).
The main problem is to determine how many pairs, given i and j. It is natural to split that off into a function.
A key point is that, for i fixed, the j which go with that i are in the range i to min(n,i+a). This is since j-i <= a is equivalent to j <= i+a.
There are min(n,i+a) - i + 1 valid j for a given i. This leads to:
def count_pairs(n,a):
return sum(min(n,i+a) - i + 1 for i in range(1,n+1))
count_pairs(898982,40000) evaluates to 35160158982 in about a second. If that is still to slow, do some more mathematical analysis.
Here is an improvement:
n, a = map(int, input().split())
i = 1
j = 1
answer = 0
while True:
if n >= j <= a + i:
answer += 1
j += 1
continue
i = j = i + 1
if j > n:
break
print(answer)

Sum of multiples of 3 and 5

I have to calculate the sum of all the multiples of 3 and 5 (including themselves) in a range of a given N number (N excluded). I created a python code and it works with N = 10 but doesn't work for N = 100. I don't understand why.
This is the code:
#!/bin/python3
import sys
def multiples_sum(n):
sum1 = 0
for i in range(n):
if i % 3 == 0:
sum1 = sum1 + i
if i % 5 == 0:
sum1 = sum1 + i
return sum1
t = int(input().strip())
for a0 in range(t):
n = int(input().strip())
print(multiples_sum(n))
you are counting the multiples of 15 (= 3 * 5) twice.
your code should be
for i in range(n):
if i % 3 == 0:
sum1 += i
elif i % 5 == 0:
sum1 += i
note the elif instead of if.
alternatively:
for i in range(n):
if i % 3 == 0 or i % 5 == 0:
sum1 += i
or directly (as DeepSpace suggests in the comments)
sum1 = sum(i for i in range(n) if 0 in {i % 3, i % 5})
note that there is no need for looping at all: knowing that the sum of the integers from 1 to (and including) n is
def sum_to(n):
return ((n+1)*n)//2
you can get your number from:
sum1 = 5 * sum_to((n-1)//5) + 3 * sum_to((n-1)//3) - 15 * sum_to((n-1)//15)
(that could be generalized and made somewhat prettier... but i'm sure you get the idea in this form).
EDIT:
In the meantime I saw #DeepSpace's solution in the comments, particularly the one with the if 0 in {i % 3, i % 5})-check - which I definitely admire; this is really smart!
I think I'd go this way, if you're interested in a different approach:
N = 100
sum(set(list(range(0, N, 3)) + list(range(0, N, 5))))
# 2318
Because 10 is less than 15, which is the least common multiple of 3 and 5.
You need to treat the particular case of 15.

complicated variable assignment

I usually do my incrementation this way:
n=0
n=n+1 # and never do n+=1
Now there is code that I am trying to comprehend and I'm struggling to understand it.
sum=0
temp = num
while temp > 0:
digit = temp % 10
# below is the line I do not understand
sum += digit ** power # what is happening here?. with power= len(str(num))
temp //= 10
if num == sum:
print num
This snippet is a piece to list the armstrong numbers.
In python ** is the sign for exponent, so x ** 2 is x^2 (or x squared).
x += g is the same as x = x + g
sum += digit ** power == sum = sum + (digit ** power)
while temp > 0:
digit = temp % 10
sum += digit ** power
temp //= 10
Take the last digit of temp
Add to sum the digit to the power of power
Delete the last digit of temp
suppose num = 34, then power becomes 2, so, for first iteration:
digit = 4
sum = 0 + 4 ** 2 # which is 0 + 16 = 16. Then adding to sum
so, digit ** power is digit to the power of 2
similarly, for second iteration:
digit = 3
sum = 16 + 3 ** 2 # which is 16 + 9 = 25

Categories

Resources