You are visiting a farm that has a single row of fruit trees arranged from left to right. The trees are represented by an integer array fruits
where fruits[i]
is the type of fruit the i<sup>th</sup>
tree produces.
You want to collect as much fruit as possible. However, the owner has some strict rules that you must follow:
Given the integer array fruits
, return the maximum number of fruits you can pick.
For example:
fruits = [1,2,1]
should return 3
because we can pick from all 3 trees.fruits = [0,1,2,2]
should return 3
because we can pick from trees [1,2,2]
. If we had started at the first tree, we would only pick from trees [0,1]
.fruits = [1,2,3,2,2]
should return 4
because we can pick from trees [2,3,2,2]
. If we had started at the first tree, we would only pick from trees [1,2]
.Can you provide an efficient solution to this problem, considering the constraints that 1 <= fruits.length <= 10^5
and 0 <= fruits[i] < fruits.length
?
The brute-force solution would be to iterate through all possible subarrays of the fruits
array and check if each subarray satisfies the condition of having at most two types of fruits. We keep track of the maximum length of such a subarray. This involves nested loops, leading to a time complexity of O(n^2).
def max_fruits_naive(fruits):
max_len = 0
for i in range(len(fruits)):
for j in range(i, len(fruits)):
subarray = fruits[i:j+1]
unique_fruits = set(subarray)
if len(unique_fruits) <= 2:
max_len = max(max_len, len(subarray))
return max_len
# Example usage:
fruits = [1, 2, 3, 2, 2]
print(max_fruits_naive(fruits)) # Output: 4
The optimal approach uses the sliding window technique to achieve a time complexity of O(n). We maintain a window with at most two types of fruits. We expand the window to the right until we have more than two types. Then, we shrink the window from the left until we have at most two types again. We keep track of the maximum window size.
def max_fruits(fruits):
max_len = 0
fruit_count = {}
left = 0
for right in range(len(fruits)):
# Expand the window
if fruits[right] not in fruit_count:
fruit_count[fruits[right]] = 0
fruit_count[fruits[right]] += 1
# Shrink the window if more than two types of fruits
while len(fruit_count) > 2:
fruit_count[fruits[left]] -= 1
if fruit_count[fruits[left]] == 0:
del fruit_count[fruits[left]]
left += 1
# Update the maximum length
max_len = max(max_len, right - left + 1)
return max_len
# Example usage:
fruits = [1, 2, 3, 2, 2]
print(max_fruits(fruits)) # Output: 4
fruits
: An array of integers representing the type of fruit each tree produces.fruit_count
: A dictionary to store the count of each type of fruit within the current window.left
: An integer representing the left boundary of the sliding window.right
: An integer representing the right boundary of the sliding window.The optimal solution with the sliding window technique has a time complexity of O(n), where n is the number of trees (length of the fruits
array).
for
loop iterates through each element of the fruits
array once, which takes O(n) time.fruit_count
dictionary take O(1) on average.while
loop also iterates, but in total, the left
pointer can only move up to n
times, so the while
loop also contributes O(n) in the worst case.The space complexity of the optimal solution is O(1) because the fruit_count
dictionary can hold at most three key-value pairs (since the while
loop ensures that no more than two types of fruits are in the window at any time). Therefore, the space used by the dictionary is constant and does not depend on the input size.
Empty Array:
fruits
array is empty, the algorithm should return 0 because no fruits can be picked.Single Type of Fruit:
fruits
array because all fruits can be picked.Two Types of Fruits:
fruits
array because all fruits can be picked.Fruits at the Beginning:
Fruits at the End:
All unique fruits: