一.试除法
首先我们要了解,所有大于1的自然数都能进行质因数分解。试除法作用如下:
质数判断
示例:判断17是否为质数,需试除2到4(因√17≈4.12),发现无法整除,故17是质数
试除法通过验证一个数是否能被小于它的数(一般是用2到用根号x)整除来判断其是否为质数。根据定义,质数只能被1和自身整除。bool isPrime(int n) { if (n <= 1) return false; for (int i=2; i<=n/i; i++) if (n%i == 0) return false; return true; }
因数分解
若目标数是合数,试除法可找到其所有质因数。例如,分解28时,依次试除2、3、5等质数,最终得到质因数2和7#include <stdio.h> #include <math.h> void primeFactors(int n) { // 处理2的因数 while (n % 2 == 0) { printf("2 "); n /= 2; } // 处理奇数因数(3到√n) for (int i = 3; i <= sqrt(n); i += 2) { while (n % i == 0) { printf("%d ", i); n /= i; } } // 处理剩余的大于2的质数 if (n > 2) { printf("%d", n); } } int main() { int num = 315; printf("质因数分解结果:"); primeFactors(num); // 输出:3 3 5 7 return 0; }
二.最大公约数 和最小公倍数
最大公约数采用辗转相除法。我们先介绍一下辗转相除法
我们假设大的数为a,小的数为b,求a和b的最大公约数c。
我们用几何理解,我们把a,b看成俩条线。
c是最大公约数,由于定义可得c必须要满足c*n(n为任意正整数)==b, c*m(m也为任意正整数)==a。简单来说就是可以用正整数的c长度将b,a覆盖。
我们再用二维的视角来看将a和b看成矩形的俩条边。由于要用用正整数的c长度将b,a俩条边覆盖,就是找到一个最大的正方形将这个矩形覆盖。
在我们预先构造的矩形中,我们以短边b构造正方形,然后再去判断用多个正方形能不能在大矩形中放满。这里用取余判断。不能放满的话,我们再在剩余的空间重复判断,剩余空间能放满的话,以短边b构造的正方形肯定可以放满,可以看下面的图理解,6*10的剩余部分能放满,说明这个正方形边长能叠加到10,那么以b为边的正方形肯定可以铺满的。
public static int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
最小公倍数
最小公倍数(a,b)=a*b/(a和b的最大公约数)。
最好先除再乘防止超过范围。
Lcm(a,b)=a/(gcd(a,b))*b;
三.组合数
这里我们用递推公式计算
可以理解成从n个苹果里面取m个苹果 ,我们先扔掉一个苹果不选,从n-1里苹果个取m个苹果,我们再捡回来扔的苹果并算作m中的一个,并计算缺少的情况,从n-1个苹果中取出m-1个苹果。
对于代码,为了避免重复计算,如下面的红色区域(4,3)重复计算了,我们可以做个记忆化,对于算过的数我们记下。
int v[100][100] = { 0 };//v[n][m];
int dfs(int n,int m)
{
if (m==0||m == n)
{
return 1;
}
if (v[n][m] != 0)
{
return v[n][m];
}
else
{
int sum = dfs(n - 1, m) + dfs(n - 1, m - 1);
v[n][m] = sum;
return sum;
}
}
int main()
{
cout<<dfs(5, 3);
}
四.质数筛
就是给你一个数n,找出1-到的所有质数。
我们可以用试除法一个个找,但是时间复杂度为O(n*n),不太好。
推荐使用埃氏筛(埃拉托斯特尼筛法),很好理解。
原理概况就是,用一个数组表示1到n,我们先假设0到n都是质数,数组的值都是1,然后遍历该质数数组,从2开始,将2的倍数都标记为0。再找到下一个质数,将质数的倍数全部标记为0。就像一个筛子一样,详细原理可以看下面这位大佬,讲解的很详细。
原文链接:https://blog.csdn.net/Yuki_fx/article/details/115103663
#include <iostream>
#include <vector>
#include <cmath>
std::vector<int> sieveOfEratosthenes(int n) {
if (n < 2) return {}; // 处理n < 2的情况
std::vector<bool> isPrime(n + 1, true);
isPrime[0] = isPrime[1] = false;
for (int p = 2; p <= n/p; ++p) {
if (isPrime[p]) {
// 标记p的倍数,从p^2开始,步长为p
for (int multiple = p * p; multiple <= n; multiple += p) {
isPrime[multiple] = false;
}
}
}
// 收集所有质数
std::vector<int> primes;
for (int i = 2; i <= n; ++i) {
if (isPrime[i]) primes.push_back(i);
}
return primes;
}
int main() {
int n;
std::cin >> n;
std::vector<int> primes = sieveOfEratosthenes(n);
std::cout << "Primes up to " << n << " are:\n";
for (int prime : primes) {
std::cout << prime << " ";
}
std::cout << "\n";
return 0;
}
五.快速幂
例如求x的n次方,我们可以先求sum=x的2/n次方,再只要求出sum*sum就行,更加快速。需要注意的是如果是奇数要多乘一个x。如2的6次方=2的3次方*2的3次方*2。
int quick(int x,int n)
{
if (n == 1)
{
return x;
}
if (n == 0)
{
return 1;
}
int middle = n / 2;
int sum = quick(x, middle);
if (n % 2 == 0)
{
return sum * sum;
}
else
{
return sum * sum * x;
}
}