I have been working on the Bonetrousle problem in hacker rank using python. After many hours the below code passes all the test cases except one where it times out. Any suggestions on how I can make the code quicker would be appreciated. I believe the problem is the code that deals with the remainder, I put comments below and above it so it is easy to find. Unfortunately I am at a loss on how to refactor it so it works faster.
The code I wrote gets the right answer for all test cases, I have verified this in pycharm. The only problem is that it is to slow for one of the hacker rank test cases.
Here is the link to the problem https://www.hackerrank.com/challenges/bonetrousle
Here is a link to the test case it fails
https://hr-testcases-us-east-1.s3.amazonaws.com/21649/input12.txt?AWSAccessKeyId=AKIAJAMR4KJHHUS76CYQ&Expires=1473987910&Signature=xaHGvYRVmUVJHh4r3on%2BWgoIsjs%3D&response-content-type=text%2Fplain
firstLine = int(input())
for a in range(0, firstLine):
nums = input()
numsArr = list(map(int, nums.split(" ")))
n = numsArr[0]
k = numsArr[1]
b = numsArr[2]
num1 = 0
rem = 0
answer = True
remAdded = False
count = 0
boxArr = []
for i in range(1, b+1):
count += i
boxArr.append(i)
num1 = (n - count)//b
rem = (n - count)%b
for j in range(0, len(boxArr)):
boxArr[j] = boxArr[j] + num1
if boxArr[j] > k:
answer = False
# In below code -> if there is a remainder I am adding it to an element in the array that has box numbers
# I check to see if I can add the remainder to an element in the array
#without that element exceeding k, the number of sticks. If I can't then the bool remAdded doesn't get set to True
# The below code works but it seems inefficient and looks like the problem
if rem == 0:
remAdded = True
elif answer != False:
for r in range(len(boxArr) - 1, 0, -1):
if boxArr[r] + rem <= k and r == len(boxArr) - 1:
boxArr[r] = boxArr[r] + rem
remAdded = True
break
else:
if boxArr[r] + rem <= k and (boxArr[r] + rem) not in boxArr:
boxArr[r] = boxArr[r] + rem
remAdded = True
break
# above is code for dealing with remainder. Might be the problem
if answer == False or remAdded == False:
print(-1)
elif 0 in boxArr:
print(-1)
else:
for z in range(0, len(boxArr)):
if z != len(boxArr) - 1:
print(boxArr[z], end =" ")
else:
print(boxArr[z])
Replace the code between your comments by:
if rem == 0:
remAdded = True
elif boxArr[-1] + 1 > k:
remAdded = False
elif answer != False:
l = len(boxArr)-1
for r in range(l, l-rem, -1):
boxArr[r] += 1
remAdded = True
This gets rid of the expensive (boxArr[r] + rem) not in boxArr, basically. It passes all test cases for me.
Related
def isPerfectSquare(n) :
i = 1
while(i * i<= n):
if ((n % i == 0) and (n / i == i)):
return True
i = i + 1
return False
lst=[]
n=int(input())
for i in range(0,n):
ele=int(input("Enter: "))
lst.append(ele)
for i in lst:
isPerfectSquare(i)
if (isPerfectSquare(n)):
print("Perf")
else:
print("Not")
I am a new python programmer so I am trying out different low levelled problems with a twist. I tried with for loops first but couldn't figure out how to do it with multiple inputs.
Where did I go wrong? When I input a perfect square, it's not working.
Issue is if (isPerfectSquare(n)): you were always just passing in the input and checking if that is a Perfect Square. You should be passing in each element of the list instead like this if isPerfectSquare(i):
def isPerfectSquare(n):
i = 1
while i * i <= n:
if (n % i == 0) and (n / i == i):
return True
i = i + 1
return False
lst = []
n = int(input())
for i in range(0, n):
ele = int(input("Enter: "))
lst.append(ele)
for i in lst:
if isPerfectSquare(i):
print("Perf")
else:
print("Not")
Output:
3
Enter: 1
Enter: 4
Enter: 10
Perf
Perf
Not
I'm a new at programming, I like solving this euler questions and I know there are solutions for this problem but it's not about the problem at all actually.
So, i managed to create a working function for finding example: 33. triangular number. It works but i couldn't manage to properly desing my while loop. I wanted to make it like, it starts from first triangular checks it's divisors make list of it's divisors, checks the length of the divisors, because problem wants "What is the value of the first triangle number to have over five hundred divisors?" . But i never managed to work the while loop. Thank you for reading.
nums = [1]
triangles = [1]
divisors = []
def triangularcreator(x):
if x == 1:
return 1
n = 1
sum = 0
while n!=0:
n += 1
nums.append(n)
for i in range(len(nums)):
sum += nums[i]
triangles.append(sum)
sum = 0
if x == len(triangles):
n = 0
return triangles[-1]
counter = 1
while True:
for i in range(1, triangularcreator(counter) + 1):
if triangularcreator(counter) % i == 0:
divisors.append(i)
if len(divisors) == 500:
print(triangularcreator(counter))
break
counter +=1
divisors.clear()
You should try to change a few things, starting with calculating just once the value of triangularcreator(counter) and assigning this value to a variable that you can use in different points of your code.
Second, you create a loop which will be calculate always triangularcreator(1). At the end of each iteration you increase the value of counter+=1, but then at the beginign of the new iteration you assignt it again value 1, so it will not progress as you expect. Try this few things:
counter = 1
while True:
triangle = triangularcreator(counter)
for i in range(1, triangle + 1):
if triangle % i == 0:
divisors.append(i)
if len(divisors) == 500:
print(triangle )
break
counter +=1
Also these two arrays nums = [1], triangles = [1] should be declared and initialized inside the def triangularcreator. Otherwise you would be appending elements in each iteration
Edit: I believe it is better to give you my own answer to the problem, since you are doing some expensive operations which will make code to run for a long time. Try this solution:
import numpy as np
factor_num = 0
n = 0
def factors(n):
cnt = 0
# You dont need to iterate through all the numbers from 1 to n
# Just to the sqrt, and multiply by two.
for i in range(1,int(np.sqrt(n)+1)):
if n % i == 0:
cnt += 1
# If n is perfect square, it will exist a middle number
if (np.sqrt(n)).is_integer():
return (cnt*2)-1
else:
return (cnt*2)-1
while factor_num < 500:
# Here you generate the triangle, by summing all elements from 1 to n
triangle = sum(list(range(n)))
# Here you calculate the number of factors of the triangle
factor_num = factors(triangle)
n += 1
print(triangle)
Turns out that both of your while loop are infinite either in triangularcreatorin the other while loop:
nums = [1]
triangles = [1]
divisors = []
def triangularcreator(x):
if x == 1:
return 1
n = 1
sum = 0
while n:
n += 1
nums.append(n)
for i in range(len(nums)):
sum += nums[i]
triangles.append(sum)
sum = 0
if len(triangles) >= x:
return triangles[-1]
return triangles[-1]
counter = 1
while True:
check = triangularcreator(counter)
for i in range(1, check + 1):
if check % i == 0:
divisors.append(i)
if len(divisors) >= 500:
tr = triangularcreator(counter)
print(tr)
break
counter +=1
Solution
Disclaimer: This is not my solution but is #TamoghnaChowdhury, as it seems the most clean one in the web. I wanted to solve it my self but really run out of time today!
import math
def count_factors(num):
# One and itself are included now
count = 2
for i in range(2, int(math.sqrt(num)) + 1):
if num % i == 0:
count += 2
return count
def triangle_number(num):
return (num * (num + 1) // 2)
def divisors_of_triangle_number(num):
if num % 2 == 0:
return count_factors(num // 2) * count_factors(num + 1)
else:
return count_factors((num + 1) // 2) * count_factors(num)
def factors_greater_than_triangular_number(n):
x = n
while divisors_of_triangle_number(x) <= n:
x += 1
return triangle_number(x)
print('The answer is', factors_greater_than_triangular_number(500))
So I am new to programming in python(and in general) and was doing some coding challenges. I came across this 'prime numbers using the sieve method' challenge. I have successfully managed to attempt it however I feel like my logic needs improvement.
So what I did was use 3 while loops in python, the code works as intended, gives me a set of prime numbers however I cannot find a way to condense it.
import sys
n = int(sys.argv[1])
ls = []
i = 2
while i <= n:
ls.append(i)
i += 1
i = 0
while i < len(ls):
if i == 0:
pass
else:
ls[i] = ''
i += 2
i = 1
while i < len(ls):
if i == 1:
pass
else:
ls[i] = ''
i += 3
i = 0
while i < len(ls):
if i == 0:
pass
else:
ls[i] = ''
i += 5
i = 0
primes = []
while i < len(ls):
if ls[i] != '':
primes.append(ls[i])
i += 1
for prime in primes:
print(prime,end=', ')
As the ceo of nvidia once said, 'it just works' but clearly not in the best way :D
Your code thinks 49 is prime, which is not awesome. Making a while loop for each prime just doesn't work.
Here's a simple version that does:
import math
def primesLessThan(N):
seive = [True] * N
seive[0] = seive[1] = False
for i in range(2,int(math.sqrt(N))+1):
if (seive[i]): # i is prime
for j in range(2*i,N,i): # all multiples of i >= 2i
seive[j] = False # j is composite since i is a factor
return [p for p in range(2,N) if seive[p]]
print(primesLessThan(500))
I recently started programming Python and was stuck at this particular Project Euler problem for finding the 1001st prime number.
My code:
L = [2]
def is_prime(x,L):
for el in L:
if x%el != 0:
flag = 1
else:
flag = 0
break
if flag == 1:
return True
elif flag == 0:
return False
a = 3
for k in range(1,1002):
if is_prime(a,L) is True:
L.append(a)
a += 1
k += 1
else:
a += 1
print(L)
print(len(L))
This prints the list of prime numbers upto 997 which is the 168th prime number. Can you tell me what am I doing wrong?
Your increment of k is pointless, because you're iterating a fixed range of numbers (k is replaced when the loop loops, the range can't be changed dynamically).
You want a while loop with a manually managed k:
a = 3
k = 1
while k < 1002:
if is_prime(a,L):
L.append(a)
a += 1
k += 1
else:
a += 1
Note: There may be some off-by-one logic errors here, but it expresses what I assume was your intent in the original code, fixing only the issue with managing k.
k += 1
That's where the problem is. Try this code:
for k in range(1, 1002):
print(k)
and then:
for k in range(1, 1002):
k += 1
print(k)
Your Mistake is that you are finding numbers that are prime UP to 1001 and Also variables of a loop cannot increase By the user
to fix that use a while loop
A Program To Find Up Prime's To Any Number would be:
import sys
def prime_num_finder():
i = 2
while True:
try:
p = int(input("Please enter up to what number the prime numbers should be: "))
break
except ValueError:
sys.stderr.write('ERROR\n')
sys.stderr.write(' Try again...\n')
while i != (p + 1):
x = i
if x % 2 and x % 3 and x % 5 and x % 7 > 0.1: # Checks if the remainder is greater than 0.1 to see if it has an remainder
r1 = True
else:
if i == 2 or i == 3 or i == 5 or i == 7:
r1 = True
else:
r1 = False
if r1 == True:
print(i, " is a prime number!")
else:
pass
i = i + 1
prime_num_finder()
quit()
That is a simple program to check if it is divisible by 2 ,3, 5, or 7
I've tried to compare my result to Wolfram Alpha's result by counting primes found.
It seems works well, without error.
But when I submit this solution to SPOJ, it shows the error message "wrong answer".
I also tried to change the final print's end= to '' (blank string), but still got "wrong answer".
Not sure if is there something wrong with my sieve algorithm, or output error.
**edit: link of problem http://www.spoj.pl/problems/PRIME1/
Here is my PRIME1 source code, hope someone can point out my fault. Thanks a lot.
And hope someone can teach me how to write a test to programs like this, I'm still learning, don't know how to do automated tests to programs, but want to learn.
def getPrimeInRange(minNum, maxNum):
#just a variation with skipping step of the Sieve of E's
processingRange = list(range(minNum, maxNum+1))
#prefix, due to 1 is not a prime
if minNum == 1:
processingRange[0] = 0
sqrtOfMaxNum = int(maxNum ** 0.5) + 1
primesUnderSqrt = list(range(sqrtOfMaxNum))
#prefix, due to 1 is not a prime
primesUnderSqrt[1] = 0
#my strategy is flip all numbers that is not a prime to zero, which equals to False.
#for Sieve of E's, all the primes under sqrt of max num are the only needed numbers to sieve primes out.
#so here is a smaller Sieve of E's for numbers under sqrt
for n in primesUnderSqrt:
if n: #which equals to "if n != 0"
nowIndex = n + n
while True:
try:
primesUnderSqrt[nowIndex] = 0
nowIndex += n
except IndexError:
break
#full aspect sieve
for n in primesUnderSqrt:
if n:
#for easier flip processing, I need the offset number for the flipping.
nMultipleMostCloseToMin = n * (minNum // n)
if nMultipleMostCloseToMin == minNum:
nowIndex = 0
elif sqrtOfMaxNum <= minNum:
nowIndex = nMultipleMostCloseToMin + n - minNum
elif sqrtOfMaxNum > minNum:
nowIndex = nMultipleMostCloseToMin + n - minNum + n
#happy flippin'
while True:
try:
processingRange[nowIndex] = 0
nowIndex += n
except IndexError:
break
return processingRange
def main():
todoTimes = int(input())
todoNums = list(range(todoTimes))
stringOutput = ''
for i in range(todoTimes):
todoNums[i] = input().split()
todoNums[i][0] = int(todoNums[i][0])
todoNums[i][1] = int(todoNums[i][1])
for [minNum, maxNum] in todoNums:
#countedNum = 0 #for algo debugging
for n in getPrimeInRange(minNum, maxNum):
if n:
stringOutput += str(n)
#countedNum += 1 #for algo debugging
stringOutput += '\n'
stringOutput += '\n'
#stringOutput += str(countedNum) #for algo debugging
stringOutput = stringOutput.rstrip('\n')
print(stringOutput)
ifMainSucceed = main()
This part of your logic
if nMultipleMostCloseToMin == minNum:
nowIndex = 0
elif sqrtOfMaxNum <= minNum:
nowIndex = nMultipleMostCloseToMin + n - minNum
elif sqrtOfMaxNum > minNum:
nowIndex = nMultipleMostCloseToMin + n - minNum + n
is wrong. Your elif-conditions don't make much sense here. If n is not a divisor of minNum, the smallest multiple of n not less than minNum is nMultipleMostCloseToMin + n, regardless of whether sqrtOfMaxNum is larger than minNum or not. The condition you intended here was n <= minNum, to avoid crossing off the prime itself.