Largest prime factor 最大素因子

注:不标明题目出处

'''
The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?
最大素因子
'''
分析:

求一个数的素因子,那么有这么几种做法:

一,列出所有的素数,然后逐个计算,计算得到最大的那个素数即是最大素因子(从前往后,与从后往前的计算量是不一样的)

二,列出当前的素数,然后用目标除尽素数,得到一个新的数,继续如此,最后得到的非1数即为最大的素因子

三,从2开始,依次递增,然后判断是否能被目标整除,若能,那么除尽此数,并添加到列表,然后继续。

最后得到一个素因子列表,列表最后一项即为目标的最大素因子

解法一:

列出所有可能的素数,从后往前依然计算,若可以整除,那么返回

def max_prime(target):
<span style="white-space:pre">	</span>if target < 2: return 0
<span style="white-space:pre">	</span>middle = int(math.sqrt(target)) + 1
<span style="white-space:pre">	</span>primelist = create_prime_list(middle)
<span style="white-space:pre">	</span>for x in xrange(1, middle):
<span style="white-space:pre">		</span>index = middle - x
<span style="white-space:pre">		</span>if primelist[index] == 1:
<span style="white-space:pre">			</span>if target % index == 0:
<span style="white-space:pre">				</span>return index
<span style="white-space:pre">	</span>return target

print max_prime(n)

若当前这个数非素数,那么一定可以分解成素数相乘,且最大的那个素数不会超过它的平方根?

对于21 = 3 * 7,所以此方法宣告失败

那进一步说,非素数分解成素数相乘,最大那个素数肯定不会超过它的一半,于是有:

def max_prime(target):
	if target < 2: return 0
	middle = target / 2 + 1
	primelist = create_prime_list(middle)
	for x in xrange(1, middle):
		index = middle - x
		if primelist[index] == 1:
			if target % index == 0:
				return index
	return target
若是这样,那么对于此题,它需要生成一个300425737572长度的列表,太大了,显然不合适。

所以此方法宣告失败


在这里用到了生成素数列表,这个方法还不错,虽然不是最好的,但肯定不是差的。

def create_prime_list(n = 10 ** 6):	
	other = n % 6
	total = n / 6
	primelist = [0, 1, 0, 0, 0, 1] * total + [0, 1, 0, 0, 0, 1][:other]
	for i in xrange(2, n):
		if primelist[i]:
			primelist[i+i :: i] = [0] * ((n - i - 1) / i)
	primelist[0:4] = [0, 0, 1, 1]
	return primelist
生成自然序列,若当前列表下标为素数,那么下标所示的位置的值为1,否则为0


从前往后计算,需要记录一下取得的素因子

<pre name="code" class="python">def max_prime(target):
if target < 2: return 0
middle = target / 2 + 1
primelist = create_prime_list(middle)
maxprime = 0
for x in xrange(1, middle):
index = x
if primelist[index] == 1:
if target % index == 0:
maxprime = index
if maxprime == 0:
maxprime = target
return maxprime

 这个算法和前面的一样,所以也可以说是 
失败的。 

解法二:

列出可能的素数,依然去除,最后得到的非1整数,即为最大素因子

def max_prime(target):
<span style="white-space:pre">	</span>if target < 2: return 0
<span style="white-space:pre">	</span>middle = int(math.sqrt(target)) + 1
<span style="white-space:pre">	</span>primelist = create_prime_list(middle)
<span style="white-space:pre">	</span>for x in xrange(1, middle):
<span style="white-space:pre">		</span>if primelist[x] == 1:
<span style="white-space:pre">			</span>while target % x == 0:
<span style="white-space:pre">				</span>target /= x
<span style="white-space:pre">			</span>if target == 1:
<span style="white-space:pre">				</span>return x
<span style="white-space:pre">		</span>if target < middle and primelist[target] == 1:
<span style="white-space:pre">			</span>return target
<span style="white-space:pre">	</span>return target

这个解法和上面的有所区别,那就是若这个数分解后,得到的素数并不在生成的素数列表里面,也可以返回正确的结果。

原因是:在计算素数因子的过程中将所有小的互生数因子都去掉了,若它含有一个素因子大于它的平方根,那么它不会被除掉,会保留下来。

那么计算后,返回计算后的target值,即为最大的素因子。

若还有一个素因子大于它的平方根,那么这两个都大于平方根的素因子相乘,显然大于这个数,所以它最多只有一个大于平方根的素因子。

而所有小于平方根的素因子都去掉了,肯定只剩下这个素因子了。

若没有一个大于平方根的素因子,那么会在遍历的过程中出现,当除尽时,target的值为1,此时的除数即为最大的素因子。

为了加快计算,若target在列表范围内,且在素数列表中找到其值为1,那么说明target为素数,且为最大,因为比它小的已经除掉了。


解法三:

从2开始,依次递增,(这是从一个朋友那里学来的,不过,没学完全)

def max_prime(target):
<span style="white-space:pre">	</span>if target < 2: return 0
<span style="white-space:pre">	</span>primelist = []
<span style="white-space:pre">	</span>f = 2
<span style="white-space:pre">	</span>while 1:
<span style="white-space:pre">		</span>while f ** 2 < target:
<span style="white-space:pre">			</span>while target % f == 0:<span style="white-space:pre">		</span>
<span style="white-space:pre">				</span>target //= f
<span style="white-space:pre">				</span>primelist.append(f)
<span style="white-space:pre">			</span>f += 1
<span style="white-space:pre">		</span>else:
<span style="white-space:pre">			</span>if target == f ** 2:
<span style="white-space:pre">				</span>target //= f
<span style="white-space:pre">			</span>primelist.append(target)
<span style="white-space:pre">			</span>return primelist
对于这个方法,若是只关注于本题,那么可以设置f=3,然后在循环的时候,f+=2,这样会更快。

上面的方法通用,但是不是足够快的。

若是希望更通用一点,那么需要处理一下后,才能这样赋值。

<span style="white-space:pre">	</span>while target % 2 == 0: target = target >> 1
	if target == 1: return 2
在第3行添加如上两行,即可以使用f = 3, f += 2这个方法。


我不知道这样讲,是否可以让你明白。是否这样就是秩序渐进。希望得到你的评论。谢谢。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值