leetcode-和为 K 的最少斐波那契数字数目

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。

题目

给你数字 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
输出:0
解释:对于 k = 19 ,我们可以得到 1 + 5 + 13 = 19 。

思路

一开始想到的是用完全背包,看了题解之后,发现贪心的方法,代码简介,证明非常巧妙。而且官方题解证明过程有些复杂,逻辑关系理解上需要一定的时间,所以再来总结一下。
贪心方法可能的关键点在于,一定存在一组最优解,包含不超过k的最大斐波那契数字f[m]。
首先,如果承认上面这个结论正确,那么贪心算法就很简单了,既然一定包含f[m],那么接下去可以转化成求解k-f[m],是原问题的子问题,一直这样求解下去,直到k=0即可。
接下来,我们看怎么证明上面这个结论。在直接证明这个结论之前,我们先看2个子结论:

  1. 最优解一定不包含连续2项斐波那契数字
  2. 存在一组最优解,不包含重复的项

结论1的证明比较简单,可以使用反正,假设存在最优解包含连续的2项,记为f[k]和f[k+1],根据斐波那契的定于,我们知道f[k+2] = f[k] + f[k+1],所以,使用f[k+2]去替换f[k]和f[k+1],和相等的情况下减少了1项,明显比原来的解更优,所以假设不成立。
结论2,我们可以这样推导,假设有1个最优解存在重复的项,记为2f[k]

2f[k] = f[k] + f[k] = (f[k+1]-f[k-1]) + (f[k-1]+f[k-2]) = f[k+1] + f[k-2]

即,可以使用2个不相同的项f[k+1]、f[k-2]来替换重复的2f[k],所以结论2成立。
接下来,我们根据上面2个子结论,我们要明证我们的最终结论,一定存在最优解包含f[m],这里官方题解有一个点没完全点破:
这一组不包含连续的项,也不包含重复的项的最优解,如果不包含不超过k的最大斐波那契数字f[m],那么剩下的数即使全选,也凑不够k了。 我们来证明:
根据上面2个子结论,我们根据m的奇偶性分成2种情况,来计算除了f[m],剩余的最大和sum:

  1. m是奇数,sum = f[m-1] + f[m-3] +...+ f[4] + f[2] = f[m-1] + f[m-3] +...+ f[4] + f[2] + f[1] - f[1] = f[m] - 1
  2. m是偶数,sum = f[m-1] + f[m-3] +...+ f[3] + f[1] = f[m-1] + f[m-3] +...+ f[3] + f[2] = f[m]

可以看到,无论是哪种情况,都可以得到

sum <= f[m] < k

所以,此时如果不选择f[m],剩下即使全选也凑不够k,所以f[m]必选。 综上所述,原始结论“一定存在一组最优解,包含不超过k的最大斐波那契数字f[m]”证明成立。

Java版本代码

class Solution {
    public int findMinFibonacciNumbers(int k) {
        List<Integer> fabList = new ArrayList<>();
        fabList.add(1);
        fabList.add(1);
        int index = 1;
        while (fabList.get(index) < k) {
            index++;
            fabList.add(fabList.get(index-2) + fabList.get(index-1));
        }
        int ans = 0;
        for (int i = index; i >= 0; i--) {
            if (k >= fabList.get(i)) {
                ans++;
                k -= fabList.get(i);
            }
        }
        return ans;
    }
}
复制代码

Guess you like

Origin juejin.im/post/7061413133100777480