在python / pypy中优化暴力过程以找到一个孩子的数字
蛮力方法并非旨在解决问题,而是有助于其研究.我正在研究一个
Project Euler问题,让我发现所有数字从X到小于Y,只有一个“子串”可以被一个数字中的位数整除.
这些被称为独子数字. 104是一个孩子的号码.在其子串中,[1,4,10,04,104]只有0可被3整除.该问题要求找出少于10 * 17的一子数的数量.蛮力方法不是正确的方法;但是,我有一个理论要求我知道在10 * 11之前发生的一个孩子数量. 我离开笔记本电脑半天后,我还没有成功找到这个数字.我试过Cython,我是一个对C一无所知的新手程序员.结果非常糟糕.我甚至尝试过云计算,但是我的ssh管道在进程完成之前总是会中断. 如果有人可以帮助我找出一些不同的方法或优化预先形成BRUTE FORCE 请不要… 借给我关于数论的建议或你对这个问题的答案,因为我已经花了很长时间研究它,我真的希望自己得出结论. ## a one child number has only one "substring" divisable by the ## number of digits in the number. Example: 104 is a one child number as 0 ## is the only substring which 3 may divide,of the set [1,104] ## FYI one-child numbers are positive,so the number 0 is not one-child from multiprocessing import Pool import os.path def OneChild(numRange): # hopefully(10*11,1) OneChild = [] start = numRange[0] number = numRange[1] ## top loop handles one number at a time ## loop ends when start become larger then end while number >= start: ## preparing to analayze one number ## for exactly one divisableSubstrings numberString = str(start) numDigits = len(numberString) divisableSubstrings = 0 ticker1,ticker2 = 0,numDigits ## ticker1 starts at 0 and ends at number of digits - 1 ## ticker2 starts at number of digits and ends +1 from ticker1 ## an example for a three digit number: (0,3) (0,2) (0,1) (1,3) (1,2) (2,3) while ticker1 <= numDigits+1: while ticker2 > ticker1: if int(numberString[ticker1:ticker2]) % numDigits == 0: divisableSubstrings += 1 if divisableSubstrings == 2: ticker1 = numDigits+1 ticker2 = ticker1 ##Counters ticker2 -= 1 ticker1 += 1 ticker2 = numDigits if divisableSubstrings == 1: ## One-Child Bouncer OneChild.append(start) ## inefficient but I want the specifics start += 1 return (OneChild) ## Speed seems improve with more pool arguments,labeled here as cores ## Im guessing this is due to pypy preforming best when task is neither ## to large nor small def MultiProcList(numRange,start = 1,cores = 100): # multiprocessing print "Asked to use %i cores between %i numbers: From %s to %s" % (cores,numRange-start,start,numRange) cores = adjustCores(numRange,cores) print "Using %i cores" % (cores) chunk = (numRange+1-start)/cores end = chunk+start -1 total,argsList= 0,[] for i in range(cores): # print start,end-1 argsList.append((start,end-1)) start,end = end,end + chunk pool = Pool(processes=cores) data = pool.map(OneChild,argsList) for d in data: total += len(d) print total ## f = open("Result.txt","w+") ## f.write(str(total)) ## f.close() def adjustCores(numRange,cores): if start == 1: start = 0 else: pass while (numRange-start)%cores != 0: cores -= 1 return cores #MultiProcList(10**7) from timeit import Timer t = Timer(lambda: MultiProcList(10**6)) print t.timeit(number=1) 解决方法
这是我最快的蛮力代码.它使用cython来加速计算.它不是检查所有数字,而是通过递归找到所有的One-Child数字.
%%cython cdef int _one_child_number(int s,int child_count,int digits_count): cdef int start,count,c,child_count2,s2,part,i if s >= 10**(digits_count-1): return child_count else: if s == 0: start = 1 else: start = 0 count = 0 for c in range(start,10): s2 = s*10 + c child_count2 = child_count i = 10 while True: part = s2 % i if part % digits_count == 0: child_count2 += 1 if child_count2 > 1: break if part == s2: break i *= 10 if child_count2 <= 1: count += _one_child_number(s2,digits_count) return count def one_child_number(int digits_count): return _one_child_number(0,digits_count) 要找到F(10 ** 7)的数量,需要大约100ms才能得到结果277674. print sum(one_child_number(i) for i in xrange(8)) 您需要64位整数来计算大结果. 编辑:我添加了一些评论,但我的英语不好,所以我将代码转换为纯python代码,并添加一些打印,以帮助您弄清楚它是如何工作的. _one_child_number递归地将数字从左添加到s,child_count是s中的子计数,digits_count是s的最终数字. def _one_child_number(s,child_count,digits_count): print s,child_count if s >= 10**(digits_count-1): # if the length of s is digits_count return child_count # child_count is 0 or 1 here,1 means we found one one-child-number. else: if s == 0: start = 1 #if the length of s is 0,we choose from 123456789 for the most left digit. else: start = 0 #otherwise we choose from 0123456789 count = 0 # init the one-child-number count for c in range(start,10): # loop for every digit s2 = s*10 + c # add digit c to the right of s # following code calculates the child count of s2 child_count2 = child_count i = 10 while True: part = s2 % i if part % digits_count == 0: child_count2 += 1 if child_count2 > 1: # when child count > 1,it's not a one-child-number,break break if part == s2: break i *= 10 # if the child count by far is less than or equal 1,# call _one_child_number recursively to add next digit. if child_count2 <= 1: count += _one_child_number(s2,digits_count) return count 这里是输出_one_child_number(0,3),并且一个3位数的子数是第一列是3位数的第二列的总和. 0 0 1 0 10 1 101 1 104 1 107 1 11 0 110 1 111 1 112 1 113 1 114 1 115 1 116 1 117 1 118 1 119 1 12 1 122 1 125 1 128 1 13 1 131 1 134 1 137 1 14 0 140 1 141 1 142 1 143 1 144 1 145 1 146 1 147 1 148 1 149 1 15 1 152 1 155 1 158 1 16 1 161 1 164 1 167 1 17 0 170 1 171 1 172 1 173 1 174 1 175 1 176 1 177 1 178 1 179 1 18 1 182 1 185 1 188 1 19 1 191 1 194 1 197 1 2 0 20 1 202 1 205 1 208 1 21 1 211 1 214 1 217 1 22 0 220 1 221 1 222 1 223 1 224 1 225 1 226 1 227 1 228 1 229 1 23 1 232 1 235 1 238 1 24 1 241 1 244 1 247 1 25 0 250 1 251 1 252 1 253 1 254 1 255 1 256 1 257 1 258 1 259 1 26 1 262 1 265 1 268 1 27 1 271 1 274 1 277 1 28 0 280 1 281 1 282 1 283 1 284 1 285 1 286 1 287 1 288 1 289 1 29 1 292 1 295 1 298 1 3 1 31 1 311 1 314 1 317 1 32 1 322 1 325 1 328 1 34 1 341 1 344 1 347 1 35 1 352 1 355 1 358 1 37 1 371 1 374 1 377 1 38 1 382 1 385 1 388 1 4 0 40 1 401 1 404 1 407 1 41 0 410 1 411 1 412 1 413 1 414 1 415 1 416 1 417 1 418 1 419 1 42 1 422 1 425 1 428 1 43 1 431 1 434 1 437 1 44 0 440 1 441 1 442 1 443 1 444 1 445 1 446 1 447 1 448 1 449 1 45 1 452 1 455 1 458 1 46 1 461 1 464 1 467 1 47 0 470 1 471 1 472 1 473 1 474 1 475 1 476 1 477 1 478 1 479 1 48 1 482 1 485 1 488 1 49 1 491 1 494 1 497 1 5 0 50 1 502 1 505 1 508 1 51 1 511 1 514 1 517 1 52 0 520 1 521 1 522 1 523 1 524 1 525 1 526 1 527 1 528 1 529 1 53 1 532 1 535 1 538 1 54 1 541 1 544 1 547 1 55 0 550 1 551 1 552 1 553 1 554 1 555 1 556 1 557 1 558 1 559 1 56 1 562 1 565 1 568 1 57 1 571 1 574 1 577 1 58 0 580 1 581 1 582 1 583 1 584 1 585 1 586 1 587 1 588 1 589 1 59 1 592 1 595 1 598 1 6 1 61 1 611 1 614 1 617 1 62 1 622 1 625 1 628 1 64 1 641 1 644 1 647 1 65 1 652 1 655 1 658 1 67 1 671 1 674 1 677 1 68 1 682 1 685 1 688 1 7 0 70 1 701 1 704 1 707 1 71 0 710 1 711 1 712 1 713 1 714 1 715 1 716 1 717 1 718 1 719 1 72 1 722 1 725 1 728 1 73 1 731 1 734 1 737 1 74 0 740 1 741 1 742 1 743 1 744 1 745 1 746 1 747 1 748 1 749 1 75 1 752 1 755 1 758 1 76 1 761 1 764 1 767 1 77 0 770 1 771 1 772 1 773 1 774 1 775 1 776 1 777 1 778 1 779 1 78 1 782 1 785 1 788 1 79 1 791 1 794 1 797 1 8 0 80 1 802 1 805 1 808 1 81 1 811 1 814 1 817 1 82 0 820 1 821 1 822 1 823 1 824 1 825 1 826 1 827 1 828 1 829 1 83 1 832 1 835 1 838 1 84 1 841 1 844 1 847 1 85 0 850 1 851 1 852 1 853 1 854 1 855 1 856 1 857 1 858 1 859 1 86 1 862 1 865 1 868 1 87 1 871 1 874 1 877 1 88 0 880 1 881 1 882 1 883 1 884 1 885 1 886 1 887 1 888 1 889 1 89 1 892 1 895 1 898 1 9 1 91 1 911 1 914 1 917 1 92 1 922 1 925 1 928 1 94 1 941 1 944 1 947 1 95 1 952 1 955 1 958 1 97 1 971 1 974 1 977 1 98 1 982 1 985 1 988 1 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |