Python-Finding the amount of neighbours given a list - python

Problem statment
On the number line there are N houses (There can be more houses in 1 number). Two houses are said to be neighbours if the distance between them is less than some give D. (the distance between 2 houses which have the same number is one )
Find the number of all neighbours.
Mathematicaly the problem boils down to this. Given a multiset N and a number D
Find the number of houses where the distance between them is less than D
def main():
number_of_ppl,distance=map(int, input().split())
inputs=map(int,input().split())
numbers=sorted(inputs)
counter=0
sum=0
for x in range(0,len(numbers)):
for y in range(i+1,len(numbers)):
if abs(numbers[x]-numbers[y])<=distance:
counter +=1
else:
break
sum+=counter
counter=0
print(sum)
main()
This code works however it fails at 3 of the 8 test cases due to ineficient time. Is there something I am missing ?
How could I make this algorithem faster?
I tried using dictionaries but got the same result
P.S If it helps I can post the test cases where this program fails

Your current code is incomplete, but it seems you are doing 2 loops which if the distance is big enough, takes O(n^2) to run. This can be reduced to O(n log n). Note that when you iterate the numbers in order, when you analize the neighbours of arr[i], when looking at the neighbours of arr[i + 1] they will be the same + maybe some more.
def main():
number_of_ppl,distance=map(int, input().split())
inputs=map(int,input().split())
numbers = sorted(inputs)
sum = 0
pointer = 0
for idx, number in enumerate(numbers):
while pointer < len(numbers) and number + distance >= numbers[pointer]:
pointer += 1
sum += (pointer - idx)
print(sum)
main()

Related

Adding a 0 to the list for Project Euler Problem 23 "Non-Abundant Sums" changes the answer

I'm a beginner in programming, and I'm trying to practice Project Euler questions.
Question 23:
A perfect number is a number for which the sum of its proper divisors
is exactly equal to the number. For example, the sum of the proper
divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28
is a perfect number.
A number n is called deficient if the sum of its proper divisors is
less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the
smallest number that can be written as the sum of two abundant numbers
is 24. By mathematical analysis, it can be shown that all integers
greater than 28123 can be written as the sum of two abundant numbers.
However, this upper limit cannot be reduced any further by analysis
even though it is known that the greatest number that cannot be
expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as
the sum of two abundant numbers.
I got the correct answer by the following code:
list1=[]
list2=[]
for num in range(1,28123):
list1.append(num)
for num in list1:
sum1=1
for i in range (2,int(num**0.5)+1):
if not num%i:
sum1+=(i+(num/i))
if int(num**0.5)==(num**0.5):
sum1-=(num**0.5)
if sum1>num:
list2.append(num)
for i in range(len(list2)):
for j in range(i,len(list2)):
check=list2[i]+list2[j]
if check<28123:
list1[check-1]=0
print(sum(list1))
I tried to make a small modification to this code, by changing the definition of list1 by adding a '0' by the following code:
list1=[x for x in range (28123)]
list2=[]
for num in list1:
sum1=1
for factor in range (2,int(num**0.5)+1):
if not num%factor:
sum1+=(factor+(num/factor))
if int(num**0.5)==(num**0.5):
sum1-=(num**0.5)
if sum1>num:
list2.append(num)
for i in range(len(list2)):
for j in range(i,len(list2)):
check=list2[i]+list2[j]
if check<28123:
list1[check]=0
print(sum(list1))
As you can see, I also changed the second last line according the new indexes. But this changed my answer from 4179871 to 4178876. I can't understand why. The former is the correct answer.
I know my code is not very efficient as I'm a beginner, trying to improve. Help will be much appreciated!
Edit:
I tried to check if 0 is getting added into the abundant number's list2, but the following code gave me [] as an output, hence it wasn't.
num = 0
list2 = []
sum1 = 1
for i in range (2, int (num ** 0.5) + 1):
if not num % i:
sum1 += (i+ (num / i))
if int (num ** 0.5) == (num ** 0.5):
sum1 -= (num ** 0.5)
if sum1 > num:
list2.append(num)
print(list2)
You inserted 0; your code recognizes this as an abundant number.
Therefore, any abundant number that was previously not the sum of two others ... is suddenly the sum of itself and 0. It's excluded from the list.
I strongly recommend that you learn to perform basic logical debugging. I determined this with a simple insertion. I pasted both of your algorithms into a file. In between, I saved the results of the first algorithm:
...
print(sum(list1))
keep1 = list1
keep2 = list2
Then, after the second algorithm, I simply found the differences between the lists you formed in the two algorithms:
print("acquired abundant numbers", set(list2) - set(keep2))
print("lost summed numbers", set(keep1) - set(list1))
Output:
4179871
4178876
acquired abundant numbers {0}
lost summed numbers {945, 18, 12, 20}
... and there is the telling evidence: three numbers less than 24, which is stated as the lowest number qualifying for the summation. Each of these is abundant, and the first added output line shows that your code mis-allocated 0 as abundant.
This is one of the most basic debugging techniques: when you have a solid difference in expected and actual output, print or otherwise compare the intermediate values to find the point of difference.
You note that I'm not tracking this into your code: you didn't make it easy to read. See the PEP-8 guidelines for suggestions.

Python: Palindrome Integer Composition

This challenge is for codewars:
Given an input n, find the count of all the numbers less than n that are both palindromic and can be written as the sum of consecutive squares.
My idea was to compute the square of incrementing numbers, add the square to the total of previous squares, and test if the total, together with the total minus all previous totals (kept in a list), are palindromes. When the total equals or exceeds n, totals are removed from the beginning of the list until the current total minus the list element is less than n, and the square incrementing is resumed until there is only 1 element remaining in the list.
def values(n):
def isPal(n):
n = str(n)
if len(n) in [0,1]:
return True
return n[0] == n[-1] and isPal(n[1:-1])
pcount = 0
current = 2
totals = [1]
while True:
tot = current**2 + totals[-1]
totals = [e for e in totals if tot - e < n]
if len(totals) == 1 and totals != [1]:
break
for e in totals[:-1]:
if isPal(tot - e):
pcount += 1
if isPal(tot):
pcount+=1
totals.append(tot)
current += 1
return pcount
My code returns the correct result for n = 100, 200, 300, 400, 1000. For larger n, however, my result is off, mostly by +1, but sometimes +2. I tried substituting a palindrome finder that uses logs rather than converting into a string, but my results are still wrong for larger n.
I know there are other posts on this problem with solutions using Counter and other methods. I'm interested in learning why my code is buggy.
Cheers.
Ahah, spotted it. Some values can be made in more than one way. 554455 is the smallest value with this property, which is why your functions goes over on big numbers. Rather than having a counter, just make a set to hold all answers found, and return the length of that set.
You're doing good coding - so keep going Mikey!
I hope you got your answer. For performance reasons, I would change the isPal function as below:
def isPal(n):
n = str(n)
return n == n[::-1]
Good solution tho!

Number of multiples less than the max number

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

Project Euler #25: Keep getting Overflow error (result to large) - is it to do with calculating fibonacci number?

I'm working on solving the Project Euler problem 25:
What is the first term in the Fibonacci sequence to contain 1000
digits?
My piece of code works for smaller digits, but when I try a 1000 digits, i get the error:
OverflowError: (34, 'Result too large')
I'm thinking it may be on how I compute the fibonacci numbers, but i've tried several different methods, yet i get the same error.
Here's my code:
'''
What is the first term in the Fibonacci sequence to contain 1000 digits
'''
def fibonacci(n):
phi = (1 + pow(5, 0.5))/2 #Golden Ratio
return int((pow(phi, n) - pow(-phi, -n))/pow(5, 0.5)) #Formula: http://bit.ly/qDumIg
n = 0
while len(str(fibonacci(n))) < 1000:
n += 1
print n
Do you know what may the cause of this problem and how i could alter my code avoid this problem?
Thanks in advance.
The problem here is that only integers in Python have unlimited length, floating point values are still calculated using normal IEEE types which has a maximum precision.
As such, since you're using an approximation, using floating point calculations, you will get that problem eventually.
Instead, try calculating the Fibonacci sequence the normal way, one number (of the sequence) at a time, until you get to 1000 digits.
ie. calculate 1, 1, 2, 3, 5, 8, 13, 21, 34, etc.
By "normal way" I mean this:
/ 1 , n < 3
Fib(n) = |
\ Fib(n-2) + Fib(n-1) , n >= 3
Note that the "obvious" approach given the above formulas is wrong for this particular problem, so I'll post the code for the wrong approach just to make sure you don't waste time on that:
def fib(n):
if n <= 3:
return 1
else:
return fib(n-2) + fib(n-1)
n = 1
while True:
f = fib(n)
if len(str(f)) >= 1000:
print("#%d: %d" % (n, f))
exit()
n += 1
On my machine, the above code starts going really slow at around the 30th fibonacci number, which is still only 6 digits long.
I modified the above recursive approach to output the number of calls to the fib function for each number, and here are some values:
#1: 1
#10: 67
#20: 8361
#30: 1028457
#40: 126491971
I can reveal that the first Fibonacci number with 1000 digits or more is the 4782th number in the sequence (unless I miscalculated), and so the number of calls to the fib function in a recursive approach will be this number:
1322674645678488041058897524122997677251644370815418243017081997189365809170617080397240798694660940801306561333081985620826547131665853835988797427277436460008943552826302292637818371178869541946923675172160637882073812751617637975578859252434733232523159781720738111111789465039097802080315208597093485915332193691618926042255999185137115272769380924184682248184802491822233335279409301171526953109189313629293841597087510083986945111011402314286581478579689377521790151499066261906574161869200410684653808796432685809284286820053164879192557959922333112075826828349513158137604336674826721837135875890203904247933489561158950800113876836884059588285713810502973052057892127879455668391150708346800909439629659013173202984026200937561704281672042219641720514989818775239313026728787980474579564685426847905299010548673623281580547481750413205269166454195584292461766536845931986460985315260676689935535552432994592033224633385680958613360375475217820675316245314150525244440638913595353267694721961
And that is just for the 4782th number. The actual value is the sum of all those values for all the fibonacci numbers from 1 up to 4782. There is no way this will ever complete.
In fact, if we would give the code 1 year of running time (simplified as 365 days), and assuming that the machine could make 10.000.000.000 calls every second, the algorithm would get as far as to the 83rd number, which is still only 18 digits long.
Actually, althought the advice given above to avoid floating-point numbers is generally good advice for Project Euler problems, in this case it is incorrect. Fibonacci numbers can be computed by the formula F_n = phi^n / sqrt(5), so that the first fibonacci number greater than a thousand digits can be computed as 10^999 < phi^n / sqrt(5). Taking the logarithm to base ten of both sides -- recall that sqrt(5) is the same as 5^(1/2) -- gives 999 < n log_10(phi) - 1/2 log_10(5), and solving for n gives (999 + 1/2 log_10(5)) / log_10(phi) < n. The left-hand side of that equation evaluates to 4781.85927, so the smallest n that gives a thousand digits is 4782.
You can use the sliding window trick to compute the terms of the Fibonacci sequence iteratively, rather than using the closed form (or doing it recursively as it's normally defined).
The Python version for finding fib(n) is as follows:
def fib(n):
a = 1
b = 1
for i in range(2, n):
b = a + b
a = b - a
return b
This works when F(1) is defined as 1, as it is in Project Euler 25.
I won't give the exact solution to the problem here, but the code above can be reworked so it keeps track of n until a sentry value (10**999) is reached.
An iterative solution such as this one has no trouble executing. I get the answer in less than a second.
def fibonacci():
current = 0
previous = 1
while True:
temp = current
current = current + previous
previous = temp
yield current
def main():
for index, element in enumerate(fibonacci()):
if len(str(element)) >= 1000:
answer = index + 1 #starts from 0
break
print(answer)
import math as m
import time
start = time.time()
fib0 = 0
fib1 = 1
n = 0
k = 0
count = 1
while k<1000 :
n = fib0 + fib1
k = int(m.log10(n))+1
fib0 = fib1
fib1 = n
count += 1
print n
print count
print time.time()-start
takes 0.005388 s on my pc. did nothing fancy just followed simple code.
Iteration will always be better. Recursion was taking to long for me as well.
Also used a math function for calculating the number of digits in a number instead of taking the number in a list and iterating through it. Saves a lot of time
Here is my very simple solution
list = [1,1,2]
for i in range(2,5000):
if len(str(list[i]+list[i-1])) == 1000:
print (i + 2)
break
else:
list.append(list[i]+list[i-1])
This is sort of a "rogue" way of doing it, but if you change the 1000 to any number except one, it gets it right.
You can use the datatype Decimal. This is a little bit slower but you will be able to have arbitrary precision.
So your code:
'''
What is the first term in the Fibonacci sequence to contain 1000 digits
'''
from Decimal import *
def fibonacci(n):
phi = (Decimal(1) + pow(Decimal(5), Decimal(0.5))) / 2 #Golden Ratio
return int((pow(phi, Decimal(n))) - pow(-phi, Decimal(-n)))/pow(Decimal(5), Decimal(0.5)))
n = 0
while len(str(fibonacci(n))) < 1000:
n += 1
print n

Help adding the Prime Number Hypothesis by C.F. Gauss to my Sieve of Eratosthenes

Hey all!
So I'm almost done with a problem that I started working on for school that deals with the Sieve of Eratosthenes. I managed to get the program to print out all the prime numbers from 2 to the square root of 1000. However, my teacher is asking me to use the Prime Number Hypothesis (?) by C.F. Gauss. This is what he says:
C. F. Gauss hypothesized that (N) the number of primes less than or equal to N is defined
as (N) = N/loge(N) as N approaches infinity. This was called the prime number
hypothesis. In a for loop print the prime numbers, a counter indicating its ordinal
number (1, 2, 3, etc.) and the value of (N).
I tried making another for loop, and printing the prime numbers but it's just not working for me! :( ugh.
Any help would be greatly appreciated! :)
import math
def sieves(N):
x = 1000*[0]
prime = 2
print('2')
i = 3
while (i <= N):
if i not in x:
print(i)
prime += 1
j = i
while (j <= (N / i)):
x.append(i * j)
j += 1
i += 2
print("\n")
def main():
count = 0
for i in range (1000):
count = count + 1
print(sieves(math.sqrt(1000)))
main()
The problem seems to be in the line j=i. You want to start j = 1 so that you catch all multiples of i and add them to your "x" list of non-prime elements. If you start j = i you will miss some. And when you test for "i not in x" it will evaluate to true for some non-primes.
Also instead of x.append(i*j) you probably meant x[i*j] = 1 (i.e. set to 1 means i*j == not prime)
With that modification "i not in x" can be optimized to "x[i] == 0", no reason to search the entire array. This would be a lot more efficient than keeping a sparse array "x" and having to search it's elements every step in the loop.

Categories