Skip to content

Commit 5b6fcd5

Browse files
authored
Merge branch 'master' into enhancement/#6336-comparision-sortUtils-logic
2 parents affe6fe + 3304cf2 commit 5b6fcd5

File tree

9 files changed

+443
-51
lines changed

9 files changed

+443
-51
lines changed

DIRECTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@
304304
- 📄 [KadaneAlgorithm](src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java)
305305
- 📄 [Knapsack](src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java)
306306
- 📄 [KnapsackMemoization](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java)
307+
- 📄 [KnapsackZeroOne](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java)
308+
- 📄 [KnapsackZeroOneTabulation](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java)
307309
- 📄 [LevenshteinDistance](src/main/java/com/thealgorithms/dynamicprogramming/LevenshteinDistance.java)
308310
- 📄 [LongestAlternatingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequence.java)
309311
- 📄 [LongestArithmeticSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java)
@@ -1009,6 +1011,8 @@
10091011
- 📄 [KadaneAlgorithmTest](src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java)
10101012
- 📄 [KnapsackMemoizationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
10111013
- 📄 [KnapsackTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java)
1014+
- 📄 [KnapsackZeroOneTabulationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java)
1015+
- 📄 [KnapsackZeroOneTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java)
10121016
- 📄 [LevenshteinDistanceTests](src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java)
10131017
- 📄 [LongestAlternatingSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequenceTest.java)
10141018
- 📄 [LongestArithmeticSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
/**
4+
* The {@code KnapsackZeroOne} provides Recursive solution for the 0/1 Knapsack
5+
* problem. Solves by exploring all combinations of items using recursion. No
6+
* memoization or dynamic programming optimizations are applied.
7+
*
8+
* Time Complexity: O(2^n) — explores all subsets.
9+
* Space Complexity: O(n) — due to recursive call stack.
10+
*
11+
* Problem Reference: https://en.wikipedia.org/wiki/Knapsack_problem
12+
*/
13+
public final class KnapsackZeroOne {
14+
15+
private KnapsackZeroOne() {
16+
// Prevent instantiation
17+
}
18+
19+
/**
20+
* Solves the 0/1 Knapsack problem using recursion.
21+
*
22+
* @param values the array containing values of the items
23+
* @param weights the array containing weights of the items
24+
* @param capacity the total capacity of the knapsack
25+
* @param n the number of items
26+
* @return the maximum total value achievable within the given weight limit
27+
* @throws IllegalArgumentException if input arrays are null, empty, or
28+
* lengths mismatch
29+
*/
30+
public static int compute(final int[] values, final int[] weights, final int capacity, final int n) {
31+
if (values == null || weights == null) {
32+
throw new IllegalArgumentException("Input arrays cannot be null.");
33+
}
34+
if (values.length != weights.length) {
35+
throw new IllegalArgumentException("Value and weight arrays must be of the same length.");
36+
}
37+
if (capacity < 0 || n < 0) {
38+
throw new IllegalArgumentException("Invalid input: arrays must be non-empty and capacity/n "
39+
+ "non-negative.");
40+
}
41+
if (n == 0 || capacity == 0 || values.length == 0) {
42+
return 0;
43+
}
44+
45+
if (weights[n - 1] <= capacity) {
46+
final int include = values[n - 1] + compute(values, weights, capacity - weights[n - 1], n - 1);
47+
final int exclude = compute(values, weights, capacity, n - 1);
48+
return Math.max(include, exclude);
49+
} else {
50+
return compute(values, weights, capacity, n - 1);
51+
}
52+
}
53+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
/**
4+
* Tabulation (Bottom-Up) Solution for 0-1 Knapsack Problem.
5+
* This method uses dynamic programming to build up a solution iteratively,
6+
* filling a 2-D array where each entry dp[i][w] represents the maximum value
7+
* achievable with the first i items and a knapsack capacity of w.
8+
*
9+
* The tabulation approach is efficient because it avoids redundant calculations
10+
* by solving all subproblems in advance and storing their results, ensuring
11+
* each subproblem is solved only once. This is a key technique in dynamic programming,
12+
* making it possible to solve problems that would otherwise be infeasible due to
13+
* exponential time complexity in naive recursive solutions.
14+
*
15+
* Time Complexity: O(n * W), where n is the number of items and W is the knapsack capacity.
16+
* Space Complexity: O(n * W) for the DP table.
17+
*
18+
* For more information, see:
19+
* https://en.wikipedia.org/wiki/Knapsack_problem#Dynamic_programming
20+
*/
21+
public final class KnapsackZeroOneTabulation {
22+
23+
private KnapsackZeroOneTabulation() {
24+
// Prevent instantiation
25+
}
26+
27+
/**
28+
* Solves the 0-1 Knapsack problem using the bottom-up tabulation technique.
29+
* @param values the values of the items
30+
* @param weights the weights of the items
31+
* @param capacity the total capacity of the knapsack
32+
* @param itemCount the number of items
33+
* @return the maximum value that can be put in the knapsack
34+
* @throws IllegalArgumentException if input arrays are null, of different lengths,or if capacity or itemCount is invalid
35+
*/
36+
public static int compute(final int[] values, final int[] weights, final int capacity, final int itemCount) {
37+
if (values == null || weights == null) {
38+
throw new IllegalArgumentException("Values and weights arrays must not be null.");
39+
}
40+
if (values.length != weights.length) {
41+
throw new IllegalArgumentException("Values and weights arrays must be non-null and of same length.");
42+
}
43+
if (capacity < 0) {
44+
throw new IllegalArgumentException("Capacity must not be negative.");
45+
}
46+
if (itemCount < 0 || itemCount > values.length) {
47+
throw new IllegalArgumentException("Item count must be between 0 and the length of the values array.");
48+
}
49+
50+
final int[][] dp = new int[itemCount + 1][capacity + 1];
51+
52+
for (int i = 1; i <= itemCount; i++) {
53+
final int currentValue = values[i - 1];
54+
final int currentWeight = weights[i - 1];
55+
56+
for (int w = 1; w <= capacity; w++) {
57+
if (currentWeight <= w) {
58+
final int includeItem = currentValue + dp[i - 1][w - currentWeight];
59+
final int excludeItem = dp[i - 1][w];
60+
dp[i][w] = Math.max(includeItem, excludeItem);
61+
} else {
62+
dp[i][w] = dp[i - 1][w];
63+
}
64+
}
65+
}
66+
67+
return dp[itemCount][capacity];
68+
}
69+
}
Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.thealgorithms.datastructures.lists;
22

3+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
34
import static org.junit.jupiter.api.Assertions.assertEquals;
45

56
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.DisplayName;
68
import org.junit.jupiter.api.Test;
79

810
public class CountSinglyLinkedListRecursionTest {
@@ -15,70 +17,112 @@ public void setUp() {
1517
}
1618

1719
@Test
20+
@DisplayName("Count of an empty list should be 0")
1821
public void testCountEmptyList() {
19-
// An empty list should have a count of 0
20-
assertEquals(0, list.count(), "Count of an empty list should be 0.");
22+
assertEquals(0, list.count());
2123
}
2224

2325
@Test
26+
@DisplayName("Count after inserting a single element should be 1")
2427
public void testCountSingleElementList() {
25-
// Insert a single element and check the count
2628
list.insert(1);
27-
assertEquals(1, list.count(), "Count of a single-element list should be 1.");
29+
assertEquals(1, list.count());
2830
}
2931

3032
@Test
33+
@DisplayName("Count after inserting multiple distinct elements")
3134
public void testCountMultipleElements() {
32-
// Insert multiple elements and check the count
3335
for (int i = 1; i <= 5; i++) {
3436
list.insert(i);
3537
}
36-
assertEquals(5, list.count(), "Count of a list with 5 elements should be 5.");
38+
assertEquals(5, list.count());
3739
}
3840

3941
@Test
42+
@DisplayName("Count should reflect total number of nodes with duplicate values")
4043
public void testCountWithDuplicateElements() {
41-
// Insert duplicate elements and verify the count is correct
42-
list.insert(1);
4344
list.insert(2);
4445
list.insert(2);
4546
list.insert(3);
4647
list.insert(3);
47-
assertEquals(5, list.count(), "Count of a list with duplicate elements should match total node count.");
48+
list.insert(1);
49+
assertEquals(5, list.count());
4850
}
4951

5052
@Test
53+
@DisplayName("Count should return 0 after clearing the list")
5154
public void testCountAfterClearingList() {
5255
for (int i = 1; i <= 4; i++) {
5356
list.insert(i);
5457
}
55-
list.clear(); // assuming you have a clear method; if not, skip this
56-
assertEquals(0, list.count(), "Count after clearing the list should be 0.");
58+
list.clear(); // assumed to exist
59+
assertEquals(0, list.count());
5760
}
5861

5962
@Test
63+
@DisplayName("Count on a very large list should be accurate")
6064
public void testCountOnVeryLargeList() {
6165
int n = 1000;
6266
for (int i = 0; i < n; i++) {
6367
list.insert(i);
6468
}
65-
assertEquals(n, list.count(), "Count should correctly return for large list sizes.");
69+
assertEquals(n, list.count());
6670
}
6771

6872
@Test
73+
@DisplayName("Count should work correctly with negative values")
6974
public void testCountOnListWithNegativeNumbers() {
7075
list.insert(-1);
71-
list.insert(-5);
72-
list.insert(-10);
73-
assertEquals(3, list.count(), "Count should correctly handle negative values.");
76+
list.insert(-2);
77+
list.insert(-3);
78+
assertEquals(3, list.count());
7479
}
7580

7681
@Test
82+
@DisplayName("Calling count multiple times should return the same value if list is unchanged")
7783
public void testCountIsConsistentWithoutModification() {
7884
list.insert(1);
7985
list.insert(2);
80-
int firstCount = list.count();
81-
int secondCount = list.count();
82-
assertEquals(firstCount, secondCount, "Repeated count calls should return consistent values.");
86+
int count1 = list.count();
87+
int count2 = list.count();
88+
assertEquals(count1, count2);
89+
}
90+
91+
@Test
92+
@DisplayName("Count should reflect total even if all values are the same")
93+
public void testCountAllSameValues() {
94+
for (int i = 0; i < 5; i++) {
95+
list.insert(42);
96+
}
97+
assertEquals(5, list.count());
98+
}
99+
100+
@Test
101+
@DisplayName("Count should remain correct after multiple interleaved insert and count operations")
102+
public void testCountAfterEachInsert() {
103+
assertEquals(0, list.count());
104+
list.insert(1);
105+
assertEquals(1, list.count());
106+
list.insert(2);
107+
assertEquals(2, list.count());
108+
list.insert(3);
109+
assertEquals(3, list.count());
110+
}
111+
112+
@Test
113+
@DisplayName("List should not throw on edge count (0 nodes)")
114+
public void testEdgeCaseNoElements() {
115+
assertDoesNotThrow(() -> list.count());
116+
}
117+
118+
@Test
119+
@DisplayName("Should count accurately after inserting then removing all elements")
120+
public void testCountAfterInsertAndClear() {
121+
for (int i = 0; i < 10; i++) {
122+
list.insert(i);
123+
}
124+
assertEquals(10, list.count());
125+
list.clear();
126+
assertEquals(0, list.count());
83127
}
84128
}

src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ public void testDequeue() {
3333
queue.put(10);
3434
queue.put(20);
3535
queue.put(30);
36-
assertEquals(10, queue.get()); // First item out
37-
assertEquals(20, queue.get()); // Second item out
38-
assertEquals(30, queue.get()); // Third item out
36+
assertEquals(10, queue.get());
37+
assertEquals(20, queue.get());
38+
assertEquals(30, queue.get());
3939
}
4040

4141
@Test
4242
public void testInterleavedOperations() {
4343
queue.put(10);
4444
queue.put(20);
45-
assertEquals(10, queue.get()); // Dequeue first item
45+
assertEquals(10, queue.get());
4646
queue.put(30);
47-
assertEquals(20, queue.get()); // Dequeue second item
48-
assertEquals(30, queue.get()); // Dequeue third item
47+
assertEquals(20, queue.get());
48+
assertEquals(30, queue.get());
4949
}
5050

5151
@Test
@@ -62,8 +62,76 @@ public void testQueueSize() {
6262

6363
@Test
6464
public void testEmptyQueueException() {
65-
assertThrows(NoSuchElementException.class, () -> {
66-
queue.get(); // Attempting to dequeue from empty queue
67-
});
65+
assertThrows(NoSuchElementException.class, () -> queue.get());
66+
}
67+
68+
@Test
69+
public void testDequeueAllElements() {
70+
for (int i = 1; i <= 5; i++) {
71+
queue.put(i);
72+
}
73+
for (int i = 1; i <= 5; i++) {
74+
assertEquals(i, queue.get());
75+
}
76+
assertEquals(0, queue.size());
77+
}
78+
79+
@Test
80+
public void testLargeNumberOfOperations() {
81+
int n = 1000;
82+
for (int i = 0; i < n; i++) {
83+
queue.put(i);
84+
}
85+
for (int i = 0; i < n; i++) {
86+
assertEquals(i, queue.get());
87+
}
88+
assertEquals(0, queue.size());
89+
}
90+
91+
@Test
92+
public void testRefillDuringDequeue() {
93+
queue.put(1);
94+
queue.put(2);
95+
assertEquals(1, queue.get());
96+
queue.put(3);
97+
queue.put(4);
98+
assertEquals(2, queue.get());
99+
assertEquals(3, queue.get());
100+
assertEquals(4, queue.get());
101+
}
102+
103+
@Test
104+
public void testAlternatingPutAndGet() {
105+
queue.put(1);
106+
assertEquals(1, queue.get());
107+
queue.put(2);
108+
queue.put(3);
109+
assertEquals(2, queue.get());
110+
queue.put(4);
111+
assertEquals(3, queue.get());
112+
assertEquals(4, queue.get());
113+
}
114+
115+
@Test
116+
public void testSizeStability() {
117+
queue.put(100);
118+
int size1 = queue.size();
119+
int size2 = queue.size();
120+
assertEquals(size1, size2);
121+
}
122+
123+
@Test
124+
public void testMultipleEmptyDequeues() {
125+
assertThrows(NoSuchElementException.class, () -> queue.get());
126+
assertThrows(NoSuchElementException.class, () -> queue.get());
127+
}
128+
129+
@Test
130+
public void testQueueWithStrings() {
131+
QueueByTwoStacks<String> stringQueue = new QueueByTwoStacks<>();
132+
stringQueue.put("a");
133+
stringQueue.put("b");
134+
assertEquals("a", stringQueue.get());
135+
assertEquals("b", stringQueue.get());
68136
}
69137
}

0 commit comments

Comments
 (0)