一句话算法
对数回答的是:底数要乘多少次,才能得到目标数。
问题模型
对数是指数运算的逆运算。
若:
其中 a>0,a=1,b>0,则:
x=logab读作“以 a 为底 b 的对数”。
“对数”
logab 表示把 a 连乘多少次可以得到 b。
在算法中,最常见的是以 2 为底的对数:
它表示从 1 开始,每次翻倍,翻多少次能到达 n 附近。
核心直觉
指数是“不断放大”:
1, 2, 4, 8, 16, 32, ...
对数是反过来问:
32 是 2 翻倍多少次得到的?
答案是:
25=32⇒log232=5所以当一个算法每一步都把规模减半时:
n -> n/2 -> n/4 -> n/8 -> ...
它通常只需要约 log2n 步。
基本性质
由定义 ax=b⟺x=logab 可以直接得到:
loga1=0因为 a0=1。
logaa=1因为 a1=a。
loga(ax)=x因为对数和指数互为逆运算。
alogab=b因为 logab 本来就是让 a 变成 b 的指数。
运算法则
下面默认 a>0,a=1,M>0,N>0。
乘法变加法
loga(MN)=logaM+logaN证明:
设:
x=logaM,y=logaN则:
M=ax,N=ay所以:
MN=axay=ax+y两边取以 a 为底的对数:
loga(MN)=x+y=logaM+logaN除法变减法
logaNM=logaM−logaN证明:
设:
x=logaM,y=logaN则:
NM=ayax=ax−y两边取对数:
logaNM=x−y=logaM−logaN幂次提到前面
loga(Mk)=klogaM证明:
设:
x=logaM则:
所以:
Mk=(ax)k=akx两边取对数:
loga(Mk)=kx=klogaM由除法公式还能得到:
logaN1=−logaN换底公式
不同底数的对数可以互相转换:
logab=logcalogcb其中 c>0,c=1。
证明:
设:
x=logab则:
两边取以 c 为底的对数:
logc(ax)=logcb使用幂次公式:
xlogca=logcb所以:
x=logcalogcb代回 x=logab:
logab=logcalogcb常用推论:
logab=logba1算法中的常用推论
每次减半需要多少步
若一个规模为 n 的问题,每一步都变成原来的一半,那么经过 k 步后规模大约是:
当规模降到 1 时:
2kn≤1等价于:
所以:
k≥log2n因此二分查找、倍增跳跃、线段树高度等问题,经常出现 O(logn)。
二进制位数
一个正整数 n 的二进制位数是:
⌊log2n⌋+1因为若:
2k≤n<2k+1则最高位的下标是 k,二进制位数是 k+1。
乘法规模转加法规模
若一个数量是很多因子的乘积:
X=a1a2⋯am取对数后:
logX=loga1+loga2+⋯+logam这在概率、组合计数、大数比较中常见:当乘积太大不能直接存时,可以比较对数和。
复杂度分析
对数本身是数学工具,不是某个固定算法。
在复杂度分析中:
-
O(logn) 通常表示问题规模按固定比例缩小。
-
O(nlogn) 常见于排序、分治、线段树批量操作。
-
换底只差一个常数,因此复杂度里通常不写底数:
logan=logbalogbn其中 logba 是常数。
代码实现
本文不提供代码模板。竞赛中若需要计算实数对数,可以使用 C++ <cmath> 中的 log、log2、log10。若要计算任意底:
1
2
3
double log_base(double a, double b) {
return log(b) / log(a);
}
注意浮点误差:如果题目只需要整数的 ⌊log2n⌋,通常优先使用二进制位运算或预处理 Log 数组,而不是浮点对数。
测试用例
基础计算
log232=5因为:
换底
log28=log102log108=3二分步数
若 n=100,每次减半:
100 -> 50 -> 25 -> 13 -> 7 -> 4 -> 2 -> 1
需要约 7 步,而:
⌈log2100⌉=7应用分类详解
对数的本质是描述“指数增长的反方向”。看到翻倍、减半、树高、二进制位数、大乘积比较时,都应该想到对数。
一、复杂度分析
典型模式: 每一步把规模除以固定常数。
识别信号: 出现“折半”“翻倍”“倍增”“树高”。
核心建模: 问题规模经过 k 步变为 n/2k,令它小于等于 1,得到 k=O(logn)。
| 应用场景 |
经典题目 |
核心思路 |
| 二分查找 |
有序数组查找 |
每次排除一半 |
| 倍增 LCA |
树上祖先查询 |
每次跳 2k 级 |
| 线段树 |
区间查询修改 |
树高约为 log2n |
二、二进制与位数
典型模式: 需要知道一个数最高位在哪里。
识别信号: 出现“最高位”“二进制长度”“不超过 n 的最大 2k”。
核心建模: 最高位 k 满足 2k≤n<2k+1,所以 k=⌊log2n⌋。
三、大数比较
典型模式: 两个乘积或幂太大,不能直接计算。
识别信号: 出现很多数相乘、指数很大、只需比较大小。
核心建模: 对乘积取对数,把乘法变成加法,比较对数和。
经典例题
1. 二分查找最多比较次数
长度为 n 的有序数组,每次比较后剩下一半候选,最多需要 ⌈log2n⌉ 级别的比较。
2. ST 表中的 Log 数组
预处理 Log[i] = floor(log2(i)),查询区间长度 len 时用 2k 覆盖,其中 k=⌊log2len⌋。
3. 大幂比较
比较 ab 和 cd 的大小时,可以比较:
和:
避免直接计算巨大整数。
参考
- 本书二分查找章节:
base/binary_search/index.md
- 本书 ST 表章节:
base/sparse_table/index.md