1. 斐波那契查找是什么
1.1 从二分查找说起
聊到有序数组的查找算法,绝大多数人第一反应就是二分查找:每次取数组中间位置,比较一次就能扔掉一半数据,时间复杂度稳定在 O(log n)。这个思路简单、直观,面试八股也爱考,所以很多人以为查找算法到这里就学完了。直到你翻开《数据结构》教材看到“斐波那契查找”这一节,才发现原来“分治”还可以换一种切法——不切正中间,而是按照黄金分割的比例去切。
斐波那契查找(Fibonacci Search),也叫黄金分割查找,是一种在有序数组中查找目标元素的算法。它和二分查找一样需要预先排序的数据,核心思想也是每轮比较后缩小搜索区间,但分割点的选择不用除法计算中点,而是借助斐波那契数列来确定。这个算法最吸引我的地方在于:它在理论上和二分查找一样是 O(log n) 的复杂度,但整个查找过程中没有乘除法运算,只有整数加减法。
如果你正在刷算法题、准备面试,或者单纯想加深对分治思想的理解,这个算法都值得花半小时搞明白。它算不上高频考点,但一旦被问到“除了二分查找你还会什么查找方式”,能讲清楚斐波那契查找的思路和实现,会显得你基础很扎实。
1.2 斐波那契查找的核心思路
先把斐波那契数列复习一遍。经典定义是:
F(0) = 1,F(1) = 1,F(k) = F(k-1) + F(k-2)。
所以数列长这样:1, 1, 2, 3, 5, 8, 13, 21, 34, 55...
斐波那契查找的思路是:假设当前搜索区间的长度是某个斐波那契数减一,也就是 len = F(k) - 1,那么把区间分成三部分:左边长度 F(k-1) - 1,右边长度 F(k-2) - 1,中间那个单独的元素就是分割点。用这个分割点去和目标值比较,不管结果是大于、小于还是等于,下一步要处理的区间长度都会再次落在“某个斐波那契数减一”的形式上,于是整个分治过程可以持续迭代下去。
这里有一个非常关键但教材往往一笔带过的细节:为什么区间长度必须是 F(k) - 1 而不是 F(k)?这是理解整个算法的钥匙。我在后面专门开一节展开讲,这里先记住结论——F(k) - 1 这种构造能让左右子区间的长度也保持同样的数学形式,从而保证迭代不会乱掉。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心原理:为什么公式里全是 -1
2.1 斐波那契数列与黄金分割的关系
斐波那契数列和黄金分割的关联很多人都听说过:当 k 趋向无穷时,相邻两项之比 F(k) / F(k-1) 会收敛到 0.618 的倒数,大约是 1.618,也就是黄金分割率。这意味着斐波那契数列天然携带黄金分割的比例信息。
二分查找每轮切 1/2,而斐波那契查找每轮切的位置大约是在整个区间的 0.618 处(或者说是从左侧起 0.382 处),这正好是黄金分割点。所以有些资料会把斐波那契查找直接叫做黄金分割查找。不过名字只是表象,真正重要的是这种切法下面的数学结构是否自洽。
我在理解这个算法的时候走过一段弯路:一开始以为斐波那契查找和黄金分割的关系是重点,把大量时间花在读黄金分割比例如何优美上,结果代码实现还是一头雾水。后来我才意识到,黄金分割只是帮助记忆和理解的背景知识,真正的核心是那个 -1 的数学构造。抓住了这个,代码就是顺理成章的事。
2.2 F(k)-1 的设计推导
现在仔细推导这个 -1。假设有序数组长度为 n,我们找一个 k 使得 F(k) - 1 >= n,然后就可以认为搜索区间长度是 F(k) - 1。分割点的下标取在区间起点加上 F(k-1) - 1 的位置:
mid = low + F(k-1) - 1
这样的话,整个区间被分成三段:左半段从 low 到 mid-1,右半段从 mid+1 到 high,加上 mid 这个比较点。
现在算一下左半段的长度:
mid - 1 - low + 1 = mid - low = F(k-1) - 1
再算右半段的长度:
high - (mid + 1) + 1 = high - mid
因为区间总长度是 F(k) - 1,所以:
high - low + 1 = F(k) - 1
high - mid = F(k) - 1 - (mid - low) = F(k) - 1 - (F(k-1) - 1) = F(k) - F(k
