There are n
oranges in the kitchen and you decided to eat some of these oranges every day as follows:
n
is divisible by 2
then you can eat n / 2
oranges.n
is divisible by 3
then you can eat 2 * (n / 3)
oranges.You can only choose one of the actions per day.
Given the integer n
, return the minimum number of days to eat n
oranges.
Example 1:
Input: n = 10 Output: 4 Explanation: You have 10 oranges. Day 1: Eat 1 orange, 10 - 1 = 9. Day 2: Eat 6 oranges, 9 - 2*(9/3) = 9 - 6 = 3. (Since 9 is divisible by 3) Day 3: Eat 2 oranges, 3 - 2*(3/3) = 3 - 2 = 1. Day 4: Eat the last orange 1 - 1 = 0. You need at least 4 days to eat the 10 oranges.
Example 2:
Input: n = 6 Output: 3 Explanation: You have 6 oranges. Day 1: Eat 3 oranges, 6 - 6/2 = 6 - 3 = 3. (Since 6 is divisible by 2). Day 2: Eat 2 oranges, 3 - 2*(3/3) = 3 - 2 = 1. (Since 3 is divisible by 3) Day 3: Eat the last orange 1 - 1 = 0. You need at least 3 days to eat the 6 oranges.
Constraints:
1 <= n <= 2 * 109
This problem asks for the minimum number of days to eat n
oranges, given that you can eat 1 orange, n/2
oranges (if n
is even), or 2*(n/3)
oranges (if n
is divisible by 3) each day. This can be efficiently solved using dynamic programming with memoization.
Approach:
The core idea is to recursively explore the possible ways to eat oranges, choosing the option that leads to the fewest days. We can represent this as a recursive function dfs(n)
which returns the minimum number of days to eat n
oranges.
The base cases are:
n < 2
: If we have less than 2 oranges, it takes n
days to eat them (1 day per orange).For n >= 2
, we explore three possibilities for each day:
n-1
oranges, so it takes 1 + dfs(n-1)
days.n/2
oranges, so it takes 1 + dfs(n/2)
days.n/3
oranges, so it takes 1 + dfs(n/3)
days.We take the minimum of these three possibilities as the optimal solution for dfs(n)
.
Memoization:
To avoid redundant computations, we use memoization. A hash table (dictionary in Python, map in Java/C++, etc.) stores previously computed results of dfs(n)
. If a result for a given n
is already in the table, we directly return it; otherwise, we compute it and store it before returning.
Time Complexity Analysis:
The time complexity is dominated by the recursive calls. In the worst case, we might explore a significant portion of the possible paths. However, the memoization drastically reduces the number of computations. The number of distinct calls to dfs
is roughly proportional to the number of possible values of n
we encounter, which is logarithmic in the initial n
(because we repeatedly divide n
by 2 or 3). Therefore, the time complexity is approximately O(log₂n * log₃n), which simplifies to O(log²n).
Space Complexity Analysis:
The space complexity is determined by the size of the memoization table. Again, the number of entries in the table is roughly O(log²n), reflecting the range of unique n
values encountered during the recursion. We also have the recursion stack which has depth at most O(log n) in the worst case. Thus, the overall space complexity is O(log²n).
Code Implementation (Python):
class Solution:
def minDays(self, n: int) -> int:
@lru_cache(None) # Use lru_cache for efficient memoization in Python
def dfs(n: int) -> int:
if n < 2:
return n
return 1 + min(dfs(n - 1), (dfs(n // 2) if n % 2 == 0 else float('inf')), (dfs(n // 3) if n % 3 == 0 else float('inf')))
return dfs(n)
Other Language Implementations: The approach remains the same across different languages. The primary difference lies in the syntax for memoization (using hash maps or dictionaries) and the handling of potential integer division in the recursive calls. The provided code snippets in Java, C++, Go and TypeScript demonstrate this. The key elements—recursive function, base cases, and memoization—are consistent across all implementations.