1414. 和为 K 的最少斐波那契数字数目
题目:
给你数字 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 。
解题思路:
读完题时第一想法:
- 先获取斐波那契数组
- 然后用dp找到最优解
- 回溯找到组成最优解的个数
但是做到后面回溯找到最优解才发现,用dp只不过是为了证明可以用斐波那契的那些数来组成k(最优解),即解可以得到!!!但是题目已经明确指出当前数可以用数组来得到!所以可以把dp给省略,这样就不会超时!
代码
第一次,用dp找最优解,超时!
class Solution {
public:
int findMinFibonacciNumbers(int k)
{
vector<int> nums;
nums.push_back(1);
nums.push_back(1);
int index = 2;
int num = 0;
while (num <= k)
{
num = nums[index - 1] + nums[index - 2];
nums.push_back(num);
index += 1;
}
int n = nums.size();
vector<vector<int>> dp(n,vector<int>(k + 1, 0));
for (int i = nums[0]; i <= k; i++)
{
dp[0][i] = nums[0];
}
for (int i = 1; i < nums.size(); i++)
{
for (int j = 0; j <= k; j++)
{
if (j > nums[i])
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
else
dp[i][j] = dp[i - 1][j];
}
}
int res = k;
int r = 0;
for (int i = n - 1; i >= 0; i--)
{
if (nums[i] <= res)
{
res -= nums[i];
r++;
}
}
return r;
}
};
第二次,可以把dp省略,因为题目已经表明这个数字一定可以用这个数组得到,不需要自己去证明
class Solution {
public:
int findMinFibonacciNumbers(int k)
{
vector<int> nums;
nums.push_back(1);
nums.push_back(1);
int index = 2;
int num = 0;
while (num <= k)
{
num = nums[index - 1] + nums[index - 2];
nums.push_back(num);
index += 1;
}
int n = nums.size();
int res = k;
int r = 0;
for (int i = n - 1; i >= 0; i--)
{
if (nums[i] <= res)
{
res -= nums[i];
r++;
}
}
return r;
}
};
总结
第一次做的时候被限制了思维,想着用dp然后回找来找到最优解.但是如果数过大就超时了,所以想到优化时才看到我在找最优解时压根就没用到dp数组.所以就把dp去除,即可得到最终结果