每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。如30=2×3×5 。分解质因数只针对合数。求一个数分解质因数,要从最小的质数除起,一直除到结果为质数为止。
    例如:360

    36 分解质因数 - 图1
    需要注意的是,每次都要从最小的质数开始尝试除,例如360可以除2、除2、除2,被2整除3次才得到一个不能被2整除的45,然后再除3,除3,最后得到质数5。
    如果先定义一个判定素数的函数,那么问题就变成整除和缩小问题规模了。

    1. def isPrime(n): # 判断素数的函数,可以接受任意整数输入,实际上本题可以不判定2以下的数字
    2. if n < 2: # 0和1不是素数
    3. return False
    4. for i in range(2, int(n ** 0.5) + 1): # 保证效率
    5. if n % i == 0:
    6. return False
    7. else:
    8. return True

    从2开始遍历,如果数 num 能被当前数字 i 整除且当前数字 i 是素数,那就记录下当前数字i,同时将 num 变成 num // i 。

    1. num = int(input())
    2. ls = []
    3. for i in range(2,num + 1): # 2开始遍历到num
    4. if num % i == 0 and isPrime(i): # 如果数 num 能被当前数字 i 整除且当前数字 i 是素数
    5. ls.append(i) # 将得到的质因数加入列表保存
    6. num = num // i # 缩小 num 规模
    7. print(num,i) # 输出最后得到的num和因子i值,观察执行过程
    8. print(ls) # 输出列表中得到的质因数

    测试程序
    输入:360
    输出:
    360
    180 2
    60 3
    12 5
    [2, 3, 5]
    这里会发现一个问题,2 3 5 = 30
    从结果可以看到:
    360 // 2 == 180
    180 // 3 == 60
    60 // 5 == 12
    此时12已经无法被比5大的质数整除了,说明上面的算法出了问题。从上面的运算可以发现,360 // 2 的结果 180仍可以被2整除,得到的结果90仍可以被2整除……。
    为了解决这个问题,可以再加一层循环,进入循环的条件是“如果数 num 能被当前数字 i 整除且当前数字 i 是素数”,这样,只有当num 不再能被 i 整除时才会退出内层循环,实现连续除运算。
    代码修改如下:

    1. num = int(input())
    2. ls = []
    3. for i in range(2,num + 1): # 2开始遍历到num
    4. while num % i == 0 and isPrime(i): # 如果数 num 能被当前数字 i 整除且当前数字 i 是素数
    5. ls.append(i) # 将得到的质因数加入列表保存
    6. num = num // i # 缩小 num 规模
    7. print(num,i) # 输出最后得到的num和因子i值,观察执行过程
    8. print(ls) # 输出列表中得到的质因数

    实际上,修改的语句只有一条,原来的if 修改为while,二者的区别是:
    if 只判断一次,然后就进入外层循环的下一次循环。
    while 本身是循环控制语句,此语句的加入,程序从一重循环变成了二重循环,while后面的条件表达式会被重复执行,每判断结果为True就会进入内层循环一次,直至条件表达式的结果为假。
    这样运算结果就变成了:
    输入:
    360
    输出:
    180 2
    90 2
    45 2
    15 3
    5 3
    1 5
    [2, 2, 2, 3, 3, 5]
    这时可以看到分解的最终结果为2 2 2 3 3 5 1,这才是正确的分解质因数的结果。
    合并上面的程序:

    1. def isPrime(n): # 判断素数的函数,可以接受任意整数输入,实际上本题可以不判定2以下的数字
    2. if n < 2:
    3. return False # 0和1不是素数
    4. for i in range(2, int(n ** 0.5) + 1): # 保证效率
    5. if n % i == 0:
    6. return False
    7. else:
    8. return True # for 循环正常结束未遇到return时返回True
    9. num = int(input())
    10. ls = []
    11. for i in range(2,num + 1): # 2开始遍历到num
    12. while num % i == 0 and isPrime(i): # 如果数 num 能被当前数字 i 整除且当前数字 i 是素数
    13. ls.append(i) # 将得到的质因数加入列表保存
    14. num = num // i # 缩小 num 规模
    15. print(ls) # 输出列表中得到的质因数

    我们知道使用筛选法,先生成小于n的所有数字,再把 2 到 sqrt(n) 之间的整数的倍数依次去掉,剩余的就是小于n的所有素数了。
    36 分解质因数 - 图2
    结合筛选法,可以使分解质因数的程序变得更简单:

    1. n = int(input())
    2. ls = []
    3. for i in range(2,n+1): # 从2 到 n 遍历
    4. while(n%i == 0): # n 可以被i整除,必是合数,将其除以i,i实际上也是按筛选法得到的素数
    5. ls.append(i) # 保存得到的质因子
    6. n = n // i # 缩小规模
    7. print(ls)

    可以在循环过程中减少外层循环次数:

    1. num = int(input())
    2. factor = []
    3. i = 2
    4. while num != 1:
    5. while num % i == 0:
    6. factor.append(i)
    7. num = num // i
    8. # print(num)
    9. i = i + 1
    10. print(factor)
    11. 426853648526468
    12. [2, 2, 547, 613, 971, 327757]

    可以只用一层循环,用分支语句控制测试因子 i 的值:

    1. num = int(input())
    2. i = 2
    3. factor = []
    4. while i <= num:
    5. if num % i == 0:
    6. factor.append(i)
    7. num = num // i
    8. else:
    9. i = i + 1
    10. print(factor)
    11. # 2685364852646826
    12. # [2, 3, 3, 3, 7, 197, 613, 58828097]