How can I speed up my solution to this self-describing number puzzle? [closed]

懵懂的女人 提交于 2019-12-07 20:08:24

问题


I came across this puzzle from centerofmath.org via Twitter:

There is a ten-digit number where the leftmost digit is also the number of zeros in the number, the second leftmost digit is the number of ones and so forth until the last digit (or rightmost digit) is the number of nines in that number. What is this number and is it unique?

I wrote a program in Python to solve the puzzle:

def yielder(exponent):
     i = 10**exponent
     while i < (10**(exponent+1))-1:
          yield i
          i += 1

def is_solution(num):
     l = list(num)
     #l.reverse()
     is_sol = True
     for i, e in enumerate(l):
          if int(e) != l.count(str(i)):
               is_sol = False
               break
     return is_sol

if __name__=="__main__":
     import sys
     ofile = open('solution.txt', 'w')
     j = int(sys.argv[1])
     print("checking between {0} and {1}".format(10**j, (10**(j+1))-1))
     ofile.write("Solutions between {0} and {1}:\n".format(10**j, (10**(j+1))-1))
     for x in yielder(j):
          if is_solution(str(x)):
              ofile.write('\t{0}\n'.format(x))
              print("solution is {0}".format(x))
     ofile.close()

And the solution I got is 6210001000

But the problem is it took several hours to solve. I want to know if there is some technique I could have used to make it faster

BTW these are the numbers between 10 9,999,999,999 that are solutions

Solutions between 10 and 99:
Solutions between 100 and 999:
Solutions between 1000 and 9999:
    1210
    2020
Solutions between 10000 and 99999:
    21200
Solutions between 100000 and 999999:
Solutions between 1000000 and 9999999:
    3211000
Solutions between 10000000 and 99999999:
    42101000
Solutions between 100000000 and 999999999:
    521001000
Solutions between 1000000000 and 9999999999:
    6210001000

回答1:


It's much faster if you construct the number other than search for it.

def to_the_number(n):
    digits=list(map(int,n))
    assert(len(digits))==10
    done = False
    while not done:
        done = True
        for i in range(10):
            if digits[i]!=digits.count(i):
                digits[i]=digits.count(i)
                print(digits)
                done = False
    return ''.join(map(str, digits))

And start from any number:

>>> to_the_number('1234567890')
[1, 1, 3, 4, 5, 6, 7, 8, 9, 0]
[1, 1, 0, 4, 5, 6, 7, 8, 9, 0]
[1, 1, 0, 0, 5, 6, 7, 8, 9, 0]
[1, 1, 0, 0, 0, 6, 7, 8, 9, 0]
[1, 1, 0, 0, 0, 0, 7, 8, 9, 0]
[1, 1, 0, 0, 0, 0, 0, 8, 9, 0]
[1, 1, 0, 0, 0, 0, 0, 0, 9, 0]
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[8, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[8, 1, 0, 0, 0, 0, 0, 0, 1, 0]
[7, 1, 0, 0, 0, 0, 0, 0, 1, 0]
[7, 2, 0, 0, 0, 0, 0, 0, 1, 0]
[7, 2, 1, 0, 0, 0, 0, 0, 1, 0]
[7, 2, 1, 0, 0, 0, 0, 1, 1, 0]
[7, 2, 1, 0, 0, 0, 0, 1, 0, 0]
[6, 2, 1, 0, 0, 0, 0, 1, 0, 0]
[6, 2, 1, 0, 0, 0, 1, 1, 0, 0]
[6, 2, 1, 0, 0, 0, 1, 0, 0, 0]
'6210001000'



回答2:


You can cut out massive amounts of number checks by using a bit more logic. For example, you know that the sum of the individual digits must be 10, otherwise the number has too many digits, so try taking advantage of that.

You could, for example, change your yielder to only generate numbers for which the condition sum(int(n) for n in num) == len(num) is satisfied, then you don't need to check with an expensive loop on numbers which you already know can't make sense.



来源:https://stackoverflow.com/questions/12704061/how-can-i-speed-up-my-solution-to-this-self-describing-number-puzzle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!