I created the code for the problem description below. It works for\$N\le10^6\$ but after that it gives a time out error. What I don't understand is how to optimize the code using dynamic programming. I have used a dictionary to create decibinary numbers with the formula mentioned inthis OEIS post. for more description link:Hackerrank decibinary problem forum
Problem description:
Let's combine decimal and binary numbers in a new system we calldecibinary! In this number system, each digit ranges from 0 to 9 (likethe decimal number system), but the place value of each digitcorresponds to the one in the binary number system. For example, thedecibinary number 2016 represents the decimal number 24 because:
\$ (2016)_{decibinary}= 2\cdot2^3+0\cdot2^2+1\cdot2^1+6\cdot2^0 = (24)_{10} \$
Pretty cool system, right? Unfortunately, there's a problem: twodifferent decibinary numbers can evaluate to the same decimal value!For example, the decibinary number 2008 also evaluates to the decimalvalue 24:
\$ (2008)_{decibinary}= 2\cdot2^3+0\cdot2^2+0\cdot2^1+8\cdot2^0 = (24)_{10}\$
This is a major problem because our new number system has no realapplications beyond this challenge!
Consider an infinite list of non-negative decibinary numbers that issorted according to the following rules:
- The decibinary numbers are sorted in increasing order of the decimal value that they evaluate to.
- Any two decibinary numbers that evaluate to the same decimal value are ordered by increasing decimal value, meaning the equivalentdecibinary values are strictly interpreted and compared as decimalvalues and the smaller decimal value is ordered first.
You will be given q queries in the form of an integer, q. For each x,find and print the\$x^{\textrm{th}}\$ decibinary number in the list on a newline.
Function Description
Complete the decibinaryNumbers function in the editor below. For eachquery, it should return the decibinary number at that one-based index.
decibinaryNumbers has the following parameter(s):
x: the index of the decibinary number to return
Input Format
The first line contains an integer,\$q\$, the number of queries. Each ofthe next\$q\$ lines contains an integer,\$x\$, describing a query.
Constraints:
\$ 1 \le q \le 10^5 \$
\$ 1 \le x \le 10^{16} \$
Output Format
For each query, print a single integer denoting the the xth decibinarynumber in the list. Note that this must be the actual decibinarynumber and not its decimal value. Use 1-based indexing.
Sample Input 0
5123410Sample Output 0
01210100Additional samples omitted…
#!/bin/python3import mathimport osimport randomimport reimport sysfrom math import floorfrom collections import defaultdicta={0:0,1:1,2:2,3:3}for i in range(4,10**6): a[i]=2*a[floor(i/10)]+i%10d=defaultdict(lambda:[])i=1x_to_decibin={}for x,y in a.items(): d[y].append(x)i=1l=list(d.values())l=sum(l,[])ind=[i for i in range(1,len(l)+1)]x_to_decibin=dict(zip(ind,l))print(x_to_decibin) def decibinaryNumbers(x): return x_to_decibin[x]if __name__ == '__main__': fptr = open(os.environ['OUTPUT_PATH'], 'w') q = int(input().strip()) for q_itr in range(q): x = int(input().strip()) result = decibinaryNumbers(x) fptr.write(str(result) + '\n') fptr.close()1 Answer1
First there's some script cleanups I want to mention.
import mathimport osimport randomimport reimport sysfrom math import floorfrom collections import defaultdictI'll assume that the imports from the default input may be needed, but I think it's pretty unnecessary to import floor in addition to math. Usuallymath.floor is short enough, but it's also not needed in this case.
a={0:0,1:1,2:2,3:3}for i in range(4,10**6): a[i]=2*a[floor(i/10)]+i%10Instead of using floor here, you can use a double division operator which will also do floored division. You also don't need adict for this purpose, and could instead just initialize a list to the size you need.
N = 10**6+1 # Max size to compute (plus one for offset)a = [0]*Nfor i in range(1,N): a[i]=2*a[i//10]+i%10d=defaultdict(lambda:[])i=1x_to_decibin={}for x,y in a.items(): d[y].append(x)i=1l=list(d.values())l=sum(l,[])Thei=1 statements don't do anything here sincei is overwritten when next used.x_to_decibin is also set later. The intermediate list is also unneeded sincedict_values is iterable.
d=defaultdict(lambda:[])# Iterate through decibin values (index) and add them to a list of their decimal value (element)for index, element in enumerate(a): d[element].append(index)l=sum(d.values(),[])ind=[i for i in range(1,len(l)+1)]x_to_decibin=dict(zip(ind,l))print(x_to_decibin)def decibinaryNumbers(x): return x_to_decibin[x]I'm not sure if you included the print in a submission, but printing a fairly large structure won't be great.x_to_decibin also doesn't need to be created at all since you can just usel directly with a simple 1 offset.
def decibinaryNumbers(x): return l[x - 1] # Get value from precomputed list (with 1 offset)With all of these changes, the running time for the setup withN=10**6+1 on my machine went from 5.7 to 2.4 seconds. From here, profiling shows that by far the slowest part of the script is callingsum on the large iterable. Replacing it with aitertools.chain.from_iterable call sped it up to 0.15 seconds.
However, I am only able to increase N to about10**8 before memory starts becoming an issue. These changes allow for doing subtask 3 of10**7 pretty quickly, but precomputing every value is just not going to work for the full size. If you want to do that, you'll instead need something that generates a value at runtime. You'll have to change your method to do this though. Try following some of what people have put in the discussions.
Final code:
from itertools import chainfrom collections import defaultdictN = 10**6+1a = [0]*Nfor i in range(1,N): a[i]=2*a[i//10]+i%10d=defaultdict(lambda:[])for index, element in enumerate(a): d[element].append(index)l=tuple(chain.from_iterable(d.values()))def decibinaryNumbers(x): return l[x - 1]- \$\begingroup\$I didn't understand what they did in the discussion section. I only want to optimize this code. Anything above 10^6 gives me memory error.\$\endgroup\$vijayalakshmi_bhagat– vijayalakshmi_bhagat2022-08-16 19:12:11 +00:00CommentedAug 16, 2022 at 19:12
- \$\begingroup\$Running it for 10^7 only used about 830MB on my machine, so I'd be a bit surprised to see a
MemoryErrorthere. You could try usingdelstatements to deleteaanddonce done with them, and also usingarray.array('L')from thearraymodule instead of the current itereables fora,l, and and thedefaultdictlambda.\$\endgroup\$duckboycool– duckboycool2022-08-16 19:56:04 +00:00CommentedAug 16, 2022 at 19:56
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

