P36 - 质因数分解(含重数)

2026-09-07 00:00    #Haskell   #99题   #数论  

P36 - 质因数分解(含重数)

Determine the prime factors and their multiplicities

官方模块:Problems.P36 核心函数:primeFactorsMultiplicity


← P35 质因数分解 | P37 欧拉乘积公式 →


题目描述

把 P35 的重复质因数压缩成 (质因数, 重数)。例如 [3,3,5,7] 变为 [(3,2),(5,1),(7,1)]

函数签名

1primeFactorsMultiplicity :: Integral a => a -> [(a, a)]

实现

方法一:group + map

1import Data.List (group)
2
3primeFactorsMultiplicity :: Integral a => a -> [(a, a)]
4primeFactorsMultiplicity = map encode . group . primeFactors
5  where
6    encode xs = (head xs, fromIntegral (length xs))

P35 保证因数有序,因此相同因数必然连续,group 可以直接打包。head 在这里是安全的,因为 group 不会生成空子列表。

方法二:打包时不依赖 group

1primeFactorsMultiplicity :: Integral a => a -> [(a, a)]
2primeFactorsMultiplicity n = pack (primeFactors n)
3  where
4    pack [] = []
5    pack (x:xs) = (x, 1 + length ys) : pack zs
6      where (ys, zs) = span (== x) xs

span 手动切分连续相同元素,效果等同于 group 但不依赖 Data.List

方法三:直接边分解边计数(不依赖 P35)

 1primeFactorsMultiplicity :: Integral a => a -> [(a, a)]
 2primeFactorsMultiplicity n
 3  | n < 1     = error "primeFactorsMultiplicity: positive input required"
 4  | otherwise = factor n 2
 5  where
 6    factor 1 _ = []
 7    factor x d
 8      | d * d > x      = [(x, 1)]
 9      | x `mod` d == 0 = (d, count) : factor remaining nextDivisor
10      | d == 2         = factor x 3
11      | otherwise      = factor x (d + 2)
12      where
13        (count, remaining) = divideOut x d 0
14        nextDivisor = if d == 2 then 3 else d + 2
15
16    divideOut value divisor count
17      | value `mod` divisor == 0 =
18          divideOut (value `div` divisor) divisor (count + 1)
19      | otherwise = (count, value)

边分解边统计重数。更紧凑但可读性不如先分解再 group

方法对比

方法特点
group + map最清晰,推荐
span 手动分组不依赖 Data.List
边分解边计数一通到底,不依赖 P35

测试

1>>> primeFactorsMultiplicity 315
2[(3,2),(5,1),(7,1)]
3>>> primeFactorsMultiplicity 81
4[(3,4)]
5>>> primeFactorsMultiplicity 1024
6[(2,10)]
7>>> primeFactorsMultiplicity 1
8[]

参考