diff --git a/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java b/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java
index 417bf1307790..5eefe3eee671 100644
--- a/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java
+++ b/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java
@@ -5,6 +5,11 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * Finds all permutations of given array
+ * @author Tuhin Mondal (Git-Tuhin Mondal)
+ */
+
public final class GenerateSubsets {
private GenerateSubsets() {
diff --git a/src/main/java/com/thealgorithms/Recursion/GenerateUniqueSubsets.java b/src/main/java/com/thealgorithms/Recursion/GenerateUniqueSubsets.java
new file mode 100644
index 000000000000..9c8cffa59df8
--- /dev/null
+++ b/src/main/java/com/thealgorithms/Recursion/GenerateUniqueSubsets.java
@@ -0,0 +1,47 @@
+package com.thealgorithms.Recursion;
+
+// program to find unique power set of a string
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Finds all permutations of given array
+ * @author Tuhin Mondal (Git-Tuhin Mondal)
+ */
+
+public final class GenerateUniqueSubsets {
+
+ private GenerateUniqueSubsets() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List subsetRecursion(String str) {
+ Set ans = doRecursion("", str);
+ List a = new ArrayList<>(ans.stream().toList());
+ Collections.sort(a);
+ return a;
+ }
+
+ private static Set doRecursion(String p, String up) {
+ if (up.isEmpty()) {
+ Set list = new HashSet<>();
+ list.add(p);
+ return list;
+ }
+
+ // Taking the character
+ char ch = up.charAt(0);
+ // Adding the character in the recursion
+ Set left = doRecursion(p + ch, up.substring(1));
+ // Not adding the character in the recursion
+ Set right = doRecursion(p, up.substring(1));
+
+ left.addAll(right);
+
+ return left;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/Recursion/TowerOfHanoi.java b/src/main/java/com/thealgorithms/Recursion/TowerOfHanoi.java
new file mode 100644
index 000000000000..f127ef74161d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/Recursion/TowerOfHanoi.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.Recursion;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Finds all permutations of given array
+ * @author Tuhin Mondal (Git-Tuhin Mondal)
+ */
+
+public final class TowerOfHanoi {
+ private TowerOfHanoi() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List towerOfHanoi(int n) {
+ List arr = new ArrayList<>();
+ recursionApproach(n, 'A', 'B', 'C', arr);
+ return arr;
+ }
+
+ public static void recursionApproach(int n, char a, char b, char c, List list) {
+ if (n == 1) {
+ list.add("Take disk 1 from rod " + a + " to rod " + b);
+ return;
+ }
+
+ recursionApproach(n - 1, a, c, b, list);
+ list.add("Take disk " + n + " from rod " + a + " to rod " + b);
+ recursionApproach(n - 1, c, b, a, list);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/DES.java b/src/main/java/com/thealgorithms/ciphers/DES.java
deleted file mode 100644
index 7f3eed70f3c2..000000000000
--- a/src/main/java/com/thealgorithms/ciphers/DES.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package com.thealgorithms.ciphers;
-
-/**
- * This class is build to demonstrate the application of the DES-algorithm
- * (https://en.wikipedia.org/wiki/Data_Encryption_Standard) on a plain English message. The supplied
- * key must be in form of a 64 bit binary String.
- */
-public class DES {
-
- private String key;
- private final String[] subKeys;
-
- private void sanitize(String key) {
- int length = key.length();
- if (length != 64) {
- throw new IllegalArgumentException("DES key must be supplied as a 64 character binary string");
- }
- }
-
- DES(String key) {
- sanitize(key);
- this.key = key;
- subKeys = getSubkeys(key);
- }
-
- public String getKey() {
- return this.key;
- }
-
- public void setKey(String key) {
- sanitize(key);
- this.key = key;
- }
-
- // Permutation table to convert initial 64-bit key to 56 bit key
- private static final int[] PC1 = {57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4};
-
- // Lookup table used to shift the initial key, in order to generate the subkeys
- private static final int[] KEY_SHIFTS = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
-
- // Table to convert the 56 bit subkeys to 48 bit subkeys
- private static final int[] PC2 = {14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32};
-
- // Initial permutation of each 64 but message block
- private static final int[] IP = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};
-
- // Expansion table to convert right half of message blocks from 32 bits to 48 bits
- private static final int[] EXPANSION = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1};
-
- // The eight substitution boxes are defined below
- private static final int[][] S1 = {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
-
- private static final int[][] S2 = {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
-
- private static final int[][] S3 = {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
-
- private static final int[][] S4 = {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}};
-
- private static final int[][] S5 = {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}};
-
- private static final int[][] S6 = {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}};
-
- private static final int[][] S7 = {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}};
-
- private static final int[][] S8 = {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}};
-
- private static final int[][][] S = {S1, S2, S3, S4, S5, S6, S7, S8};
-
- // Permutation table, used in the Feistel function post s-box usage
- static final int[] PERMUTATION = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25};
-
- // Table used for final inversion of the message box after 16 rounds of Feistel Function
- static final int[] IP_INVERSE = {40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25};
-
- private String[] getSubkeys(String originalKey) {
- StringBuilder permutedKey = new StringBuilder(); // Initial permutation of keys via pc1
- int i;
- int j;
- for (i = 0; i < 56; i++) {
- permutedKey.append(originalKey.charAt(PC1[i] - 1));
- }
- String[] subKeys = new String[16];
- String initialPermutedKey = permutedKey.toString();
- String c0 = initialPermutedKey.substring(0, 28);
- String d0 = initialPermutedKey.substring(28);
-
- // We will now operate on the left and right halves of the permutedKey
- for (i = 0; i < 16; i++) {
- String cN = c0.substring(KEY_SHIFTS[i]) + c0.substring(0, KEY_SHIFTS[i]);
- String dN = d0.substring(KEY_SHIFTS[i]) + d0.substring(0, KEY_SHIFTS[i]);
- subKeys[i] = cN + dN;
- c0 = cN; // Re-assign the values to create running permutation
- d0 = dN;
- }
-
- // Let us shrink the keys to 48 bits (well, characters here) using pc2
- for (i = 0; i < 16; i++) {
- String key = subKeys[i];
- permutedKey.setLength(0);
- for (j = 0; j < 48; j++) {
- permutedKey.append(key.charAt(PC2[j] - 1));
- }
- subKeys[i] = permutedKey.toString();
- }
-
- return subKeys;
- }
-
- private String xOR(String a, String b) {
- int i;
- int l = a.length();
- StringBuilder xor = new StringBuilder();
- for (i = 0; i < l; i++) {
- int firstBit = a.charAt(i) - 48; // 48 is '0' in ascii
- int secondBit = b.charAt(i) - 48;
- xor.append((firstBit ^ secondBit));
- }
- return xor.toString();
- }
-
- private String createPaddedString(String s, int desiredLength, char pad) {
- int i;
- int l = s.length();
- StringBuilder paddedString = new StringBuilder();
- int diff = desiredLength - l;
- for (i = 0; i < diff; i++) {
- paddedString.append(pad);
- }
- return paddedString.toString();
- }
-
- private String pad(String s, int desiredLength) {
- return createPaddedString(s, desiredLength, '0') + s;
- }
-
- private String padLast(String s, int desiredLength) {
- return s + createPaddedString(s, desiredLength, '\u0000');
- }
-
- private String feistel(String messageBlock, String key) {
- int i;
- StringBuilder expandedKey = new StringBuilder();
- for (i = 0; i < 48; i++) {
- expandedKey.append(messageBlock.charAt(EXPANSION[i] - 1));
- }
- String mixedKey = xOR(expandedKey.toString(), key);
- StringBuilder substitutedString = new StringBuilder();
-
- // Let us now use the s-boxes to transform each 6 bit (length here) block to 4 bits
- for (i = 0; i < 48; i += 6) {
- String block = mixedKey.substring(i, i + 6);
- int row = (block.charAt(0) - 48) * 2 + (block.charAt(5) - 48);
- int col = (block.charAt(1) - 48) * 8 + (block.charAt(2) - 48) * 4 + (block.charAt(3) - 48) * 2 + (block.charAt(4) - 48);
- String substitutedBlock = pad(Integer.toBinaryString(S[i / 6][row][col]), 4);
- substitutedString.append(substitutedBlock);
- }
-
- StringBuilder permutedString = new StringBuilder();
- for (i = 0; i < 32; i++) {
- permutedString.append(substitutedString.charAt(PERMUTATION[i] - 1));
- }
-
- return permutedString.toString();
- }
-
- private String encryptBlock(String message, String[] keys) {
- StringBuilder permutedMessage = new StringBuilder();
- int i;
- for (i = 0; i < 64; i++) {
- permutedMessage.append(message.charAt(IP[i] - 1));
- }
- String e0 = permutedMessage.substring(0, 32);
- String f0 = permutedMessage.substring(32);
-
- // Iterate 16 times
- for (i = 0; i < 16; i++) {
- String eN = f0; // Previous Right block
- String fN = xOR(e0, feistel(f0, keys[i]));
- e0 = eN;
- f0 = fN;
- }
-
- String combinedBlock = f0 + e0; // Reverse the 16th block
- permutedMessage.setLength(0);
- for (i = 0; i < 64; i++) {
- permutedMessage.append(combinedBlock.charAt(IP_INVERSE[i] - 1));
- }
- return permutedMessage.toString();
- }
-
- // To decode, we follow the same process as encoding, but with reversed keys
- private String decryptBlock(String message, String[] keys) {
- String[] reversedKeys = new String[keys.length];
- for (int i = 0; i < keys.length; i++) {
- reversedKeys[i] = keys[keys.length - i - 1];
- }
- return encryptBlock(message, reversedKeys);
- }
-
- /**
- * @param message Message to be encrypted
- * @return The encrypted message, as a binary string
- */
- public String encrypt(String message) {
- StringBuilder encryptedMessage = new StringBuilder();
- int l = message.length();
- int i;
- int j;
- if (l % 8 != 0) {
- int desiredLength = (l / 8 + 1) * 8;
- l = desiredLength;
- message = padLast(message, desiredLength);
- }
-
- for (i = 0; i < l; i += 8) {
- String block = message.substring(i, i + 8);
- StringBuilder bitBlock = new StringBuilder();
- byte[] bytes = block.getBytes();
- for (j = 0; j < 8; j++) {
- bitBlock.append(pad(Integer.toBinaryString(bytes[j]), 8));
- }
- encryptedMessage.append(encryptBlock(bitBlock.toString(), subKeys));
- }
- return encryptedMessage.toString();
- }
-
- /**
- * @param message The encrypted string. Expects it to be a multiple of 64 bits, in binary format
- * @return The decrypted String, in plain English
- */
- public String decrypt(String message) {
- StringBuilder decryptedMessage = new StringBuilder();
- int l = message.length();
- int i;
- int j;
- if (l % 64 != 0) {
- throw new IllegalArgumentException("Encrypted message should be a multiple of 64 characters in length");
- }
- for (i = 0; i < l; i += 64) {
- String block = message.substring(i, i + 64);
- String result = decryptBlock(block, subKeys);
- byte[] res = new byte[8];
- for (j = 0; j < 64; j += 8) {
- res[j / 8] = (byte) Integer.parseInt(result.substring(j, j + 8), 2);
- }
- decryptedMessage.append(new String(res));
- }
- return decryptedMessage.toString().replace("\0", ""); // Get rid of the null bytes used for padding
- }
-}
diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java
deleted file mode 100644
index 2b8959ed0136..000000000000
--- a/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.thealgorithms.datastructures.crdt;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * GSet (Grow-only Set) is a state-based CRDT (Conflict-free Replicated Data Type)
- * that allows only the addition of elements and ensures that once an element is added,
- * it cannot be removed. The merge operation of two G-Sets is their union.
- * This implementation supports adding elements, looking up elements, comparing with other G-Sets,
- * and merging with another G-Set to create a new G-Set containing all unique elements from both sets.
- * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
- *
- * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
- */
-
-public class GSet {
- private final Set elements;
-
- /**
- * Constructs an empty G-Set.
- */
- public GSet() {
- this.elements = new HashSet<>();
- }
-
- /**
- * Adds an element to the G-Set.
- *
- * @param e the element to be added
- */
- public void addElement(T e) {
- elements.add(e);
- }
-
- /**
- * Checks if the given element is present in the G-Set.
- *
- * @param e the element to be checked
- * @return true if the element is present, false otherwise
- */
- public boolean lookup(T e) {
- return elements.contains(e);
- }
-
- /**
- * Compares the G-Set with another G-Set to check if it is a subset.
- *
- * @param other the other G-Set to compare with
- * @return true if the current G-Set is a subset of the other, false otherwise
- */
- public boolean compare(GSet other) {
- return other.elements.containsAll(elements);
- }
-
- /**
- * Merges the current G-Set with another G-Set, creating a new G-Set
- * containing all unique elements from both sets.
- *
- * @param other the G-Set to merge with
- */
- public void merge(GSet other) {
- elements.addAll(other.elements);
- }
-}
diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java
deleted file mode 100644
index 2c6ce8a427d1..000000000000
--- a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.thealgorithms.datastructures.crdt;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type)
- * designed for managing sets in a distributed and concurrent environment. It supports the addition and removal
- * of elements, using timestamps to determine the order of operations. The set is split into two subsets:
- * the add set for elements to be added and the remove set for elements to be removed.
- *
- * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
- * @see Conflict-free_replicated_data_type
- * @see itakurah (Niklas Hoefflin)
- */
-
-class Element {
- String key;
- int timestamp;
- Bias bias;
-
- /**
- * Constructs a new Element with the specified key, timestamp and bias.
- *
- * @param key The key of the element.
- * @param timestamp The timestamp associated with the element.
- * @param bias The bias of the element (ADDS or REMOVALS).
- */
- Element(String key, int timestamp, Bias bias) {
- this.key = key;
- this.timestamp = timestamp;
- this.bias = bias;
- }
-}
-
-enum Bias {
- /**
- * ADDS bias for the add set.
- * REMOVALS bias for the remove set.
- */
- ADDS,
- REMOVALS
-}
-
-class LWWElementSet {
- private final Map addSet;
- private final Map removeSet;
-
- /**
- * Constructs an empty LWWElementSet.
- */
- LWWElementSet() {
- this.addSet = new HashMap<>();
- this.removeSet = new HashMap<>();
- }
-
- /**
- * Adds an element to the addSet.
- *
- * @param e The element to be added.
- */
- public void add(Element e) {
- addSet.put(e.key, e);
- }
-
- /**
- * Removes an element from the removeSet.
- *
- * @param e The element to be removed.
- */
- public void remove(Element e) {
- if (lookup(e)) {
- removeSet.put(e.key, e);
- }
- }
-
- /**
- * Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet.
- *
- * @param e The element to be checked.
- * @return True if the element is present, false otherwise.
- */
- public boolean lookup(Element e) {
- Element inAddSet = addSet.get(e.key);
- Element inRemoveSet = removeSet.get(e.key);
-
- return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp));
- }
-
- /**
- * Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset.
- *
- * @param other The LWWElementSet to compare.
- * @return True if the set is subset, false otherwise.
- */
- public boolean compare(LWWElementSet other) {
- return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet());
- }
-
- /**
- * Merges another LWWElementSet into this set by resolving conflicts based on timestamps.
- *
- * @param other The LWWElementSet to merge.
- */
- public void merge(LWWElementSet other) {
- for (Element e : other.addSet.values()) {
- if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) {
- addSet.put(e.key, e);
- }
- }
-
- for (Element e : other.removeSet.values()) {
- if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) {
- removeSet.put(e.key, e);
- }
- }
- }
-
- /**
- * Compares timestamps of two elements based on their bias (ADDS or REMOVALS).
- *
- * @param e The first element.
- * @param other The second element.
- * @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal.
- */
- public boolean compareTimestamps(Element e, Element other) {
- if (e.bias != other.bias) {
- throw new IllegalArgumentException("Invalid bias value");
- }
- Bias bias = e.bias;
- int timestampComparison = Integer.compare(e.timestamp, other.timestamp);
-
- if (timestampComparison == 0) {
- return bias != Bias.ADDS;
- }
- return timestampComparison < 0;
- }
-}
diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java
deleted file mode 100644
index a4cc2ffdd4a6..000000000000
--- a/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package com.thealgorithms.datastructures.crdt;
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * ORSet (Observed-Removed Set) is a state-based CRDT (Conflict-free Replicated Data Type)
- * that supports both addition and removal of elements. This particular implementation follows
- * the Add-Wins strategy, meaning that in case of conflicting add and remove operations,
- * the add operation takes precedence. The merge operation of two OR-Sets ensures that
- * elements added at any replica are eventually observed at all replicas. Removed elements,
- * once observed, are never reintroduced.
- * This OR-Set implementation provides methods for adding elements, removing elements,
- * checking for element existence, retrieving the set of elements, comparing with other OR-Sets,
- * and merging with another OR-Set to create a new OR-Set containing all unique elements
- * from both sets.
- *
- * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
- * @see Conflict-free_replicated_data_type
- * @see itakurah (Niklas Hoefflin)
- */
-
-public class ORSet {
-
- private final Set> elements;
- private final Set> tombstones;
-
- /**
- * Constructs an empty OR-Set.
- */
- public ORSet() {
- this.elements = new HashSet<>();
- this.tombstones = new HashSet<>();
- }
-
- /**
- * Checks if the set contains the specified element.
- *
- * @param element the element to check for
- * @return true if the set contains the element, false otherwise
- */
- public boolean contains(T element) {
- return elements.stream().anyMatch(pair -> pair.getElement().equals(element));
- }
-
- /**
- * Retrieves the elements in the set.
- *
- * @return a set containing the elements
- */
- public Set elements() {
- Set result = new HashSet<>();
- elements.forEach(pair -> result.add(pair.getElement()));
- return result;
- }
-
- /**
- * Adds the specified element to the set.
- *
- * @param element the element to add
- */
- public void add(T element) {
- String n = prepare();
- effect(element, n);
- }
-
- /**
- * Removes the specified element from the set.
- *
- * @param element the element to remove
- */
- public void remove(T element) {
- Set> pairsToRemove = prepare(element);
- effect(pairsToRemove);
- }
-
- /**
- * Collect all pairs with the specified element.
- *
- * @param element the element to collect pairs for
- * @return a set of pairs with the specified element to be removed
- */
- private Set> prepare(T element) {
- Set> pairsToRemove = new HashSet<>();
- for (Pair pair : elements) {
- if (pair.getElement().equals(element)) {
- pairsToRemove.add(pair);
- }
- }
- return pairsToRemove;
- }
-
- /**
- * Generates a unique tag for the element.
- *
- * @return the unique tag
- */
- private String prepare() {
- return generateUniqueTag();
- }
-
- /**
- * Adds the element with the specified unique tag to the set.
- *
- * @param element the element to add
- * @param n the unique tag associated with the element
- */
- private void effect(T element, String n) {
- Pair pair = new Pair<>(element, n);
- elements.add(pair);
- elements.removeAll(tombstones);
- }
-
- /**
- * Removes the specified pairs from the set.
- *
- * @param pairsToRemove the pairs to remove
- */
- private void effect(Set> pairsToRemove) {
- elements.removeAll(pairsToRemove);
- tombstones.addAll(pairsToRemove);
- }
-
- /**
- * Generates a unique tag.
- *
- * @return the unique tag
- */
- private String generateUniqueTag() {
- return UUID.randomUUID().toString();
- }
-
- /**
- * Compares this Add-Wins OR-Set with another OR-Set to check if elements and tombstones are a subset.
- *
- * @param other the other OR-Set to compare
- * @return true if the sets are subset, false otherwise
- */
- public boolean compare(ORSet other) {
- Set> union = new HashSet<>(elements);
- union.addAll(tombstones);
-
- Set> otherUnion = new HashSet<>(other.elements);
- otherUnion.addAll(other.tombstones);
-
- return otherUnion.containsAll(union) && other.tombstones.containsAll(tombstones);
- }
-
- /**
- * Merges this Add-Wins OR-Set with another OR-Set.
- *
- * @param other the other OR-Set to merge
- */
- public void merge(ORSet other) {
- elements.removeAll(other.tombstones);
- other.elements.removeAll(tombstones);
- elements.addAll(other.elements);
- tombstones.addAll(other.tombstones);
- }
-
- /**
- * Represents a pair containing an element and a unique tag.
- *
- * @param the type of the element in the pair
- */
- public static class Pair {
- private final T element;
- private final String uniqueTag;
-
- /**
- * Constructs a pair with the specified element and unique tag.
- *
- * @param element the element in the pair
- * @param uniqueTag the unique tag associated with the element
- */
- public Pair(T element, String uniqueTag) {
- this.element = element;
- this.uniqueTag = uniqueTag;
- }
-
- /**
- * Gets the element from the pair.
- *
- * @return the element
- */
- public T getElement() {
- return element;
- }
- }
-}
diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java
deleted file mode 100644
index c0ce17b2802b..000000000000
--- a/src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.thealgorithms.datastructures.crdt;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * TwoPhaseSet (2P-Set) is a state-based CRDT (Conflict-free Replicated Data Type) designed for managing sets
- * with support for both addition and removal operations in a distributed and concurrent environment.
- * It combines two G-Sets (grow-only sets) - one set for additions and another set (tombstone set) for removals.
- * Once an element is removed and placed in the tombstone set, it cannot be re-added, adhering to "remove-wins" semantics.
- * This implementation supports querying the presence of elements, adding elements, removing elements,
- * comparing with other 2P-Sets, and merging two 2P-Sets while preserving the remove-wins semantics.
- * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
- *
- * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
- */
-
-public class TwoPSet {
- private final Set setA;
- private final Set setR;
-
- /**
- * Constructs an empty Two-Phase Set.
- */
- public TwoPSet() {
- this.setA = new HashSet<>();
- this.setR = new HashSet<>();
- }
-
- /**
- * Checks if an element is in the set and has not been removed.
- *
- * @param element The element to be checked.
- * @return True if the element is in the set and has not been removed, otherwise false.
- */
- public boolean lookup(T element) {
- return setA.contains(element) && !setR.contains(element);
- }
-
- /**
- * Adds an element to the set.
- *
- * @param element The element to be added.
- */
- public void add(T element) {
- setA.add(element);
- }
-
- /**
- * Removes an element from the set. The element will be placed in the tombstone set.
- *
- * @param element The element to be removed.
- */
- public void remove(T element) {
- if (lookup(element)) {
- setR.add(element);
- }
- }
-
- /**
- * Compares the current 2P-Set with another 2P-Set.
- *
- * @param otherSet The other 2P-Set to compare with.
- * @return True if both SetA and SetR are subset, otherwise false.
- */
- public boolean compare(TwoPSet otherSet) {
- return otherSet.setA.containsAll(setA) && otherSet.setR.containsAll(setR);
- }
-
- /**
- * Merges the current 2P-Set with another 2P-Set.
- *
- * @param otherSet The other 2P-Set to merge with.
- * @return A new 2P-Set containing the merged elements.
- */
- public TwoPSet merge(TwoPSet otherSet) {
- TwoPSet mergedSet = new TwoPSet<>();
- mergedSet.setA.addAll(this.setA);
- mergedSet.setA.addAll(otherSet.setA);
- mergedSet.setR.addAll(this.setR);
- mergedSet.setR.addAll(otherSet.setR);
- return mergedSet;
- }
-}
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java
deleted file mode 100644
index dcdb08ad133e..000000000000
--- a/src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package com.thealgorithms.datastructures.graphs;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Boruvka's algorithm to find Minimum Spanning Tree
- * (https://en.wikipedia.org/wiki/Bor%C5%AFvka%27s_algorithm)
- *
- * @author itakurah (https://github.com/itakurah)
- */
-
-final class BoruvkaAlgorithm {
- private BoruvkaAlgorithm() {
- }
-
- /**
- * Represents an edge in the graph
- */
- static class Edge {
- final int src;
- final int dest;
- final int weight;
-
- Edge(final int src, final int dest, final int weight) {
- this.src = src;
- this.dest = dest;
- this.weight = weight;
- }
- }
-
- /**
- * Represents the graph
- */
- static class Graph {
- final int vertex;
- final List edges;
-
- /**
- * Constructor for the graph
- *
- * @param vertex number of vertices
- * @param edges list of edges
- */
- Graph(final int vertex, final List edges) {
- if (vertex < 0) {
- throw new IllegalArgumentException("Number of vertices must be positive");
- }
- if (edges == null || edges.isEmpty()) {
- throw new IllegalArgumentException("Edges list must not be null or empty");
- }
- for (final var edge : edges) {
- checkEdgeVertices(edge.src, vertex);
- checkEdgeVertices(edge.dest, vertex);
- }
-
- this.vertex = vertex;
- this.edges = edges;
- }
- }
-
- /**
- * Represents a subset for Union-Find operations
- */
- private static class Component {
- int parent;
- int rank;
-
- Component(final int parent, final int rank) {
- this.parent = parent;
- this.rank = rank;
- }
- }
-
- /**
- * Represents the state of Union-Find components and the result list
- */
- private static class BoruvkaState {
- List result;
- Component[] components;
- final Graph graph;
-
- BoruvkaState(final Graph graph) {
- this.result = new ArrayList<>();
- this.components = initializeComponents(graph);
- this.graph = graph;
- }
-
- /**
- * Adds the cheapest edges to the result list and performs Union operation on the subsets.
- *
- * @param cheapest Array containing the cheapest edge for each subset.
- */
- void merge(final Edge[] cheapest) {
- for (int i = 0; i < graph.vertex; ++i) {
- if (cheapest[i] != null) {
- final var component1 = find(components, cheapest[i].src);
- final var component2 = find(components, cheapest[i].dest);
-
- if (component1 != component2) {
- result.add(cheapest[i]);
- union(components, component1, component2);
- }
- }
- }
- }
-
- /**
- * Checks if there are more edges to add to the result list
- *
- * @return true if there are more edges to add, false otherwise
- */
- boolean hasMoreEdgesToAdd() {
- return result.size() < graph.vertex - 1;
- }
-
- /**
- * Computes the cheapest edges for each subset in the Union-Find structure.
- *
- * @return an array containing the cheapest edge for each subset.
- */
- private Edge[] computeCheapestEdges() {
- Edge[] cheapest = new Edge[graph.vertex];
- for (final var edge : graph.edges) {
- final var set1 = find(components, edge.src);
- final var set2 = find(components, edge.dest);
-
- if (set1 != set2) {
- if (cheapest[set1] == null || edge.weight < cheapest[set1].weight) {
- cheapest[set1] = edge;
- }
- if (cheapest[set2] == null || edge.weight < cheapest[set2].weight) {
- cheapest[set2] = edge;
- }
- }
- }
- return cheapest;
- }
-
- /**
- * Initializes subsets for Union-Find
- *
- * @param graph the graph
- * @return the initialized subsets
- */
- private static Component[] initializeComponents(final Graph graph) {
- Component[] components = new Component[graph.vertex];
- for (int v = 0; v < graph.vertex; ++v) {
- components[v] = new Component(v, 0);
- }
- return components;
- }
- }
-
- /**
- * Finds the parent of the subset using path compression
- *
- * @param components array of subsets
- * @param i index of the subset
- * @return the parent of the subset
- */
- static int find(final Component[] components, final int i) {
- if (components[i].parent != i) {
- components[i].parent = find(components, components[i].parent);
- }
- return components[i].parent;
- }
-
- /**
- * Performs the Union operation for Union-Find
- *
- * @param components array of subsets
- * @param x index of the first subset
- * @param y index of the second subset
- */
- static void union(Component[] components, final int x, final int y) {
- final int xroot = find(components, x);
- final int yroot = find(components, y);
-
- if (components[xroot].rank < components[yroot].rank) {
- components[xroot].parent = yroot;
- } else if (components[xroot].rank > components[yroot].rank) {
- components[yroot].parent = xroot;
- } else {
- components[yroot].parent = xroot;
- components[xroot].rank++;
- }
- }
-
- /**
- * Boruvka's algorithm to find the Minimum Spanning Tree
- *
- * @param graph the graph
- * @return list of edges in the Minimum Spanning Tree
- */
- static List boruvkaMST(final Graph graph) {
- var boruvkaState = new BoruvkaState(graph);
-
- while (boruvkaState.hasMoreEdgesToAdd()) {
- final var cheapest = boruvkaState.computeCheapestEdges();
- boruvkaState.merge(cheapest);
- }
- return boruvkaState.result;
- }
-
- /**
- * Checks if the edge vertices are in a valid range
- *
- * @param vertex the vertex to check
- * @param upperBound the upper bound for the vertex range
- */
- private static void checkEdgeVertices(final int vertex, final int upperBound) {
- if (vertex < 0 || vertex >= upperBound) {
- throw new IllegalArgumentException("Edge vertex out of range");
- }
- }
-}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java b/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java
deleted file mode 100644
index 52308c23cf1c..000000000000
--- a/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package com.thealgorithms.dynamicprogramming;
-
-import java.util.Arrays;
-
-/*
-Given an array of non-negative integers , partition the array in two subset that
-difference in sum of elements for both subset minimum.
-Return the minimum difference in sum of these subsets you can achieve.
-
-Input: array[] = {1, 6, 11, 4}
-Output: 0
-Explanation:
-Subset1 = {1, 4, 6}, sum of Subset1 = 11
-Subset2 = {11}, sum of Subset2 = 11
-
-Input: array[] = {36, 7, 46, 40}
-Output: 23
-Explanation:
-Subset1 = {7, 46} ; sum of Subset1 = 53
-Subset2 = {36, 40} ; sum of Subset2 = 76
- */
-public final class MinimumSumPartition {
- private MinimumSumPartition() {
- }
-
- private static void throwIfInvalidInput(final int[] array) {
- if (Arrays.stream(array).anyMatch(a -> a < 0)) {
- throw new IllegalArgumentException("Input array should not contain negative number(s).");
- }
- }
-
- public static int minimumSumPartition(final int[] array) {
- throwIfInvalidInput(array);
- int sum = Arrays.stream(array).sum();
- boolean[] dp = new boolean[sum / 2 + 1];
- dp[0] = true; // Base case , don't select any element from array
-
- // Find the closest sum of subset array that we can achieve which is closest to half of sum of full array
- int closestPartitionSum = 0;
-
- for (int i = 0; i < array.length; i++) {
- for (int j = sum / 2; j > 0; j--) {
- if (array[i] <= j) {
- dp[j] = dp[j] || dp[j - array[i]];
- }
- if (dp[j]) {
- closestPartitionSum = Math.max(closestPartitionSum, j);
- }
- }
- }
- /*
- Difference in sum = Big partition sum - Small partition sum
- = ( Total sum - Small partition sum) - Small partition sum
- */
- return sum - (2 * closestPartitionSum);
- }
-}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java b/src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java
deleted file mode 100644
index 49c4a0a3a008..000000000000
--- a/src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * @author Md Asif Joardar
- *
- * Description: The partition problem is a classic problem in computer science
- * that asks whether a given set can be partitioned into two subsets such that
- * the sum of elements in each subset is the same.
- *
- * Example:
- * Consider nums = {1, 2, 3}
- * We can split the array "nums" into two partitions, where each having a sum of 3.
- * nums1 = {1, 2}
- * nums2 = {3}
- *
- * The time complexity of the solution is O(n × sum) and requires O(n × sum) space
- */
-
-package com.thealgorithms.dynamicprogramming;
-
-import java.util.Arrays;
-
-public final class PartitionProblem {
- private PartitionProblem() {
- }
-
- /**
- * Test if a set of integers can be partitioned into two subsets such that the sum of elements
- * in each subset is the same.
- *
- * @param nums the array contains integers.
- * @return {@code true} if two subset exists, otherwise {@code false}.
- */
- public static boolean partition(int[] nums) {
- // calculate the sum of all the elements in the array
- int sum = Arrays.stream(nums).sum();
-
- // it will return true if the sum is even and the array can be divided into two
- // subarrays/subset with equal sum. and here i reuse the SubsetSum class from dynamic
- // programming section to check if there is exists a subsetsum into nums[] array same as the
- // given sum
- return (sum & 1) == 0 && SubsetSum.subsetSum(nums, sum / 2);
- }
-}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java
deleted file mode 100644
index 0c5bc2c5884d..000000000000
--- a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.thealgorithms.dynamicprogramming;
-
-/**
- * Find the number of subsets present in the given array with a sum equal to target.
- * Based on Solution discussed on
- * StackOverflow
- * @author Samrat Podder
- */
-public final class SubsetCount {
- private SubsetCount() {
- }
-
- /**
- * Dynamic Programming Implementation.
- * Method to find out the number of subsets present in the given array with a sum equal to
- * target. Time Complexity is O(n*target) and Space Complexity is O(n*target)
- * @param arr is the input array on which subsets are to searched
- * @param target is the sum of each element of the subset taken together
- *
- */
- public static int getCount(int[] arr, int target) {
- /*
- * Base Cases - If target becomes zero, we have reached the required sum for the subset
- * If we reach the end of the array arr then, either if target==arr[end], then we add one to
- * the final count Otherwise we add 0 to the final count
- */
- int n = arr.length;
- int[][] dp = new int[n][target + 1];
- for (int i = 0; i < n; i++) {
- dp[i][0] = 1;
- }
- if (arr[0] <= target) {
- dp[0][arr[0]] = 1;
- }
- for (int t = 1; t <= target; t++) {
- for (int idx = 1; idx < n; idx++) {
- int notpick = dp[idx - 1][t];
- int pick = 0;
- if (arr[idx] <= t) {
- pick += dp[idx - 1][target - t];
- }
- dp[idx][target] = pick + notpick;
- }
- }
- return dp[n - 1][target];
- }
-
- /**
- * This Method is a Space Optimized version of the getCount(int[], int) method and solves the
- * same problem This approach is a bit better in terms of Space Used Time Complexity is
- * O(n*target) and Space Complexity is O(target)
- * @param arr is the input array on which subsets are to searched
- * @param target is the sum of each element of the subset taken together
- */
- public static int getCountSO(int[] arr, int target) {
- int n = arr.length;
- int[] prev = new int[target + 1];
- prev[0] = 1;
- if (arr[0] <= target) {
- prev[arr[0]] = 1;
- }
- for (int ind = 1; ind < n; ind++) {
- int[] cur = new int[target + 1];
- cur[0] = 1;
- for (int t = 1; t <= target; t++) {
- int notTaken = prev[t];
- int taken = 0;
- if (arr[ind] <= t) {
- taken = prev[t - arr[ind]];
- }
- cur[t] = notTaken + taken;
- }
- prev = cur;
- }
- return prev[target];
- }
-}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java
deleted file mode 100644
index 3dd41d2fdc0f..000000000000
--- a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.thealgorithms.dynamicprogramming;
-
-public final class SubsetSum {
- private SubsetSum() {
- }
-
- /**
- * Test if a set of integers contains a subset that sums to a given integer.
- *
- * @param arr the array containing integers.
- * @param sum the target sum of the subset.
- * @return {@code true} if a subset exists that sums to the given value, otherwise {@code false}.
- */
- public static boolean subsetSum(int[] arr, int sum) {
- int n = arr.length;
- boolean[][] isSum = new boolean[n + 1][sum + 1];
-
- // Initialize the first column to true since a sum of 0 can always be achieved with an empty subset.
- for (int i = 0; i <= n; i++) {
- isSum[i][0] = true;
- }
-
- // Fill the subset sum matrix
- for (int i = 1; i <= n; i++) {
- for (int j = 1; j <= sum; j++) {
- if (arr[i - 1] <= j) {
- isSum[i][j] = isSum[i - 1][j] || isSum[i - 1][j - arr[i - 1]];
- } else {
- isSum[i][j] = isSum[i - 1][j];
- }
- }
- }
-
- return isSum[n][sum];
- }
-}
diff --git a/src/test/java/com/thealgorithms/Recursion/GenerateUniqueSubsetsTest.java b/src/test/java/com/thealgorithms/Recursion/GenerateUniqueSubsetsTest.java
new file mode 100644
index 000000000000..ceaa5081f0c5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/Recursion/GenerateUniqueSubsetsTest.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.Recursion;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public final class GenerateUniqueSubsetsTest {
+
+ @Test
+ void subsetRecursionTestOne() {
+ String str = "aba";
+ String[] expected = new String[] {"", "a", "aa", "ab", "aba", "b", "ba"};
+
+ List ans = GenerateUniqueSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+
+ @Test
+ void subsetRecursionTestTwo() {
+ String str = "abba";
+ String[] expected = new String[] {"", "a", "aa", "ab", "aba", "abb", "abba", "b", "ba", "bb", "bba"};
+
+ List ans = GenerateUniqueSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+
+ @Test
+ void subsetRecursionTestThree() {
+ String str = "aaa";
+ String[] expected = new String[] {"", "a", "aa", "aaa"};
+
+ List ans = GenerateUniqueSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/Recursion/TowerOfHanoiTest.java b/src/test/java/com/thealgorithms/Recursion/TowerOfHanoiTest.java
new file mode 100644
index 000000000000..404c195ae400
--- /dev/null
+++ b/src/test/java/com/thealgorithms/Recursion/TowerOfHanoiTest.java
@@ -0,0 +1,42 @@
+package com.thealgorithms.Recursion;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public final class TowerOfHanoiTest {
+
+ @Test
+ void hanoiTowerTestOne() {
+
+ int n = 5;
+ String[] expected = {"Take disk 1 from rod A to rod B", "Take disk 2 from rod A to rod C", "Take disk 1 from rod B to rod C", "Take disk 3 from rod A to rod B", "Take disk 1 from rod C to rod A", "Take disk 2 from rod C to rod B", "Take disk 1 from rod A to rod B",
+ "Take disk 4 from rod A to rod C", "Take disk 1 from rod B to rod C", "Take disk 2 from rod B to rod A", "Take disk 1 from rod C to rod A", "Take disk 3 from rod B to rod C", "Take disk 1 from rod A to rod B", "Take disk 2 from rod A to rod C", "Take disk 1 from rod B to rod C",
+ "Take disk 5 from rod A to rod B", "Take disk 1 from rod C to rod A", "Take disk 2 from rod C to rod B", "Take disk 1 from rod A to rod B", "Take disk 3 from rod C to rod A", "Take disk 1 from rod B to rod C", "Take disk 2 from rod B to rod A", "Take disk 1 from rod C to rod A",
+ "Take disk 4 from rod C to rod B", "Take disk 1 from rod A to rod B", "Take disk 2 from rod A to rod C", "Take disk 1 from rod B to rod C", "Take disk 3 from rod A to rod B", "Take disk 1 from rod C to rod A", "Take disk 2 from rod C to rod B", "Take disk 1 from rod A to rod B"};
+
+ List actual = TowerOfHanoi.towerOfHanoi(n);
+ assertArrayEquals(expected, actual.toArray());
+ }
+
+ @Test
+ void hanoiTowerTestTwo() {
+
+ int n = 3;
+ String[] expected = {"Take disk 1 from rod A to rod B", "Take disk 2 from rod A to rod C", "Take disk 1 from rod B to rod C", "Take disk 3 from rod A to rod B", "Take disk 1 from rod C to rod A", "Take disk 2 from rod C to rod B", "Take disk 1 from rod A to rod B"};
+
+ List actual = TowerOfHanoi.towerOfHanoi(n);
+ assertArrayEquals(expected, actual.toArray());
+ }
+
+ @Test
+ void hanoiTowerTestThree() {
+
+ int n = 1;
+ String[] expected = {"Take disk 1 from rod A to rod B"};
+
+ List actual = TowerOfHanoi.towerOfHanoi(n);
+ assertArrayEquals(expected, actual.toArray());
+ }
+}