doocs/leetcode 数论算法精解:从基础到高阶实战指南
还在为LeetCode中的数论题目头疼吗?面对素数判定、最大公约数、模运算等数学问题无从下手?本文带你系统掌握doocs/leetcode项目中所有数论算法核心技巧,一文解决你的数学算法难题!
读完本文你将获得:
- ✅ 数论算法核心概念与理论基础
- ✅ 10+种经典数论问题解法模板
- ✅ 20+道LeetCode数论题目详细解析
- ✅ 高效算法实现与优化技巧
- ✅ 实战代码示例与复杂度分析
数论算法基础概念
1. 素数(质数)判定与生成
素数定义:大于1的自然数中,除了1和它本身以外不再有其他因数的数。
埃拉托斯特尼筛法(Sieve of Eratosthenes)
def count_primes(n: int) -> int:
if n <= 2:
return 0
is_prime = [True] * n
is_prime[0] = is_prime[1] = False
for i in range(2, int(n**0.5) + 1):
if is_prime[i]:
for j in range(i*i, n, i):
is_prime[j] = False
return sum(is_prime)
复杂度分析:
- 时间复杂度:O(n log log n)
- 空间复杂度:O(n)
2. 最大公约数(GCD)与最小公倍数(LCM)
欧几里得算法(辗转相除法)
def gcd(a: int, b: int) -> int:
while b:
a, b = b, a % b
return a
def lcm(a: int, b: int) -> int:
return a * b // gcd(a, b)
数学原理:gcd(a, b) = gcd(b, a mod b)
核心数论算法分类
1. 模运算与同余定理
快速幂算法(Fast Exponentiation)
def pow_mod(base: int, exponent: int, modulus: int) -> int:
result = 1
base = base % modulus
while exponent > 0:
if exponent % 2 == 1:
result = (result * base) % modulus
exponent = exponent >> 1
base = (base * base) % modulus
return result
2. 素数相关算法
算法类型 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
试除法 | O(√n) | O(1) | 单个素数判断 |
埃氏筛 | O(n log log n) | O(n) | 区间素数统计 |
线性筛 | O(n) | O(n) | 需要质因数分解 |
3. 数论分块与莫比乌斯反演
def sum_divisors(n: int) -> int:
result = 0
i = 1
while i <= n:
j = n // (n // i)
result += (n // i) * (i + j) * (j - i + 1) // 2
i = j + 1
return result
LeetCode数论题目精选解析
题目1:计数质数(204. Count Primes)
问题描述:统计所有小于非负整数 n 的质数的数量。
解法思路:
- 使用埃拉托斯特尼筛法标记非素数
- 从2开始遍历到√n
- 标记所有倍数
代码实现:
class Solution:
def countPrimes(self, n: int) -> int:
if n <= 2:
return 0
is_prime = [True] * n
is_prime[0] = is_prime[1] = False
for i in range(2, int(n**0.5) + 1):
if is_prime[i]:
for j in range(i*i, n, i):
is_prime[j] = False
return sum(is_prime)
题目2:快乐数(202. Happy Number)
问题描述:判断一个数是否是快乐数。
解法思路:
- 使用快慢指针检测循环
- 数学性质:不快乐数最终会进入4→16→37→58→89→145→42→20→4的循环
class Solution:
def isHappy(self, n: int) -> bool:
def get_next(number):
total_sum = 0
while number > 0:
digit = number % 10
total_sum += digit * digit
number //= 10
return total_sum
slow = n
fast = get_next(n)
while fast != 1 and slow != fast:
slow = get_next(slow)
fast = get_next(get_next(fast))
return fast == 1
题目3:分数到小数(166. Fraction to Recurring Decimal)
问题描述:给定两个整数,分别表示分数的分子和分母,返回字符串形式的小数。
解法思路:
- 处理正负号
- 计算整数部分
- 计算小数部分,使用哈希表记录余数位置检测循环节
class Solution:
def fractionToDecimal(self, numerator: int, denominator: int) -> str:
if numerator == 0:
return "0"
result = []
if (numerator < 0) ^ (denominator < 0):
result.append("-")
num = abs(numerator)
den = abs(denominator)
result.append(str(num // den))
remainder = num % den
if remainder == 0:
return "".join(result)
result.append(".")
remainder_map = {}
while remainder != 0:
if remainder in remainder_map:
result.insert(remainder_map[remainder], "(")
result.append(")")
break
remainder_map[remainder] = len(result)
remainder *= 10
result.append(str(remainder // den))
remainder %= den
return "".join(result)
数论算法实战技巧
1. 模运算性质应用
2. 素数测试优化策略
方法 | 原理 | 适用场景 |
---|---|---|
试除法 | 检查2到√n的因数 | 小范围素数判断 |
Miller-Rabin | 概率性素数测试 | 大数素数判断 |
AKS算法 | 确定性多项式时间 | 理论证明 |
3. 组合数计算与模运算
def nCr_mod(n: int, r: int, mod: int) -> int:
if r < 0 or r > n:
return 0
if r == 0 or r == n:
return 1
# 预计算阶乘和逆元
fact = [1] * (n + 1)
inv_fact = [1] * (n + 1)
for i in range(1, n + 1):
fact[i] = fact[i-1] * i % mod
inv_fact[n] = pow(fact[n], mod-2, mod)
for i in range(n, 0, -1):
inv_fact[i-1] = inv_fact[i] * i % mod
return fact[n] * inv_fact[r] % mod * inv_fact[n-r] % mod
高级数论问题解析
1. 中国剩余定理(Chinese Remainder Theorem)
问题场景:解决同余方程组
x ≡ a₁ (mod m₁)
x ≡ a₂ (mod m₂)
...
x ≡ aₖ (mod mₖ)
解法模板:
def crt(a_list, m_list):
M = 1
for m in m_list:
M *= m
result = 0
for a, m in zip(a_list, m_list):
M_i = M // m
inv = pow(M_i, -1, m)
result = (result + a * M_i * inv) % M
return result
2. 原根与离散对数
原根定义:模m下的原根g满足g^1, g^2, ..., g^(φ(m))模m两两不同
def find_primitive_root(p):
if p == 2:
return 1
factors = prime_factors(p-1)
for g in range(2, p):
is_primitive = True
for factor in factors:
if pow(g, (p-1)//factor, p) == 1:
is_primitive = False
break
if is_primitive:
return g
return -1
性能优化与实战建议
1. 算法选择策略
2. 内存优化技巧
- 使用位图代替布尔数组(8倍空间节省)
- 分块处理大数据集
- 利用数学性质减少计算量
3. 常见陷阱与调试技巧
- 整数溢出:使用Python自动处理大整数,其他语言注意使用long类型
- 边界条件:特别注意0和1的处理
- 负数处理:模运算中负数的处理需要特别注意
- 循环检测:使用哈希表记录状态避免无限循环
总结与进阶学习
通过本文的系统学习,你已经掌握了LeetCode数论算法的核心知识和实战技巧。数论作为算法竞赛和面试中的重要组成部分,需要不断的练习和总结。
下一步学习建议:
- 刷完doocs/leetcode中所有数学标签的题目
- 学习更高级的数论算法:FFT、NTT、生成函数等
- 参加算法竞赛实战锻炼
- 阅读《具体数学》、《算法导论》等经典著作
记住,数论算法的学习是一个循序渐进的过程,多思考数学背后的原理,而不仅仅是记忆模板代码。祝你算法学习之路顺利!
如果觉得本文对你有帮助,请点赞收藏支持,欢迎关注后续更多算法精讲文章!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考