四、算法中的数学问题
数学是程序的基础,很多问题可以通过转换为数学问题而减少计算过程,从而减少算法的时间复杂度。另一方面,有一些程序利用了数学的计算公式及原理,这里对常见的数学问题进行总结和归纳。
1. 素数(质数)问题
素数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
素数的常见问题如下:
Q1.如何获得自然数n以内的全部素数 ?
常用的素数的检测方法为:埃拉托斯特尼筛法(埃氏筛)。该算法思路为:要得到自然数n以内的全部素数,必须把不大于
n
\sqrt n
n 的所有素数的倍数剔除,剩下的就是素数 。如,从2-25的自然数中找出所有素数。具体步骤如下:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/bce3c70638d5fb1c9ea660d7b32291fc.png)
class Solution {
public:
int countPrimes(int n) {
vector<bool> isAns(n+1,true);
int count=0;
for(int i=2;i<n;i++){
if(isAns[i]){
count++; //记录素数个数
for(int j=2;i*j<n;j++) //将当前素数的倍数剔除
isAns[i*j]=false;
}
}
return count;
}
};
🐟 Leetcode相关题目:① 204. 计数质数
2. 最大公约数与最小公倍数问题
两个数的最大公约数是指能同时整除它们的最大正整数。
Q1.如何计算两个数a,b的最大公约数 ?
① 辗转相除法
step1: 找到a,b两数的最小数(a≥b),用
a
÷
b
a÷b
a÷b,得
a
÷
b
=
q
1
.
.
.
r
1
a÷b=q_1...r_1
a÷b=q1...r1
step2: 若
r
1
=
0
r_1=0
r1=0,则最大公约数为b。
step3: 若
r
1
≠
0
r_1≠0
r1=0,计算
b
÷
r
1
b÷r_1
b÷r1,得
b
÷
r
1
=
q
1
.
.
.
r
2
b÷r_1=q_1...r_2
b÷r1=q1...r2
step4: 若
r
2
=
0
r_2=0
r2=0,则最大公约数为
r
1
r_1
r1。 否则,计算
r
1
÷
r
2
r_1÷r_2
r1÷r2…循环下去,直到可以整除为止。
如(a,b)=(32,14) -> 32÷14=2余4,14÷4=3余2,4÷2=0,所以(32,14)的最大公约数为2;
int getGcd(int a,int b){ //辗转相除,a/b
int gcd=0;
if(a<b){ //辗转相处
int temp=a;
a=b;
b=temp;
}
int mod=0;
while(b!=0){
mod= a%b; //求a/b的余数
a=b;
b=mod;
}
gcd=a; //最大公约数*/
return gcd;
}
② 更相减损法
“较大数” 减 “较小数”,循环,当两数相同时,相同的数即为“最大公约数”
如(a,b)=(32,14) -> 32-14=18,18-14=4,14-4=10,10-4=6,6-4=2,4-2=2,a=b=2,公约数为2;
int getGcd(int a,int b){
int gcd=0;
while(a!=b){ //更相减损法
if(a>b){
a=a-b;
}else{
b=b-a;
}
gcd=a; //最大公约数
}
}
(2). 如何计算两个数a,b的最小公倍数?
两个数a,b的最小公倍数=两数乘积÷两数最大公约数;
int getLcm(int a,int b){
return a*b/getGcd(a,b);
}
3. 分解质因数
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来,叫做分解质因数。如30=2×3×5 。分解质因数只针对合数。
求一个数分解质因数,要从最小的质数除起,一直除到结果为质数为止。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/7128f804f476a6d6649f6efa3b6e8112.png)
void getPrime(int n){
while(n>1){
for(int i=2;i<=n;i++){
if(n%i==0){
n=n/i;
cout<<i;
if(n!=1)
cout<<"*";
break;
}
}
}
cout<<endl;
}
4. 卡特兰数 Catalan
卡特兰数是组合数据中一个常在各种计数问题中出现的数列,其本质是一个数列。Catalan
数的定义为:Catalan
数的定义:令h(0)=1,Catalan
数满足递归式:
h
(
n
)
=
h
(
0
)
∗
h
(
n
−
1
)
+
h
(
1
)
∗
h
(
n
−
2
)
+
.
.
.
+
h
(
n
−
1
)
h
(
0
)
=
C
2
n
n
−
C
2
n
n
−
1
=
[
1
/
(
n
+
1
)
]
C
2
n
n
h(n)= h(0)*h(n-1) + h(1)*h(n-2) + ... + h(n-1)h(0) ={C_{2n}^{n}-C_{2n}^{n-1}} =[1/(n+1)]C_{2n}^{n}
h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)h(0)=C2nn−C2nn−1=[1/(n+1)]C2nn 卡特兰数应用:
① 进出栈问题:
若有1…n,n个整数顺序入栈,则有多少个不同的出栈顺序?
解:设k(k∈[1,n])
是最后出栈的数,则比k
先入栈且先出栈的有k-1
个数,共有h(k-1)
个方案;比k
晚入栈且早出栈的有n-k
个数,共有h(n-k)
个方案,一共有h(k-1)*h(n-k)
个方案。当k
取不同值时,产生的出栈序列是相互独立的,因此结果可以叠加,则结果为:h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)
② 二叉树构建方案问题:
有n个结点,总共能构成几种不同的二叉树?
解:采用中序遍历,根节点第k(k∈[1,n])
个被访问到,则根节点的左子树有k-1
个点,根节点的右子树有n-k
个点。求解过程与进出栈问题相同,结果为:h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0)
③ 凸多边形的三角形划分问题: