# Leetcode Maximum Profit from Sale of Wine: A Comprehensive Guide

The “Leetcode Maximum Profit from Sale of Wine” problem is a classic dynamic programming problem frequently encountered in coding interviews and algorithm challenges. It showcases the importance of making optimal decisions based on available information over a **sequence **of steps. The problem involves maximizing profit from selling wines over a certain period while adhering to specific constraints on sales.

This article will break down the problem, explore various approaches to solving it, and analyze their complexities.

## Problem Statement

You are given an array of integers representing the amount of wine available for sale, where each wine has a specific price determined by the day it is sold. The selling price increases as the days progress. You can sell one bottle of wine per day, starting from the first day (day 1) until the last day (day n). The selling price of the wine is defined as follows:

- On the first day, you can sell the first wine.
- On the second day, you can sell the second wine.
- This continues until you sell all the wines.

Your objective is to maximize the profit from selling all the bottles of wine. The challenge is to determine the optimal order of selling the wines based on the given constraints.

### Example

Consider the following example:

```
Wines = [2, 3, 5, 1, 4]
```

- On day 1, you can sell the first wine for $2.
- On day 2, you can sell the second wine for $3.
- On day 3, you can sell the third wine for $5.
- On day 4, you can sell the fourth wine for $1.
- On day 5, you can sell the fifth wine for $4.

To maximize profit, you must determine the best order to sell the wines. The output for this example would be the maximum profit achievable from selling all the wines.

## Dynamic Programming Approach

To solve this problem effectively, we can use a dynamic programming approach. This method involves breaking down the problem into smaller subproblems and building up a solution using previously computed values.

### Step 1: Define the State

Let’s define a function `maxProfit(left, right, day)`

that computes the maximum profit from selling wines between indices `left`

and `right`

on a given day. The parameters are as follows:

`left`

: The index of the leftmost wine bottle available for sale.`right`

: The index of the rightmost wine bottle available for sale.`day`

: The current day of sale.

The profit from selling a bottle of wine can be computed as follows:

- If you sell the wine at index
`left`

, the profit is:$profit=Wines[left]×day+maxProfit(left + 1, right, day + 1)$

- If you sell the wine at index
`right`

, the profit is:$profit=Wines[right]×day+maxProfit(left, right – 1, day + 1)$

Thus, we can define our recursive relation:

$maxProfit(left, right, day)=max(Wines[left]×day+maxProfit(left + 1, right, day + 1),Wines[right]×day+maxProfit(left, right – 1, day + 1))$

### Step 2: Base Cases

The base cases for our recursion are:

- If
`left > right`

, it means there are no wines left to sell, and the profit should be`0`

. - If
`left == right`

, there’s only one wine bottle left, and you can sell it for`Wines[left] * day`

.

### Step 3: Memoization

Since this recursive approach may revisit the same states multiple times, we can optimize it using memoization. We’ll create a 3D array `dp`

where `dp[left][right][day]`

stores the maximum profit for the corresponding indices and day.

### Implementation

Now, let’s implement the above logic in Python:

`def maxProfit(wines):`

n = len(wines)

dp = [[[-1 for _ in range(n + 1)] for _ in range(n)] for _ in range(n)]
def helper(left, right, day):

if left > right:

return 0

if dp[left][right][day] != -1:

return dp[left][right][day]

sell_left = wines[left] * day + helper(left + 1, right, day + 1)

sell_right = wines[right] * day + helper(left, right - 1, day + 1)

dp[left][right][day] = max(sell_left, sell_right)

return dp[left][right][day]

return helper(0, n - 1, 1)

`# Example usage`

wines = [2, 3, 5, 1, 4]
print(maxProfit(wines)) # Output: Maximum profit

### Complexity Analysis

The time complexity of the above solution is $O(n_{3})$ due to the three nested loops (for `left`

, `right`

, and `day`

), where $n$ is the number of wine bottles. The space complexity is $O(n_{3})$ as well due to the memoization table.

## Bottom-Up Dynamic Programming Approach

The recursive approach can be further optimized into an iterative solution using a bottom-up dynamic programming approach. This method builds up the solution by solving all subproblems first.

### Step 1: Create a DP Table

Create a 2D DP table where `dp[left][right]`

stores the maximum profit obtainable from selling the wines between the `left`

and `right`

indices.

### Step 2: Fill the DP Table

- Iterate over the range of days from $n$ down to $1$.
- For each day, iterate over all possible pairs of
`left`

and`right`

indices. - Use the previously defined relations to compute the maximum profit.

### Implementation

Here’s how you can implement the bottom-up approach in Python:

`def maxProfit(wines):`

n = len(wines)

dp = [[0 for _ in range(n)] for _ in range(n)]
for day in range(1, n + 1):

for left in range(n - day + 1):

right = left + day - 1

dp[left][right] = max(wines[left] * day + (dp[left + 1][right] if left + 1 <= right else 0),

wines[right] * day + (dp[left][right - 1] if left <= right - 1 else 0))

return dp[0][n - 1]

`# Example usage`

wines = [2, 3, 5, 1, 4]
print(maxProfit(wines)) # Output: Maximum profit

### Complexity Analysis

The time complexity for the bottom-up approach is also $O(n_{2})$, while the space complexity is $O(n_{2})$ due to the DP table.

## Conclusion

The “Leetcode Maximum Profit from Sale of Wine” problem illustrates the power of dynamic programming in solving complex optimization problems. Both the recursive memoization approach and the bottom-up dynamic programming approach provide efficient solutions to maximize profit from selling wine bottles over time.

By understanding and implementing these strategies, you will be well-equipped to tackle similar problems in coding interviews and algorithm challenges. Always remember to analyze the time and space complexity of your solutions to optimize performance further.

Feel free to use and modify this article as needed for your purposes!