没有合适的资源?快使用搜索试试~ 我知道了~
三峡大学算法设计与分析论文-倍增思想在算法运用与实现
需积分: 5 1 下载量 19 浏览量
2024-01-13
19:08:27
上传
评论
收藏 382KB DOCX 举报
温馨提示
试读
24页
1.引言 我们常常会遇到这样的问题:给定一个有序数组a\left[N\right],需要查找出最大的不小于某个数的数字或者查找出最小的大于某个数的数字,通常的朴素做法是从头到尾遍历一遍,那么时间复杂度就是O\left(n\right)。 如果我们用倍增的思想去思考,假设我们有一个增长长度∆l和一个已经确定的长度l,我们只需要确定a∆l+l是否满足条件就行,若满足就让∆l × 2;否则l缩小范围,这样时间复杂度就是O\left(logn\right) 。肯定会有人说用二分查找,时间复杂度也是O\left(logn\right),二者有些相似,但二分是值对应区间,倍增是区间对于值。 如果我们将问题升级一下,数组a\left[N\right]并不是有序的,并且有T次查询,每次都是在\left[l,r\right]的区间去查找我们所要求的数,如果每次都去暴力求解每次询问,从头到尾去遍历,时间复杂度就是O\left(T\times\left(l-r\right)\right),并且区间可能会重复,包含,会很浪费时间,可能面对我们的只有Time\ Limit\ Exceeded了。那有没有一种算法
资源推荐
资源详情
资源评论
本科课程论文
倍增思想在算法运用与实现
课程名称: 算法设计与分析 。
学 号: 。
姓 名: 。
专 业: 计算机科学与技术 。
任课教师: 王俊英 。
。
课程论文评价结果
课程
目标
占比
主要考核内容
评分标准
得分
1
30%
能对所选择的算法
方案的优缺点进行
评价。
A(24-30):能对算法方案作出全面的评价;
B(18-23):对算法方案的评价比较全面;
C(0-17):算法方案评价中出现较多错误。
2
30%
能对算法的关键环
节的复杂性进行恰
当的分析。
A(24-30):能正确进行复杂性分析;
B(18-23):复杂性分析基本正确;
C(0-17):复杂性分析中出现较多错误。
3
20%
能通过文献研究,表
述并分析问题所涉
及的算法。
A(16-20):能正确理解、表述和评价文献中的
算法;
B(12-15):对文献中算法的理解和评价基本
正确;
C(0-11):对文献中算法的评价出现较多错误。
4
20%
能通过文献研究,跟
踪算法新的研究进
展。
A(16-20): 能检索并学习最新的算法;
B(12-15): 基本能检索并学习到较新的算法;
C(0-11): 检索和学习新算法的能力不足。
总 分
100
论文提交时间: 2023 年 5 月 13 日
倍增思想在算法运用与实现
1.引言
我们常常会遇到这样的问题:给定一个有序数组
a
[
N
]
,需要查找出最大的不
小于某个数的数字或者查找出最小的大于某个数的数字,通常的朴素做法是从头
到尾遍历一遍,那么时间复杂度就是
O
(
n
)
。
如果我们用倍增的思想去思考,假设我们有一个增长长度
∆
l
和一个已经确
定的长度
l
,我们只需要确定
a
∆
l
+
l
是否满足条件就行,若满足就让
∆
l
×
2
;
否则
l
缩小范围,这样时间复杂度就是
O
(
logn
)
。肯定会有人说用二分查找,时间
复杂度也是
O
(
logn
)
,二者有些相似,但二分是值对应区间,倍增是区间对于值。
如果我们将问题升级一下,数组
a
[
N
]
并不是有序的,并且有
T
次查询,每次都
是在
[
l,r
]
的区间去查找我们所要求的数,如果每次都去暴力求解每次询问,从
头到尾去遍历,时间复杂度就是
O
(
T
×
(
l
―
r
)
)
,并且区间可能会重复,包含,会
很浪费时间,可能面对我们的只有
Time Limit Exceeded
了。那有没有一种算法经
过处理,可以在
O
(
1
)
时间去回答我们的查询呢,这就需要倍增的思想去处理问题
了。
2.算法原理
倍增算法是一种基于分治和递归思想的算法,用于解决一些数论、图论等方
面的问题,它可以将一些线性的处理转化为对数级的处理,从而优化时间复杂度。
倍增算法的核心思想是预处理一些规模为
2
的幂次的子问题,然后将原问题拆分
成这些子问题的组合。倍增算法在很多领域都有应用,例如快速幂、最近公共祖
先(LCA)、区间极值(RMQ)等。本文将介绍倍增算法的原理、实现和应用。
倍增算法在具体的实现过程中,需要根据具体的问题来设计不同的算法框
架和算法特征。
简单说,就是对于一种操作
f
(
x
)
,我们要去求
f
n
(
x
)
,并不是逐个去求
f
1
(
x
)
,
f
2
(
x
)
,
f
3
(
x
)
,
······
,
f
n
(
x
)
; 而 是 通 过 求
f
1
(
x
)
,
f
2
(
x
)
,
f
4
(
x
)
,
f
8
(
x
)
,
······
,
f
2
k
(
x
)
,来加速求解
f
n
(
x
)
。在相同的变化规则下加速状态转移,
这样我们的时间复杂度就从
O
(
n
)
→
O
(
logn
)
了。
倍增算法主要分为三类:快速幂,
RMQ
(
st
表
)
,
LCA
。
2.1 二进制
既然是预处理一些规模为
2
的幂次的子问题,那么首先我们的了解一下二进
制。那么如何去打印一个数的二进制呢?
我们可以这样表示一个数
n
:
n
=
𝑎
𝑘
×
2
𝑘
+
𝑎
𝑘
―
1
×
2
𝑘
―
1
+
𝑎
𝑘
―
2
×
2
𝑘
―
2
+
······
+
𝑎
0
×
2
0
现在只需要求得
𝑎
𝑘
等于
1
,还是
0
;这就需要利用
&
运算判断最低位是几。
最低位为
1
:
𝑛
&
1
>
0
,为
0
:
𝑛
&
1
=
0
。
9
&
1
=
(1001)_2
&
(0001)_2
=
(0001)_2
>
0
8
&
1
=
(1000)_2
&
(0001)_2
=
(0000)_2
=
0
那么其他为怎么办呢?我们只须将
n
右移或者
1
左移就行了,上一位变成最低位。
我们以 32 位数为例,
for(int i = 31; i >= 0; i --){ //
从高位到低位逐位判断二进制数的每一位
if(n & 1 << i) //
判断
n
的第
i
位是否为
1
cout << 1; //
如果是
1
,输出
1
else
cout << 0; //
如果是
0
,输出
0
}
2.2 快速幂
即快速的求
a
b
%
p
,这将如何去处理一些规模为
2
的幂次的子问题。
2.2.1 暴力实现方式
通过求
f
1
(
x
)
,
f
2
(
x
)
,
f
3
(
x
)
,
······
,
f
n
(
x
)
最后 mod p 来实现。
只需令初始
res
=
1
,通过循环
b
次,不断
r
𝑒𝑠
=
𝑟𝑒𝑠
×
𝑎
最后
%q
就可实现。
long long res = 1;
while(b --){
res = res * a % q;
}
2.2.2 快速幂
通过
f
1
(
x
)
,
f
2
(
x
)
,
f
4
(
x
)
,
f
8
(
x
)
,
······
,
f
2
k
(
x
)
来实现的。
预处理具体思路:
① 预处理出
a
2
0
,
a
2
1
,
a
2
2
,
a
2
3
,…,
a
2
logb
,这 b 个数。
② 由于一个数的二进制是唯一的,我们只需要在将
a
b
用
a
2
0
,
a
2
1
,
a
2
2
,
a
2
3
,…,
a
2
logb
这 b 种数来组合,
即
a
b
=
a
2
x
1
+
x
2
+
x
3
+
…
+
x
n
=
a
2
x
1
×
a
2
x
2
×
a
2
x
3
×
…
×
a
2
x
n
用二进制表示,也说
就是把
b
用二进制表示出来。
③ 最后判断
x
1
,
x
2
,
x
3
,
x
4
,…,
x
n
的值,为 1 就乘到结果里面,为 0 就不乘
到结果里面,即判断
b
的二进制中哪一位为 1。
通过
①
②③我们就对
𝑎
𝑏
处理成一些规模为 2 的幂次的子问题。
实现:在初始时
a
=
a
,
在每判断一位
x
n
(从
b
的低位开始判断)后执行
a
=
a
×
a
的操作,
a
就能成倍的增加;在判断
x
n
值是采用位运算,每次
用
b
&
1
来判断
b
的最低位是否为 1,若为 1,结果乘上此时的
a
;为 0,结果就不
乘,判断完后,将
b
向右移动一位(即
b
>
>
=
1
),使得上一位变为最低位。
LL quick_m(LL a, LL b, LL q)
{
LL res = 1;
while (b)
{
//
如果
b
的二进制位为
1
,则计算
res = res * a mod q
if (b & 1) res = res * a % q;
//
将
b
右移一位,等价于
b = b / 2
,
a
的平方取模
b >>= 1;
a = a * a % q;
}
return res;
}
对比:每个数据范围测 10 次,一次测试有 10 组数据
(为了方便测试 a,b 的指数级别一样,q 取定值
10
9
+
7
,时间单位:
𝜇
s
)
数据范围
(
𝑎,𝑏
)
快速幂
朴素算法
0
0
0
1
―
10
1065
1060
10
―
10
2
1075
1094
10
2
―
10
3
1072
1092
10
3
―
10
4
1080
1328
10
4
―
10
5
1067
2530
10
5
―
10
6
1078
7456
10
6
―
10
7
1195
52588
10
7
―
10
8
1112
505116
10
8
―
10
9
1079
4952771
· 朴素做法的思路:是先计算
𝑎
𝑏
,然后再对
𝑞
取模,即
(
𝑎
𝑏
)
% 𝑞
。该方法的时间复
杂度为
O
(
𝑏
)
,空间复杂度为
O
(
1
)
。
· 快速幂的思路是将指数
𝑏
转化成二进制数,根据指数的二进制位数分解幂次,
然后反复平方法计算出
𝑎
的幂次,从而得到
𝑎
𝑏
% 𝑞
。将
𝑏
看成 2 进制数,循环次数
变为
𝑏
的二进制位数,时间复杂度以此为
O
(
𝑙𝑜𝑔𝑏
)
,空间复杂度为
O
(
1
)
。
· 由于指数 b 可能非常大,使用朴素方法计算幂次需要执行大量的循环,导致
时间复杂度非常高。在指数非常大时,朴素算法所需的时间甚至是指数次的。而
快速幂算法通过将指数分解为二进制位数,将计算幂次的循环次数降低到 log b
级别,大大缩短了计算时间。此外,快速幂算法的空间复杂度较低,只需要常数
级别的存储空间。因此,快速幂算法更加高效。
不足:可能会出现整数溢出问题,在计算过程中,幂次不断增大,超过了计算机
所能表示的整数范围,导致整数溢出,计算结果错误;不支持负数幂,快速幂算
法只适用于正整数幂次,对于负数幂次无法做出响应;无法处理实数幂,快速幂
算法只适用于整数幂次,对于实数幂次无法做出响应。底数和模数必须互质,快
速幂算法的底数和模数必须互质,否则算法会失效。如果底数和模数不互质,需
要进行拆分或变换,增加了算法的复杂度。
剩余23页未读,继续阅读
资源评论
123456msk
- 粉丝: 300
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功