Skip to content

Add tests, add IllegalArgumentException, remove main in `WineProb… #5662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,7 @@
* [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java)
* [UniqueSubsequencesCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java)
* [WildcardMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
* [WineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java)
* geometry
* [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java)
* greedyalgorithms
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
package com.thealgorithms.dynamicprogramming;

/**
* Imagine you have a collection of N wines placed next to each other on the
* shelf. The price of ith wine is pi(Prices of different wines are different).
* Because wine gets better every year supposing today is year 1, on year y the
* price would be y*pi i.e y times the value of the initial year. You want to
* sell all wines but you have to sell one wine per year. One more constraint on
* each year you are allowed to sell either leftmost or rightmost wine on the
* shelf. You are not allowed to reorder. You have to find the maximum profit
* The WineProblem class provides a solution to the wine selling problem.
* Given a collection of N wines with different prices, the objective is to maximize profit by selling
* one wine each year, considering the constraint that only the leftmost or rightmost wine can be sold
* at any given time.
*
* The price of the ith wine is pi, and the selling price increases by a factor of the year in which
* it is sold. This class implements three approaches to solve the problem:
*
* 1. **Recursion**: A straightforward recursive method that computes the maximum profit.
* - Time Complexity: O(2^N)
* - Space Complexity: O(N) due to recursive calls.
*
* 2. **Top-Down Dynamic Programming (Memoization)**: This approach caches the results of subproblems
* to avoid redundant computations.
* - Time Complexity: O(N^2)
* - Space Complexity: O(N^2) for the storage of results and O(N) for recursion stack.
*
* 3. **Bottom-Up Dynamic Programming (Tabulation)**: This method builds a table iteratively to
* compute the maximum profit for all possible subproblems.
* - Time Complexity: O(N^2)
* - Space Complexity: O(N^2) for the table.
*/
public final class WineProblem {
private WineProblem() {
}

// Method 1: Using Recursion
// Time Complexity=0(2^N) Space Complexity=Recursion extra space
/**
* Calculate maximum profit using recursion.
*
* @param arr Array of wine prices.
* @param si Start index of the wine to consider.
* @param ei End index of the wine to consider.
* @return Maximum profit obtainable by selling the wines.
*/
public static int wpRecursion(int[] arr, int si, int ei) {
int n = arr.length;
int year = (n - (ei - si + 1)) + 1;
Expand All @@ -29,8 +48,15 @@ public static int wpRecursion(int[] arr, int si, int ei) {
return Math.max(start, end);
}

// Method 2: Top-Down DP(Memoization)
// Time Complexity=0(N*N) Space Complexity=0(N*N)+Recursion extra space
/**
* Calculate maximum profit using top-down dynamic programming with memoization.
*
* @param arr Array of wine prices.
* @param si Start index of the wine to consider.
* @param ei End index of the wine to consider.
* @param strg 2D array to store results of subproblems.
* @return Maximum profit obtainable by selling the wines.
*/
public static int wptd(int[] arr, int si, int ei, int[][] strg) {
int n = arr.length;
int year = (n - (ei - si + 1)) + 1;
Expand All @@ -45,15 +71,22 @@ public static int wptd(int[] arr, int si, int ei, int[][] strg) {
int end = wptd(arr, si, ei - 1, strg) + arr[ei] * year;

int ans = Math.max(start, end);

strg[si][ei] = ans;

return ans;
}

// Method 3: Bottom-Up DP(Tabulation)
// Time Complexity=0(N*N/2)->0(N*N) Space Complexity=0(N*N)
/**
* Calculate maximum profit using bottom-up dynamic programming with tabulation.
*
* @param arr Array of wine prices.
* @throws IllegalArgumentException if the input array is null or empty.
* @return Maximum profit obtainable by selling the wines.
*/
public static int wpbu(int[] arr) {
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("Input array cannot be null or empty.");
}
int n = arr.length;
int[][] strg = new int[n][n];

Expand All @@ -73,13 +106,4 @@ public static int wpbu(int[] arr) {
}
return strg[0][n - 1];
}

public static void main(String[] args) {
int[] arr = {2, 3, 5, 1, 4};
System.out.println("Method 1: " + wpRecursion(arr, 0, arr.length - 1));
System.out.println("Method 2: " + wptd(arr, 0, arr.length - 1, new int[arr.length][arr.length]));
System.out.println("Method 3: " + wpbu(arr));
}
}
// Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
// Question Link : https://www.geeksforgeeks.org/maximum-profit-sale-wines/
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.thealgorithms.dynamicprogramming;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.Test;

/**
* Unit tests for the WineProblem class.
* This test class verifies the correctness of the wine selling problem solutions.
*/
class WineProblemTest {

/**
* Test for wpRecursion method.
*/
@Test
void testWpRecursion() {
int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
int expectedProfit = 50; // The expected maximum profit
assertEquals(expectedProfit, WineProblem.wpRecursion(wines, 0, wines.length - 1), "The maximum profit using recursion should be 50.");
}

/**
* Test for wptd method (Top-Down DP with Memoization).
*/
@Test
void testWptd() {
int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
int expectedProfit = 50; // The expected maximum profit
assertEquals(expectedProfit, WineProblem.wptd(wines, 0, wines.length - 1, new int[wines.length][wines.length]), "The maximum profit using top-down DP should be 50.");
}

/**
* Test for wpbu method (Bottom-Up DP with Tabulation).
*/
@Test
void testWpbu() {
int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
int expectedProfit = 50; // The expected maximum profit
assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit using bottom-up DP should be 50.");
}

/**
* Test with a single wine.
*/
@Test
void testSingleWine() {
int[] wines = {10}; // Only one wine
int expectedProfit = 10; // Selling the only wine at year 1
assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit for a single wine should be 10.");
}

/**
* Test with multiple wines of the same price.
*/
@Test
void testSamePriceWines() {
int[] wines = {5, 5, 5}; // All wines have the same price
int expectedProfit = 30; // Profit is 5 * (1 + 2 + 3)
assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit with same price wines should be 30.");
}

/**
* Test with no wines.
*/
@Test
void testNoWines() {
int[] wines = {};
assertThrows(IllegalArgumentException.class, () -> WineProblem.wpbu(wines), "The maximum profit for no wines should throw an IllegalArgumentException.");
}
}