斐波那契查找Java 实现 + 完整思路

一、算法思路

1. 前置知识:斐波那契数列

\(F0=0,\ F1=1,\ Fn=Fn-1+Fn-2\) {0,1,1,2,3,5,8,13,21...}

2. 核心思想

二分查找:使用 除法 分割区间 mid = (left+right)/2 插值查找:使用 比例公式 斐波那契查找:利用 ** 斐波那契黄金分割比例(0.618)** 分割区间 公式: \(mid = left + Fk-1 - 1\)

把数组长度扩充至 斐波那契数 F k-1。 区间划分逻辑: 总长度 \(Fk-1\) 分为两部分:

  • 左段长度:\(Fk-1-1\)
  • 右段长度:\(Fk-2-1\)

优势:全程只有加减法,没有乘除运算,早期硬件环境效率更高;现代工程很少使用,面试常考原理。

3. 条件限制

  1. 数组升序有序
  2. 需要将原数组扩容到长度 = \(Fk-1\),不足的位置用数组最后一个元素填充
  3. 不断缩小 k 值,直到找到目标

4. 查找流程

  1. 构建斐波那契数列,找到最小 k,满足 \(Fk-1 \ge arr.length\)
  2. 创建临时数组 temp,扩容至 \(Fk-1\),空位填充数组末尾最大值
  3. 初始化 left=0, right=arr.length-1
  4. 循环条件 left <= right && k>0
    • 计算 mid = left + F[k-1] - 1
    • 三种判断: ① temp[mid] == target
      • 如果mid < arr.length,返回 mid;否则是扩容填充位置,返回arr.length-1temp[mid] > target:目标在左侧,k = k - 1temp[mid] < target:目标在右侧,left = mid + 1,k = k - 2
  5. 未找到返回 -1

原理记忆:左区间占 F k-1-1 → k-1;右区间占 F k-2-1 → k-2

二、完整 Java 代码(迭代版,面试标准写法)

java

运行

复制代码
public class FibonacciSearch {

    /**
     * 斐波那契查找
     * @param arr 升序有序数组
     * @param target 查找目标
     * @return 索引,找不到返回-1
     */
    public static int fibonacciSearch(int[] arr, int target) {
        if (arr == null || arr.length == 0) {
            return -1;
        }
        int left = 0;
        int right = arr.length - 1;

        // 斐波那契数组,预先定义
        int[] F = new int[40];
        F[0] = 0;
        F[1] = 1;
        // 生成斐波那契数列
        for (int i = 2; i < F.length; i++) {
            F[i] = F[i - 1] + F[i - 2];
        }

        // 找到最小的k,满足 F[k]-1 >= arr.length
        int k = 1;
        while (F[k] - 1 < arr.length) {
            k++;
        }

        // 扩容临时数组,长度 F[k]-1,空缺位置填充数组最后一个元素
        int[] temp = new int[F[k] - 1];
        System.arraycopy(arr, 0, temp, 0, arr.length);
        for (int i = arr.length; i < temp.length; i++) {
            temp[i] = arr[right];
        }

        // 开始查找
        while (left <= right && k > 0) {
            int mid = left + F[k - 1] - 1;

            if (temp[mid] > target) {
                // 目标在左区间 [left,mid-1],长度 F[k-1]-1
                k = k - 1;
            } else if (temp[mid] < target) {
                // 目标在右区间 [mid+1,right],长度 F[k-2]-1
                left = mid + 1;
                k = k - 2;
            } else {
                // 找到目标
                if (mid <= right) {
                    return mid;
                } else {
                    // mid落在扩容填充区域,真实位置是数组最后一位
                    return right;
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 5, 8, 11, 16, 22, 30};
        int target1 = 11;
        int target2 = 100;

        System.out.println(target1 + " 的索引:" + fibonacciSearch(arr, target1));
        System.out.println(target2 + " 的索引:" + fibonacciSearch(arr, target2));
    }
}

三、三大有序查找算法面试对比总结

表格

算法 mid 计算公式 要求 优点 缺点
二分查找 mid = left+(right-left)/2 有序 稳定,适用所有有序数组 需要除法运算
插值查找 \(mid=left+\frac{target-arrleft}{arrright-arrleft}(right-left)\) 有序 + 数据均匀分布 均匀数据下平均速度更快 不均匀时退化 O (n),存在除零风险
斐波那契查找 mid = left + Fk-1-1 有序 仅加减法,无乘除,早期硬件友好 需要扩容、生成斐波那契数组,现代极少使用

面试高频问答

  1. 斐波那契查找为什么不用除法? 答:依靠黄金分割比例拆分区间,只做加减,在计算机底层加减法运算速度优于乘除。
  2. 为什么扩容数组并且填充末尾元素? 答:保证数组长度等于 F k-1,严格满足斐波那契区间分割模型;填充最大值防止扩容区域干扰比较。
  3. 实际开发用哪个? 日常开发优先二分查找;插值、斐波那契更多属于笔试面试考点,工程几乎不用。
相关推荐
星恒随风1 小时前
C++ 继承进阶:默认成员函数、多继承、虚继承与组合设计
开发语言·c++·笔记·学习
祐樹1 小时前
1987年5月25日下午15-17点出生性格、运势和命运
java
Yeauty1 小时前
用 Whisper 转录前,你不用再离开 Rust
开发语言·rust·ffmpeg·音视频·视频
电子云与长程纠缠1 小时前
UE中使用TGuardValue与TInlineComponentArray数据结构
开发语言·数据结构·学习·ue5·游戏引擎
正儿八经的少年1 小时前
Spring 事务保证数据一致性
java·数据库·spring
Lakers-242 小时前
1987年5月29日晚上19-21点出生性格、运势和命运
java
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题 第194题】【08_Kafka篇】第10题:简述 Kafka 的 Rebalance 机制?
java·kafka·消费者组·rebalance·分布式消息队列
呜喵王阿尔萨斯2 小时前
C/C++ const -- 多义混乱
c语言·开发语言·c++
__log2 小时前
幂等性设计:从“重复提交“到“稳如磐石“的系统防护
java·开发语言·spring boot