当前位置: 首页 > news >正文

【LeetCode 每日一题】1414. 和为 K 的最少斐波那契数字数目

Problem: 1414. 和为 K 的最少斐波那契数字数目

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O((log K)^2) 或 O(log K)
    • 空间复杂度:O(log K)

整体思路

这段代码的目的是找到表示一个给定整数 k 所需的最少斐波那契数的数量。这里的斐波那契数是指不重复的、标准的斐波那契数列中的数(通常从 F_1=1, F_2=1 开始)。例如,k=7 可以表示为 5+2,所以需要 2 个斐波那
契数。

该算法采用了一种 贪心策略 (Greedy Strategy),并结合了 递归 (Recursion) 来实现。

  1. 核心贪心思想 (基于 宰克endorf定理)

    • 该算法的正确性基于一个名为 宰克endorf定理 (Zeckendorf’s theorem) 的数学定理。该定理指出,任何正整数都可以唯一地表示为不相邻的斐波那契数的和。
    • 这个定理的一个重要推论是,要找到表示 k 的最少数量的斐波那契数,我们可以采用贪心策略:
      1. 首先,找到小于或等于 k 的最大斐波那契数,我们称之为 fib_max
      2. fib_max 选入我们的和中。
      3. 然后,对剩余的数 k - fib_max 重复这个过程。
    • 由于斐波那契数列的性质 (F_n < F_{n+1} < 2 * F_n),可以证明这种贪心选择总是最优的,并且不会选择到相邻的斐波那契数。
  2. findMinFibonacciNumbers (递归主函数)

    • 这个函数实现了上述的贪心策略。
    • 基准情形 (Base Case): if (k == 0) { return 0; }。当 k 减为 0 时,说明我们已经用斐波那契数完全表示了原始的 k,此时不再需要任何斐波那契数,返回 0。
    • 递归步骤:
      • maxFibonacci(k): 调用一个辅助函数,找到小于或等于当前 k 的最大斐波那契数。
      • k - maxFibonacci(k): 从 k 中减去这个最大的斐波那契数,得到剩余需要表示的数。
      • findMinFibonacciNumbers(...): 对这个剩余的数进行递归调用,求解表示它所需的最少斐波那契数数量。
      • ... + 1: 将递归调用的结果加 1。这个 +1 代表我们当前选择的那个 maxFibonacci(k)
  3. maxFibonacci (辅助函数)

    • 这个函数的功能是找到小于或等于 n 的最大斐波那契数。
    • 它通过一个 while 循环,从 a=1, b=1 开始,迭代地生成斐波那契数列 (a, b, a+b, …)。
    • 循环的条件是 while (b <= n)
    • 当循环结束时,b 刚刚超过了 n,而 a 正好是最后一个小于或等于 n 的斐波那契数。因此,返回 a

完整代码

class Solution {/*** 计算表示整数 k 所需的最少斐波那契数的数量。* @param k 目标正整数* @return 最少的斐波那契数数量*/public int findMinFibonacciNumbers(int k) {// 基准情形:如果 k 已经是 0,则不需要任何斐波那契数。if (k == 0) {return 0;}// 贪心选择:// 1. 找到小于或等于 k 的最大斐波那契数。int maxFib = maxFibonacci(k);// 2. 对剩余部分 k - maxFib 进行递归求解,//    并将当前选择的这个斐波那契数 (计为1) 加入结果。return findMinFibonacciNumbers(k - maxFib) + 1;}/*** 辅助函数:找到小于或等于 n 的最大斐波那契数。* @param n 上限值* @return 小于或等于 n 的最大斐波那契数*/public int maxFibonacci(int n) {// 初始化斐波那契数列的前两项 (F_1=1, F_2=1)int a = 1;int b = 1;// 循环生成斐波那契数,直到 b 超过 nwhile (b <= n) {int temp = a + b; // 计算下一项a = b;            // 更新 ab = temp;         // 更新 b}// 当循环结束时,b 是第一个大于 n 的斐波那契数,// a 则是最后一个小于或等于 n 的斐波那契数。return a;}
}

时空复杂度

  • K 是输入值。

时间复杂度:O((log K)^2) 或 O(log K)

  1. maxFibonacci(n) 的复杂度

    • 斐波那契数列是指数级增长的。第 m 个斐波那契数 F_m 大约是 φ^m / sqrt(5),其中 φ 是黄金比例 (约1.618)。
    • 因此,要生成一个值达到 n 的斐波那契数,需要的迭代次数与 log(n) 成正比。
    • 所以,maxFibonacci(n) 的时间复杂度是 O(log n)
  2. findMinFibonacciNumbers(k) 的复杂度分析

    • 该函数是递归的。我们需要分析递归的深度和每次递归调用的开销。
    • 递归深度:每次递归,k 的值都会减去一个 maxFibonacci(k)。由于斐波那契数列的性质,k - maxFibonacci(k) < k / 2 并不总是成立,但可以证明 k - maxFibonacci(k) 会显著减小。递归的深度也大致是 O(log K) 级别。
    • 每次递归的开销:在每次 findMinFibonacciNumbers 调用中,都会调用一次 maxFibonacci
    • 简单分析 (上界):递归深度 O(log K),每次开销 O(log K),总时间复杂度为 O(log K * log K) = O((log K)^2)
    • 更精确的分析:可以预先生成所有小于等于 K 的斐波那契数并存储起来。这样,每次贪心选择就变成了在列表中进行二分查找 (O(log(log K))),或者直接线性查找。如果预先生成斐波那契数(耗时 O(log K)),然后进行贪心选择,总时间可以优化到 O(log K)。对于当前代码,O((log K)^2) 是一个更贴切的描述。

综合分析
当前递归实现的时间复杂度为 O((log K)^2)

空间复杂度:O(log K)

  1. 主要存储开销
    • 该算法是递归的,主要的额外空间开销来自于递归调用栈
    • 如上文分析,递归的最大深度与 log K 成正比。
  2. 辅助变量:在每个函数调用中,只使用了几个基本类型的变量,占用 O(1) 空间。

综合分析
算法所需的额外空间由递归栈深度决定。因此,其空间复杂度为 O(log K)

http://www.dtcms.com/a/561413.html

相关文章:

  • 怎么用一个主机做多个网站制作网站报价单
  • 5、webgl基本概念 + 绘制多边形 + 绘制圆 + 绘制圆环
  • 触摸屏网站如何做电子商务网站建设清华大学
  • 北京做网站的大公司惠阳网站建设
  • 网站开发做什么简单wordpress 自动发卡
  • 毕业设计做网站教程深圳app定制开发多少钱
  • 4.2【2020统考真题】
  • 4.2【2022统考真题】
  • 13.C++:继承
  • 做我的世界壁纸网站VPS wordpress 教程
  • 扒下来的网站怎么做修改php做网站访问记录
  • jxWebUI--日期时间选择框
  • Linux防火墙配置:iptables与firewalld使用指南(附案例)
  • 毕业设计网站开发类题目济南营销型网站建设贵吗
  • 网站服务器维护价格wordpress主页链接失效
  • 销售网站建设考核指标旅游网站开发目的6
  • 路由器端口镜像的配置与实验(eNSP)
  • vagrant+virtualBox使用记录
  • c++:析构与异常——noexcept的隐形爆炸
  • JavaEE多线程进阶
  • 网站建设结课总结如何在亚马逊开店流程及费用
  • 学习网页制作的网站如何修改网站源文件
  • 停车场管理|停车预约管理|基于Springboot的停车场管理系统设计与实现(源码+数据库+文档)
  • 计算机网络---ICMP协议(Internet Control Message Protocol,互联网控制消息协议)
  • 网站如何做淘宝客网站做要钱
  • 做公司网站需要什么资料开源手机网站系统
  • 成都网站优化公司哪家好南京哪家网络公司做网站优化好
  • Java 通配符
  • java-learn(9):常见算法,collection框架
  • 海口网站建设维护网校 039 网站建设多少钱