Project Euler第35题:代码输出异常及重复计数问题排查
你的初始代码里,circular_checker函数的核心逻辑有两个致命缺陷:
1. 函数提前终止,后续素数未被检查
在circular_checker中,你一旦发现某个素数的循环变体不在prime_list里,就直接return False——这会让整个函数立刻停止执行,后面的所有素数都不会被处理。
举个例子:当遍历到19时,它的循环变体是91,而91不是素数(7×13),此时函数直接return False,终止运行,所以19之后的素数(比如11、13、17等)根本没机会被检查,这就是输出在19处中断的原因。
正确的做法应该是用一个标志变量(比如is_circular)来标记当前素数是否符合条件,而不是直接返回:
def circular_checker(): for j in prime_list: original = str(j) is_circular = True # 基于原始字符串生成所有循环变体 for i in range(len(original)): rotated = original[i:] + original[:i] if int(rotated) not in prime_list: is_circular = False break if is_circular: prime2.append(j)
2. 循环变体生成逻辑错误
你在生成循环变体时,每次都会修改x的值:
x = x[i:len(x)]+x[0:i]
这会导致后续的循环变体是基于上一次修改后的x生成的,虽然两位数字的情况下结果可能碰巧正确,但逻辑上是错误的(比如三位数的素数113,第二次循环会基于第一次旋转后的311再旋转,而不是原始的113)。正确的做法是基于原始字符串生成每个循环变体,就像上面的代码那样。
3. 额外小问题:prime_list的范围
你的prime_sieve函数里,收集素数的循环是for p in range(2,n):,这会漏掉n本身(如果n是素数的话)。比如当n=1000时没问题,但如果n=997(素数),就会漏掉它。应该改成range(2, n+1)。
你的更新代码试图通过排除含偶数/5的数来优化,但逻辑上有几个错误:
1. 条件逻辑错误
你写的判断条件:
if not prime[int(x)] or "2" in x or "4" in x or "6" in x or "8" in x or "0" in x or "5" in x:
这里的or逻辑会导致:只要循环变体包含这些数字,就判定不是循环素数。但循环变体的数字和原始素数完全一致,只是顺序不同——所以只要原始素数(除了2和5)包含这些数字,它的某个循环变体必然会以偶数/5结尾,肯定不是素数。
正确的逻辑应该是:
- 首先判断当前素数是否是2或5:如果是,直接加入结果(它们是循环素数)
- 否则,检查原始素数是否包含2、4、6、8、0、5:如果包含,直接跳过(不可能是循环素数)
- 最后检查所有循环变体是否都是素数
修改后的circular_checker:
def circular_checker(): excluded = {'2','4','6','8','0','5'} for j in prime_list: if j == 2 or j ==5: prime2.append(j) continue original = str(j) # 检查原始数是否包含排除数字 if any(c in excluded for c in original): continue # 检查所有循环变体 is_circular = True for i in range(len(original)): rotated = original[i:] + original[:i] if not prime[int(rotated)]: is_circular = False break if is_circular: prime2.append(j)
2. 全局变量的潜在问题
你的prime是prime_sieve里的局部变量,但circular_checker里直接访问了prime[int(x)]——这在Python里会报错,除非你把prime声明为全局变量。如果没声明,代码能运行说明你可能修改了prime_sieve,但如果全局变量的处理有问题,可能导致prime列表的标记错误,进而误判素数,导致计数错误。
3. 重复添加与去重的问题
你手动添加了2和5到prime2_up,但如果修改后的circular_checker已经把2和5加入prime2,就会导致重复。不过remove_duplicate会去重,这不是主要问题,但最好让逻辑统一,不要手动添加。
最后,修正后的代码应该能得到正确的55个循环素数(小于1e6)。
内容的提问来源于stack exchange,提问作者YourAverageEuler

