Find the Minimum Number of Fibonacci Numbers Whose Sum Is K
MedPrompt
Given an integer k, return the minimum number of Fibonacci numbers whose sum is equal to k. The same Fibonacci number can be used multiple times.
The Fibonacci numbers are defined as:
F1 = 1F2 = 1Fn = Fn-1 + Fn-2forn > 2.
k.
Example 1:
Input: k = 7
Output: 2
Explanation: The Fibonacci numbers are: 1, 1, 2, 3, 5, 8, 13, ...
For k = 7 we can use 2 + 5 = 7.Example 2:
Input: k = 10
Output: 2
Explanation: For k = 10 we can use 2 + 8 = 10.Example 3:
Input: k = 19
Output: 3
Explanation: For k = 19 we can use 1 + 5 + 13 = 19.
Constraints:
1 <= k <= 109
Approaches
2 approaches with complexity analysis and trade-offs.
A standard approach for problems that ask for the minimum number of items to form a specific sum is dynamic programming. We can define dp[i] as the minimum number of Fibonacci numbers that sum to i. By building up the solution for k from smaller subproblems, we can find the answer. However, this approach is too slow and memory-intensive for the given constraints on k.
Algorithm
- First, generate all Fibonacci numbers
fsuch thatf <= k. - Create a DP array,
dp, of sizek + 1.dp[i]will store the minimum number of Fibonacci numbers needed to form the sumi. - Initialize
dp[0] = 0and all otherdp[i]to a large value (infinity). - Iterate from
i = 1tok. For eachi, iterate through the generated Fibonacci numbersf. - The recurrence relation is
dp[i] = min(dp[i], 1 + dp[i - f])for every Fibonacci numberf <= i. - The final answer is
dp[k].
Walkthrough
This method involves building a table of solutions for all values from 1 to k. We define dp[i] as the minimum count of Fibonacci numbers that sum up to i.
The process is as follows:
- Generate all unique Fibonacci numbers less than or equal to
k. - Create a
dparray of sizek + 1and initialize all its values to infinity, except fordp[0], which is 0 (since 0 requires zero Fibonacci numbers). - We then fill the
dptable iteratively. For each numberifrom 1 tok, we try to form it by adding a Fibonacci numberfto a previously computed sumi - f. The number of Fibonacci numbers foriwould be1 + dp[i - f]. We do this for all possible Fibonacci numbersf <= iand take the one that results in the minimum count. - The final result is stored in
dp[k].
While correct, the large value of k makes this approach impractical.
import java.util.ArrayList;import java.util.Arrays;import java.util.List; class Solution { public int findMinFibonacciNumbers(int k) { // This approach is too slow and memory-intensive for the given constraints. // It is provided for illustrative purposes. // Generate unique Fibonacci numbers up to k List<Integer> fibs = new ArrayList<>(); int a = 1, b = 1; fibs.add(1); while (b <= k) { int temp = a + b; a = b; b = temp; if (b <= k) { fibs.add(b); } } int[] dp = new int[k + 1]; Arrays.fill(dp, k + 1); // Initialize with a value larger than any possible answer dp[0] = 0; for (int i = 1; i <= k; i++) { for (int fib : fibs) { if (i >= fib) { dp[i] = Math.min(dp[i], 1 + dp[i - fib]); } else { break; // Optimization as fibs is sorted } } } return dp[k]; }}Complexity
Time
O(k * log k) - The outer loop runs `k` times, and the inner loop iterates through the Fibonacci numbers, of which there are `O(log k)` up to `k`. This is too slow for `k = 10^9`.
Space
O(k) - We need an array of size `k+1` to store the DP states. For `k = 10^9`, this is not feasible.
Trade-offs
Pros
It's a standard and straightforward application of dynamic programming.
Guaranteed to find the optimal solution for any similar change-making problem.
Cons
Highly inefficient for large
k.The time complexity of
O(k * log k)is too slow for the given constraints, leading to a Time Limit Exceeded (TLE) error.The space complexity of
O(k)requires a very large amount of memory forkup to 10^9, leading to a Memory Limit Exceeded (MLE) error.
A much more efficient solution is a greedy algorithm. The core idea is to always subtract the largest possible Fibonacci number from the remaining value of k. This works because of a special property of Fibonacci numbers which guarantees that this greedy choice is always part of an optimal solution. This method is extremely fast and uses minimal memory, making it ideal for the given constraints.
Algorithm
- Generate Fibonacci numbers
F_1, F_2, ...and store them in a listfibsuntil the generated number is greater thank. - Initialize a counter
count = 0. - Start from the largest number in
fibsand move downwards (e.g., using an indexifromfibs.size() - 1to 0). - While
k > 0:- If the current Fibonacci number
fibs.get(i)is less than or equal tok:- Subtract it from
k:k = k - fibs.get(i). - Increment the counter:
count = count + 1.
- Subtract it from
- Move to the next smaller Fibonacci number:
i = i - 1.
- If the current Fibonacci number
- Return
count.
Walkthrough
The greedy strategy is based on the insight that to minimize the number of terms in a sum, one should use the largest possible numbers first. For Fibonacci numbers, this strategy is proven to be optimal.
The algorithm proceeds as follows:
- First, we generate all Fibonacci numbers that are less than or equal to
k. Since Fibonacci numbers grow exponentially, this list will be small (fewer than 50 numbers forkup to 10^9). - We initialize a counter to 0.
- We iterate from the largest generated Fibonacci number downwards. At each step, we check if the current Fibonacci number
fcan be subtracted from the remainingk(i.e.,f <= k). - If it can, we perform the subtraction (
k = k - f) and increment our counter. This greedy choice is optimal because any sum of smaller Fibonacci numbers that could replacefwould require more terms. - We repeat this until
kbecomes 0. The final count is our answer.
import java.util.ArrayList;import java.util.List; class Solution { public int findMinFibonacciNumbers(int k) { // Step 1: Generate Fibonacci numbers up to k. List<Integer> fibs = new ArrayList<>(); fibs.add(1); fibs.add(1); while (fibs.get(fibs.size() - 1) < k) { int n = fibs.size(); fibs.add(fibs.get(n - 1) + fibs.get(n - 2)); } // Step 2: Use a greedy approach to find the minimum number of terms. int count = 0; int i = fibs.size() - 1; while (k > 0) { if (fibs.get(i) <= k) { k -= fibs.get(i); count++; } i--; } return count; }}Complexity
Time
O(log k) - Generating the Fibonacci numbers takes `O(log k)` time. The greedy subtraction loop also takes `O(log k)` time as it iterates through the list of Fibonacci numbers once.
Space
O(log k) - We need to store the list of Fibonacci numbers up to `k`. The number of such Fibonacci numbers is proportional to `log(k)`.
Trade-offs
Pros
Extremely efficient, with logarithmic time and space complexity.
Simple to implement once the greedy strategy is known.
Easily handles the large constraints on
k.
Cons
The correctness of the greedy approach is not immediately obvious and relies on a specific mathematical property of Fibonacci numbers (related to Zeckendorf's theorem).
Solutions
Solution
class Solution {public int findMinFibonacciNumbers(int k) { if (k < 2) { return k; } int a = 1, b = 1; while (b <= k) { b = a + b; a = b - a; } return 1 + findMinFibonacciNumbers(k - a); }}class Solution {public: int findMinFibonacciNumbers(int k) { if (k < 2) return k; int a = 1, b = 1; while (b <= k) { b = a + b; a = b - a; } return 1 + findMinFibonacciNumbers(k - a); }};class Solution: def findMinFibonacciNumbers(self, k: int) -> int: def dfs(k): if k < 2: return k a = b = 1 while b <= k: a, b = b, a + b return 1 + dfs(k - a) return dfs(k)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.