Why is my code giving memory error? - python

I am making a program where I can count the number of a in a string. This is my Code:
def repeatedString(s, n):
converged = s*n
got_it = converged[0:n]
count = 0
for x in got_it:
if "a" in x:
count += 1
return count
s = input()
n = int(input())
result = repeatedString(s, n)
print(result)
The variable s is where the string is entered, and variable n is for upto how long the string will repeat. My Code works OK, but for some reason when I give a bigger integer, it falls apart and gives me a Memory Error. For example, my input is:
a
1000000000000
It gives me this error:
Traceback (most recent call last):
File "programs.py", line 11, in <module>
result = repeatedString(s, n)
File "programs.py", line 2, in repeatedString
converged = s*n
MemoryError
How can I fix this Memory Error? If there's a better way to do it, it would also be helpful.

The problem with your code is where you do converged = s*n. In that line, you are asking the program to take the string s and allocate enough memory to fit the number of bytes in s * n, which, as you have seen, has a limit because your computer has a finite amount of free memory available (most modern-day computers only carry 4 - 16 gigabytes of RAM).
One way you can fix the memory error is by exploiting one aspect of your function - you are simply checking how many "a"'s fit in a string s repeated up to a length of n. So, instead of doing converged = s*n and subsequent modifications that require a lot of memory to store such a large string, you can instead use simple math to get the answer you are looking for.
Also, another optimization you could do is that you do not have to convert your string into an array to loop over it. Instead of doing for x in got_it, you could do for c in s.
Here is a working example of how you can accomplish what you need:
import math
def repeatedString(s, n):
if len(s) == 0:
return 0
reps = float(n) / len(s)
count = 0
for c in s:
if c == "a":
count += 1
# After testing the code, it turns out that Python does not play nicely
# with rounding UP from 0.5, so this is necessary to get the correct answer
result = count * reps
if result - math.floor(result) < 0.5:
return math.floor(result)
return math.ceil(result)
s = input()
n = int(input())
result = repeatedString(s, n)
print(result)

this program
takes a input string named s
repeats this string concatenated n times
takes only the first n charactes in the concatenated
counts how many times the letter "a" appears
you
you give the string "a"
you give the number 1000000000000
then the program should count and return 1000000000000
memmory problem
I guess this string with 1000000000000 letters "a" is too big
for the type in the python language
or for the computer memmory
the way it is
given that the program searches for the fixed occurrences of letter "a"
you passed exactly the letter "a" and the number 1000000000000
the better way is that it's not necessary a program
if you want to know how many times there is the letter "a"
in a string with 1000000000000 letters "a"
the answer is obviously 1000000000000
extra:
it would be complicated:
to rewrite the program
to search for a pattern
given as input parameter,
with variable length
AND
avoid the memmory problem
I guess I would write a program that
concatenates the "s" input just to have a length bigger than the searched pattern (if already not is)
check if the pattern occurs
after that multiply by "n"
ajust the how many times it will 'fit' in the final

one-line solution: find no of 'a' in string s, multiply with floor division of no.of repetition with the length of s + finding 'a' in the remaining length of s
s.count("a") * (n // len(s)) + s[:n % len(s)].count("a")

Thanks for all the help guys, I managed to solve the problem by handling the exception using try and except MemoryError

Related

Finding the product of first Million natural numbers in Python

I have just started with Python programming language. I tried to write a function which takes input either a list or multiple integers to find their product. I am trying to find the product of first million natural numbers but its displaying an MemoryError.
def product(*arg):
answer=1
if type(arg) == tuple:
arg=str(arg)
arg=arg.lstrip('[(')
arg=arg.rstrip('],)')
arg=arg.split(',')
for i in arg:
answer*=int(i)
return answer
else:
for i in arg:
answer*=int(i)
return answer
j=range(1,1000000,1)
j=list(j)
print(product(j))
Steps:
I convert the range object into list object if i am to pass a list as
argument
Now, within the function, i try to split the tuple by converting it
string.
I convert the resultant string into a list and then loop over the
elements to find the product
Q1: How to avoid the memory error as i try to find the product of first Million natural numbers?
Q2 How to improve this code?
You can use a Generator in Python.
def generate_product():
r = 1
for i in range(1,1000000):
r *= i + 1
yield r
list(generate_product())[0]
It is more memory efficient and better in terms of performance.
To calculate the product of all numbers from 1 to 1 million use a simple loop:
r = 1
for l in range(1,1000000):
r*=(i+1)
print(res)
But keep in mind that the result will be a pretty big number.
That means that your calculation might take long and the resulting number will need a lot memory.
EDIT Then i missread your question a little. This is a function that multiplies the elements in a list:
def multiply_list_elements(_list):
result = 1
for element in _list:
result*=element
return result
multiply_list_elements([1,2,3,4])
>>> 24
The memory error probably came from the huge number as #ZabirAlNazi calculated so nicely.
All of the solution is fine, but one point to make - your question is equivalent to find the factorial of 1 million.
The number of digits of n! = log10(1) + log10(2) + ... log10(n)
import math
num_dig = 1
for i in range(1,1000000):
num_dig += math.log10(i)
print(num_dig)
So, the number of digits in your answer is 5565703 (approx.).
That's only the final n, if you also want the intermediate results it will require squared memory O(m^2).
import math
ans = 1
for i in range(2,1000001):
ans *= i
print(ans)
N.B: You can approximate with logarithms and Stirling numbers with faster run-time.
A very simple solution would be:
def prod_of():
p=1
for i in range(1,1000000):
p* = i
print(p)

Python optimizing loops for checking number of anagrams

i am trying to solve a question that provides a string as input and gives the number of anagrams possible as output. this can be solved using dictionaries but i could only think in terms of for loops and string indices.
count = 0
for i in range(1,len(s)):
for j in range(0,len(s)):
for k in range(j+1,len(s)):
if(k+i>len(s)):
continue
# print(list(s[j:j+i]),list(s[k:k+i]),j,j+i,k,k+i)
if(sorted(list(s[j:j+i]))==sorted(list(s[k:k+i]))):
count +=1
return count
i have coded this far and tried for optimization with k+i. can someone tell me other techniques to optimize the code without losing the logic. the code keeps getting terminated due to time-out for larger strings.should i replace sorted function with something else.
The number of anagrams if each letter was unique would be n! with n as the length of the string (e.g. law has 3!=6). If there a given letter is repeated, say, twice (e.g. wall), then you have twice as many answers as you should (since things like w-(second l)-(first l)-a are actually indistinguishable from things like w-(first l)-(second l)-a). It turns out that if a letter is repeated k times (k is 2 for the letter "l" in wall), n! overcounts by a factor of k!. This is true for each repeated letter.
So to get the number of anagrams, you can do:
letter_counts = get_letter_counts(s) #returns something like [1, 1, 2] when given wall, since there is one w, one a, two ls
n_anagrams = factorial(len(s))
#account for overcounts
for letter_count in letter_counts:
n_anagrams /= factorial(letter_count)
return n_anagrams
Implementing factorial and get_letter_counts left as an excercise for the reader :-) . Note: Be careful to consider that repeated letters can show up more than once, and not always next to each other. Ex: "aardvark" should return a count of 3 for the "a"s, 2 for the "r"s, and 1 for everything else.

Memory error Using intertool in python

i write a programme that i input 10 for example and it find the odd number first and the even number and put them in a list [1,3,5,7,9,2,4,6,8,10] and input another number which choose the number in the list for example 3 so it print 5 and so on so i write a code like that
from itertools import count
n,y=map(int, raw_input().split()) # Input the 2 numbers
listaa=[0,] # list to save
for x in count(1,1):
if x%2!=0:
listaa.append(x)
if x==n:
break
for h in count(1,1):
if h%2==0:
listaa.append(h)
if h==n:
break
res=listaa[y]
print res # it print the number that is in the Array or list
but when i submit the code on the online judge it try this number 1000000000000 500000000001 so it get RUNTIME_ERROR then i try this on my eclipse i get Memory Error Note i first try the Xrange but i get error when i search found the Generator so i try it and use count instead of Xrange note the Run time limit for each test case is 1 second
you cannot solve this problem using that approach because the list is very big also it will time limit the test case you suggested 1000000000000 500000000001 contains approximately 4*10^12 numbers which needs more than a terabyte of ram.
so don't use a list use a math formula instead.
sample code
n,y=map(int, raw_input().split())
first_odd = 1
last_odd = n if n%2 == 1 else n-1
n_odd = (last_odd-first_odd)/2 + 1
if y <= n_odd:
print first_odd + 2*(y-1)
else:
y -= n_odd
print 2+2*(y-1)

Lucky Numbers Python Program Incorrect Python Output

Practice Problems /
Lucky String
All submissions to this problem are public. View all submissions.
Lucky numbers are those numbers which contain only "4" and/or "5". For example 4, 5, 44, 54,55,444 are lucky numbers while 457, 987 ,154 are not.
Lucky number sequence is one in which all lucky numbers exist in increasing order for example 4,5,44,45,54,55,444,445,454,455...
Now we concatenate all the lucky numbers (in ascending order) to make a lucky string "4544455455444445454455..."
Given n, your task is to find the nth digit of the lucky string. If the digit is 4 then you >have to print "Hacker" else you have to print "Earth".
Input:
first line contain number of test cases T , next T line contain a single integer n.
Output:
For each test case print Hacker if n-th digit of lucky string is 4 else print Earth if n-th digit of lucky string is 5.
Constraints:
1 <= t <= 10^5
1 <= n <= 10^15
Following is the python code :
test_cases = int(input())
final = []
def check(stra,num):
if stra[num-1]==4:
final.append("Hacker")
else:
final.append("Earth")
def GenStr(num):
stra = "4"
i = int(5)
while(len(stra)<num+2):
X = str(i)
flag = True
for j in range(len(str(i))):
if(X[j]==4 or X[j]==5):
pass
else:
flag = False
if flag==True:
stra+=X
i+=1
print(stra)
return stra
for i in range(test_cases):
num = int(input())
# generate string
stra = GenStr(num)
print("stra "+stra)
# check the stat
check(stra,num)
print("\n".join(final))
What is wrong in this code, please do not mind if it is a silly mistake I am just a beginner in python programming
Comments on your Code
There are several things in your code which don't quite make sense, and need to be addressed:
int(input()) says to ask the user nothing, try to convert any string they type before pressing enter to an integer, and crash otherwise.
The pattern for i in range(len(x)) is almost always wrong in Python. Strings are iterable (they are lists of characters), which is why you can use the list-style index operator (as you do with x[j]), so just iterate over them: for j in str(i).
The pattern if x==True: is always wrong in Python. We prefer if x:.
i = int(5). There is no need to convert an integer literal to an integer. i = 5 is the correct assignment statement.
Try to use better variable names. It's very difficult to follow your code and your reasoning because it is littered with meaningless identifiers like stra (string a??), X, num, etc.
How to Approach the Assignment
I will be honest: I don't fully understand the assignment as presented. It's not clear what a "test case" is or how the input will be formatted (or, for that matter, where the input is coming from). That said, a few thoughts on how to approach this:
Finding numbers that contain only 4 or 5 means treating them as strings. This could be as easy as testing len(str(x).replace('4', '').replace('5', '')), and there are better ways than that.
Listing 'lucky numbers' in increasing order can be accomplished with the built-in sorted function.
Concatenating that list would be ''.join(sorted(lucky_numbers)) or similar.
Taking the nth digit of that list could then be done with string indexing as before.
The immediately incorrect thing is the following. stra is 4. flag always becomes False. Thus stra never grows, and while(len(stra)<num+2): is an infinite loop.
The approach itself will not fully solve the problem, since you can't construct a string of length 1015, it would take too much time and just won't fit into memory.
As #Gassa points out, brute-forcing this is just not going to work; you would need a million gigabytes of RAM, and it would take far too long.
So what would an analytic solution look like?
If you replace "4" with "0" and "5" with "1", you will see that the lucky number sequence becomes 0, 1, 00, 01, 10, 11, 000, 001, 010, 011, 100, 101, 110, 111, .... This should look familiar: it is every 1-digit binary number in ascending order, followed by every 2-digit binary number in ascending order, followed by every 3-digit binary number in ascending order, etc.
So if you do something like
n = 491 # the digit we are seeking (for example)
d = 1 # number of binary digits
p = 2 # 2**d == number of items encoded
while n > d*p: # sought digit is past the end of the next binary expansion?
n -= d*p # reduce offset by appropriate number of digits
d += 1
p *= 2
then n = 233, d = 6 means we are looking for the 233rd character in the 6-bit expansion.
But we can improve on that:
k, n = n // d, n % d
which gives n = 5, k = 38, d = 6 means we are looking at the 5th character of the 38th 6-bit value.
Note: all offsets here are 0-based; if you expect 1-based offsets, you will have to adjust your math accordingly!
The 38th 6-bit value is just 38 converted to a 6-bit binary value; you could muck about with strings to extract the character you want, but it's probably easier to remember that integers are stored as binary internally so we can get what we want with a bit of math:
digit = (k >> (d - n - 1)) & 1 # => 0
so the character in the original string would be a "4".

Python String item not callable/math

I have to write a program that given the number below, s, finds the maximum product of a given length of consecutive numbers within the larger number. I have the framework of the code but in the line preceded by the three "#"s i keep getting an error that I cant call string 's' even though I'm turning it into an integer. I kind of understand why but I'm not quite sure. Also, if mathematically there is a better way t do that line, what would it be? Thanks so much for the help!
s=""\
"73167176531330624919225119674426574742355349194934"\
"96983520312774506326239578318016984801869478851843"\
"858615670789112949495459501737958331952853208805511"\
"12540698747158523863050715693290963295227443043557"\
"66896648950445244523161731856403098711121722383113"\
"62229893423380308135336276614282806444486645238749"\
"30358907296290491560440772390713810515859307960866"\
"70172427121883998797908792274921901699720888093776"\
"65727333001053367881220235421809751254540594752243"\
"52584907711670556013604839586446706324415722155397"\
"53697817977846174064955149290862569321978468622482"\
"83972241375657056057490261407972968652414535100474"\
"82166370484403199890008895243450658541227588666881"\
"16427171479924442928230863465674813919123162824586"\
"17866458359124566529476545682848912883142607690042"\
"24219022671055626321111109370544217506941658960408"\
"07198403850962455444362981230987879927244284909188"\
"84580156166097919133875499200524063689912560717606"\
"05886116467109405077541002256983155200055935729725"\
"71636269561882670428252483600823257530420752963450"
def findMaxProduct(n):
"""
>>> findMaxProduct(1)
9
>>> findMaxProduct(2)
81
>>> findMaxProduct(22)
3556892570112000
>>> findMaxProduct(60)
130883609235662685781298144870400000000
>>> findMaxProduct(70)
2412446685431734624320887406251212800000000
>>> findMaxProduct(80)
2412446685431734624320887406251212800000000
"""
largest = 0
for digit in range(len(s)-n):
product = 1
for k in range (n):
###product = product * int(s(digit + k))
if product > largest:
largest = product
return largest
You have s(...) which attempts to call a function named s. What you want instead is s[...] which will index into the string and return a subset of it.

Categories

Resources