Leetcode:1414. 和为 K 的最少斐波那契数字数目(贪心)

本文介绍了一种算法,如何找到和为给定整数k的所有斐波那契数中最少的使用次数。通过构建斐波那契数列并利用贪心策略,解决中等难度的编程问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

难度中等15收藏分享切换为英文接收动态反馈

给你数字 k ,请你返回和为 k 的斐波那契数字的最少数目,其中,每个斐波那契数字都可以被使用多次。

斐波那契数字定义为:

  • F1 = 1
  • F2 = 1
  • Fn = Fn-1 + Fn-2 , 其中 n > 2 。

数据保证对于给定的 k ,一定能找到可行解。

 

示例 1:

输入:k = 7
输出:2 
解释:斐波那契数字为:1,1,2,3,5,8,13,……
对于 k = 7 ,我们可以得到 2 + 5 = 7 。

示例 2:

输入:k = 10
输出:2 
解释:对于 k = 10 ,我们可以得到 2 + 8 = 10 。

示例 3:

输入:k = 19
输出:3 
解释:对于 k = 19 ,我们可以得到 1 + 5 + 13 = 19 。

 

提示:

  • 1 <= k <= 10^9

通过次数5,056提交次数8,752

有的时候感觉有些题真的不再自己的能力范围内啊,

构造斐波那契。等到数字大于K后,跳出,至于贪心的算法呢,只能说这是数学归纳法,让我来,我是不行的

贴上链接吧

斐波那契归纳

看懂了归纳,再来做的话,倒也是迎刃而解了

class Solution {
public:
    int findMinFibonacciNumbers(int k) {
        int a=1,b=1;
        vector<int>fibo={a,b};
        while(a+b<=k){
            fibo.push_back(a+b);
            int c=a+b;
            a=b;
            b=c;
        }
        int ans=0;
        for(int i=fibo.size()-1;i>=0;i--){
            if(k>=fibo[i]){
                ++ans;
                k-=fibo[i];
            }
        }
        return ans;
    }
};

 

<think>好的,用户想要了解动态规划中的逆序求解算法,并且需要示例代码。首先,我需要明确什么是逆序求解。动态规划通常有两种实现方式:自顶向下(记忆化搜索)自底向上(迭代)。逆序求解可能指的是从问题终点开始反向推导,比如在某些问题中,从后往前处理状态转移会更高效,比如最长公共子序列或者路径问题中的反向DP。 接下来,我需要查找相关的引用内容。用户提供了三个引用,其中引用[2]提到了逆序对,但可能逆序求解关系不大。引用[1][3]都是关于动态规划的。引用[1]提到动态规划的基本原理,将问题分解为子问题并存储结果。引用[3]给出了斐波那契爬楼梯的例子,但都是自底向上的常规方法,不是逆序的。 用户可能需要的是从后向前处理状态的例子。例如,在矩阵链乘法或编辑距离问题中,有时候反向遍历可以优化计算。另一个例子是背包问题,但通常也是正向处理。可能需要找一个典型的问题,比如最小路径,如果从终点往起点反向计算的话,可能更高效。 比如,最小路径问题,通常从左上到右下,但也可以从右下到左上,结果是一样的。但这是否算逆序求解呢?或者更复杂的例子,比如时间序列问题中的状态转移需要依赖后面的状态,这时候必须逆序处理。 比如,股票买卖问题中的某些情况,比如冷冻期问题,可能需要逆序处理。或者动态规划中的某些特定问题,比如“打家劫舍”问题,但常规解法是顺序的。 可能用户指的是状态转移方程中的依赖方向,比如当当前状态依赖于后面的状态时,必须逆序计算。例如,当处理i的状态需要i+1的状态时,必须从后往前遍历。比如,计算斐波那契数时,如果使用数组,通常是从前往后计算,但若某个问题需要从后往前填充数组,那可能属于逆序求解。 比如,一个假设的问题:计算从起点到终点的路径数,但只能向右或向下走。常规DP是正向,但如果问题要求从终点开始计算到起点的路径数,可能结构类似,但方向相反。不过这可能不算真正的逆序求解,只是方向不同。 或者,考虑一个时间序列的问题,比如资源分配,其中当前决策影响后续状态,可能需要逆序计算,例如从最后一步倒推到第一步。这种情况下,动态规划的处理顺序是逆序的。 例如,在背包问题中,如果每个物品只能选一次,逆序处理容量可以避免重复选择,但这是优化技巧,可能用户需要的是这种例子。 现在需要确定用户的问题是什么。用户提到“动态规划逆序求解”,可能是指状态转移方程中的处理顺序,或者问题本身需要反向推导。需要找一个合适的例子,并给出代码。 根据引用[3]中的斐波那契例子,常规是正向计算,但如果改变方向,可能没有太大区别。但可能需要更明显的例子,比如最长递增子序列(LIS),通常解法是正向的,但另一种方法可能涉及逆序处理。或者,编辑距离问题中的状态转移,可能涉及从后往前比较字符。 但可能更合适的例子是时间序列的逆序处理。例如,某个问题中,状态i依赖于i+1的状态,因此必须从后往前计算。 比如,计算从位置n到位置0的最短路径,其中每个位置i可以跳到i+1或i+2,这时逆序处理可能从n开始倒推。或者,一个更具体的例子,比如解决“最小跳跃次数”问题,其中需要从目标位置反向计算到起点的最少步骤。 例如,Leetcode 45. 跳跃游戏 II,可能需要逆序贪心,但动态规划解法可能需要反向处理。或者,比如,给定一个数组,每个元素表示最多可以跳跃的步数,求到达最后一个位置的最小跳跃次数。常规的动态规划解法是正向,但可能效率低,而逆序处理可能更高效。 不过,我需要找到一个明确的逆序动态规划的例子,并给出代码。假设用户需要的是状态转移方向为逆序的情况,例如从后往前填充DP表。 例如,计算一个字符串的回文子序列数目,可能涉及到从两端向中间处理,但常规解法可能不是逆序的。另一个例子是,最长回文子序列的动态规划解法,其中dp[i][j]依赖于dp[i+1][j-1]等,因此需要逆序填充i从后往前。 是的,最长回文子序列的问题中,通常我们会让i从字符串末尾向前遍历,j从i+1开始向后遍历,这样确保计算dp[i][j]时,dp[i+1][j-1]已经计算过了。这种情况下,i的处理顺序是逆序的。 因此,可以以最长回文子序列为例,说明逆序动态规划的应用,并给出代码。 例如,动态规划表dp[i][j]表示字符串s[i..j]的最长回文子序列长度。状态转移方程为: 如果s[i] == s[j],则dp[i][j] = dp[i+1][j-1] + 2 否则,dp[i][j] = max(dp[i+1][j], dp[i][j-1]) 在这种情况下,i需要从n-1到0逆序处理,j从i+1到n-1顺序处理。因为计算dp[i][j]时需要dp[i+1][j-1],所以必须逆序i。 这样的例子符合逆序求解的动态规划。因此,可以给出这个问题的代码示例,并解释逆序处理的原因。 接下来,我需要检查用户提供的引用是否有相关内容。引用[2]提到逆序对,但可能与当前问题无关。引用[3]中的动态规划例子都是常规顺序,但最长回文子序列的例子可能没有在引用中出现。不过用户要求的是逆序求解的程序实现,所以可能需要自己构造这个例子。 因此,回答的结构可以是: 1. 解释逆序动态规划的概念应用场景。 2. 给出最长回文子序列作为例子,说明状态转移方程逆序处理的原因。 3. 提供示例代码(Python或Java),并解释代码中的逆序处理部分。 4. 分析代码的时间复杂度空间复杂度。 5. 最后生成相关问题。 另外,需要确保数学公式使用正确的格式,行内公式用$...$,独立公式用$$...$$。 现在,开始组织回答内容: 首先,解释逆序求解在动态规划中的含义,比如状态转移方向需要从后向前处理,常用于某些特定问题结构,例如最长回文子序列,其中子问题的解依赖于后面的状态。接着,以最长回文子序列为例,给出状态转移方程,说明为什么需要逆序处理i。然后提供代码示例,使用双重循环,外层i从n-1到0逆序,内层j从i+1到n-1。然后分析时间空间复杂度。最后生成相关问题,如逆序求解的应用场景、优化空间复杂度的方法,以及与顺序求解的区别等。 需要确保代码正确,并且注释说明逆序处理的部分。例如,在Python中: def longestPalindromeSubseq(s: str) -> int: n = len(s) dp = [[0]*n for _ in range(n)] for i in range(n-1, -1, -1): dp[i][i] = 1 for j in range(i+1, n): if s[i] == s[j]: dp[i][j] = dp[i+1][j-1] + 2 else: dp[i][j] = max(dp[i+1][j], dp[i][j-1]) return dp[0][n-1] 这段代码中,i从n-1到0逆序遍历,确保在计算dp[i][j]时,dp[i+1][...]已经计算过。这正是逆序动态规划的典型应用。 总结:用户需要的是动态规划中逆序处理状态的示例,最长回文子序列是一个合适的例子,代码中的i循环逆序处理是关键点。</think>### 动态规划逆序求解示例 动态规划中的逆序求解通常指从问题终点反向推导状态转移,适用于某些子问题的解依赖于后续状态的情况。例如最长回文子序列问题,其状态转移方程要求先计算较大索引的状态,因此需要逆序处理下标。 #### 示例:最长回文子序列 **问题描述** 给定字符串 $s$,求其最长回文子序列的长度。 **状态定义** 设 $dp[i][j]$ 表示子串 $s[i..j]$ 的最长回文子序列长度。 **状态转移方程** $$ dp[i][j] = \begin{cases} dp[i+1][j-1] + 2, & s[i] = s[j] \\ \max(dp[i+1][j], \, dp[i][j-1]), & s[i] \neq s[j] \end{cases} $$ **逆序处理逻辑** 由于 $dp[i][j]$ 依赖于 $dp[i+1][j-1]$(即行索引更大的状态),必须从后向前遍历 $i$,而 $j$ 则从 $i+1$ 开始正向遍历。 #### 示例代码(Python) ```python def longest_palindrome_subseq(s: str) -> int: n = len(s) dp = [[0] * n for _ in range(n)] for i in range(n-1, -1, -1): # 逆序遍历i dp[i][i] = 1 # 单个字符的字符串回文长度为1 for j in range(i+1, n): if s[i] == s[j]: dp[i][j] = dp[i+1][j-1] + 2 else: dp[i][j] = max(dp[i+1][j], dp[i][j-1]) return dp[0][n-1] ``` #### 代码解析 1. **初始化**:二维数组 `dp` 表示子问题的解。 2. **逆序填充**:外层循环 `i` 从字符串末尾向前遍历,确保计算 `dp[i][j]` 时 `dp[i+1][j-1]` 已就绪。 3. **边界条件**:单个字符的字符串回文长度为1。 4. **状态转移**:根据字符是否相等,选择不同的转移路径。 #### 复杂度分析 - **时间复杂度**:$O(n^2)$,双重循环遍历所有子问题。 - **空间复杂度**:$O(n^2)$,二维数组存储状态。可通过滚动数组优化至 $O(n)$[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值