elements = new ArrayList<>();
+ Node temp = this.head;
+ while (temp != null) {
+ elements.add(String.valueOf(temp.value));
+ temp = temp.next;
+ }
+ return "[" + String.join(", ", elements) + "]";
+
+ } else {
+ return "[]";
+ }
+ }
+
+ public final class Node {
+ public final int value;
+ public Node next;
+
+ public Node(int value) {
+ this.value = value;
+ this.next = null;
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java b/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java
new file mode 100644
index 000000000000..d6204455a047
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/lists/SwapNodes.java
@@ -0,0 +1,96 @@
+// Java program to swap the nodes of a linked list rather
+// than swapping the data from the nodes.
+class Node {
+ int data;
+ Node next;
+
+ Node(int data) {
+ this.data = data;
+ this.next = null;
+ }
+}
+
+public class SwapNodes {
+
+ // Function to swap nodes x and y in linked list by changing links
+ static Node swapNodes(Node head, int x, int y) {
+
+ // Nothing to do if x and y are the same
+ if (x == y) {
+ return head;
+ }
+
+ Node prevX = null, currX = null;
+ Node prevY = null, currY = null;
+ Node curr = head;
+
+ // First loop to find x
+ while (curr != null) {
+ if (curr.data == x) {
+ currX = curr;
+ break;
+ }
+ prevX = curr;
+ curr = curr.next;
+ }
+
+ curr = head;
+
+ // Second loop to find y
+ while (curr != null) {
+ if (curr.data == y) {
+ currY = curr;
+ break;
+ }
+ prevY = curr;
+ curr = curr.next;
+ }
+
+ // If either x or y is not present, nothing to do
+ if (currX == null || currY == null) {
+ return head;
+ }
+
+ // If x is not head of the linked list
+ if (prevX != null) {
+ prevX.next = currY;
+ } else {
+ head = currY;
+ }
+
+ // If y is not head of the linked list
+ if (prevY != null) {
+ prevY.next = currX;
+ } else {
+ head = currX;
+ }
+
+ // Swap next pointers
+ Node temp = currY.next;
+ currY.next = currX.next;
+ currX.next = temp;
+
+ return head;
+ }
+
+ static void printList(Node curr) {
+ while (curr != null) {
+ System.out.print(curr.data + " ");
+ curr = curr.next;
+ }
+ System.out.println();
+ }
+
+ public static void main(String[] args) {
+
+ // Constructed linked list: 1->2->3->4->5
+ Node head = new Node(1);
+ head.next = new Node(2);
+ head.next.next = new Node(3);
+ head.next.next.next = new Node(4);
+ head.next.next.next.next = new Node(5);
+
+ head = swapNodes(head, 4, 3);
+ printList(head);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java b/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java
index d166653ff1b4..a43a454146cb 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java
@@ -1,19 +1,35 @@
package com.thealgorithms.datastructures.trees;
-import java.util.Scanner;
-
/**
- * Trie Data structure implementation without any libraries
+ * Trie Data structure implementation without any libraries.
+ *
+ * The Trie (also known as a prefix tree) is a special tree-like data structure
+ * that is used to store a dynamic set or associative array where the keys are
+ * usually strings. It is highly efficient for prefix-based searches.
+ *
+ * This implementation supports basic Trie operations like insertion, search,
+ * and deletion.
+ *
+ * Each node of the Trie represents a character and has child nodes for each
+ * possible character.
*
* @author Dheeraj Kumar Barnwal
*/
public class TrieImp {
+ /**
+ * Represents a Trie Node that stores a character and pointers to its children.
+ * Each node has an array of 26 children (one for each letter from 'a' to 'z').
+ */
public class TrieNode {
TrieNode[] child;
boolean end;
+ /**
+ * Constructor to initialize a TrieNode with an empty child array
+ * and set end to false.
+ */
public TrieNode() {
child = new TrieNode[26];
end = false;
@@ -22,10 +38,22 @@ public TrieNode() {
private final TrieNode root;
+ /**
+ * Constructor to initialize the Trie.
+ * The root node is created but doesn't represent any character.
+ */
public TrieImp() {
root = new TrieNode();
}
+ /**
+ * Inserts a word into the Trie.
+ *
+ * The method traverses the Trie from the root, character by character, and adds
+ * nodes if necessary. It marks the last node of the word as an end node.
+ *
+ * @param word The word to be inserted into the Trie.
+ */
public void insert(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
@@ -39,6 +67,16 @@ public void insert(String word) {
currentNode.end = true;
}
+ /**
+ * Searches for a word in the Trie.
+ *
+ * This method traverses the Trie based on the input word and checks whether
+ * the word exists. It returns true if the word is found and its end flag is
+ * true.
+ *
+ * @param word The word to search in the Trie.
+ * @return true if the word exists in the Trie, false otherwise.
+ */
public boolean search(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
@@ -52,6 +90,17 @@ public boolean search(String word) {
return currentNode.end;
}
+ /**
+ * Deletes a word from the Trie.
+ *
+ * The method traverses the Trie to find the word and marks its end flag as
+ * false.
+ * It returns true if the word was successfully deleted, false if the word
+ * wasn't found.
+ *
+ * @param word The word to be deleted from the Trie.
+ * @return true if the word was found and deleted, false if it was not found.
+ */
public boolean delete(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
@@ -69,75 +118,26 @@ public boolean delete(String word) {
return false;
}
+ /**
+ * Helper method to print a string to the console.
+ *
+ * @param print The string to be printed.
+ */
public static void sop(String print) {
System.out.println(print);
}
/**
- * Regex to check if word contains only a-z character
+ * Validates if a given word contains only lowercase alphabetic characters
+ * (a-z).
+ *
+ * The method uses a regular expression to check if the word matches the pattern
+ * of only lowercase letters.
+ *
+ * @param word The word to be validated.
+ * @return true if the word is valid (only a-z), false otherwise.
*/
public static boolean isValid(String word) {
return word.matches("^[a-z]+$");
}
-
- public static void main(String[] args) {
- TrieImp obj = new TrieImp();
- String word;
- @SuppressWarnings("resource") Scanner scan = new Scanner(System.in);
- sop("string should contain only a-z character for all operation");
- while (true) {
- sop("1. Insert\n2. Search\n3. Delete\n4. Quit");
- try {
- int t = scan.nextInt();
- switch (t) {
- case 1:
- word = scan.next();
- if (isValid(word)) {
- obj.insert(word);
- } else {
- sop("Invalid string: allowed only a-z");
- }
- break;
- case 2:
- word = scan.next();
- boolean resS = false;
- if (isValid(word)) {
- resS = obj.search(word);
- } else {
- sop("Invalid string: allowed only a-z");
- }
- if (resS) {
- sop("word found");
- } else {
- sop("word not found");
- }
- break;
- case 3:
- word = scan.next();
- boolean resD = false;
- if (isValid(word)) {
- resD = obj.delete(word);
- } else {
- sop("Invalid string: allowed only a-z");
- }
- if (resD) {
- sop("word got deleted successfully");
- } else {
- sop("word not found");
- }
- break;
- case 4:
- sop("Quit successfully");
- System.exit(1);
- break;
- default:
- sop("Input int from 1-4");
- break;
- }
- } catch (Exception e) {
- String badInput = scan.next();
- sop("This is bad input: " + badInput);
- }
- }
- }
}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java
new file mode 100644
index 000000000000..b5ac62b4674b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java
@@ -0,0 +1,42 @@
+package com.thealgorithms.dynamicprogramming;
+
+import java.util.HashMap;
+
+final class LongestArithmeticSubsequence {
+ private LongestArithmeticSubsequence() {
+ }
+
+ /**
+ * Returns the length of the longest arithmetic subsequence in the given array.
+ *
+ * A sequence seq is arithmetic if seq[i + 1] - seq[i] are all the same value
+ * (for 0 <= i < seq.length - 1).
+ *
+ * @param nums the input array of integers
+ * @return the length of the longest arithmetic subsequence
+ */
+ public static int getLongestArithmeticSubsequenceLength(int[] nums) {
+ if (nums == null) {
+ throw new IllegalArgumentException("Input array cannot be null");
+ }
+
+ if (nums.length <= 1) {
+ return nums.length;
+ }
+
+ HashMap[] dp = new HashMap[nums.length];
+ int maxLength = 2;
+
+ // fill the dp array
+ for (int i = 0; i < nums.length; i++) {
+ dp[i] = new HashMap<>();
+ for (int j = 0; j < i; j++) {
+ final int diff = nums[i] - nums[j];
+ dp[i].put(diff, dp[j].getOrDefault(diff, 1) + 1);
+ maxLength = Math.max(maxLength, dp[i].get(diff));
+ }
+ }
+
+ return maxLength;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java
index 2d1fa1d1153f..54837b5f4e71 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java
@@ -1,73 +1,98 @@
package com.thealgorithms.dynamicprogramming;
+/**
+ * This class implements the Longest Common Subsequence (LCS) problem.
+ * The LCS of two sequences is the longest sequence that appears in both
+ * sequences
+ * in the same order, but not necessarily consecutively.
+ *
+ * This implementation uses dynamic programming to find the LCS of two strings.
+ */
final class LongestCommonSubsequence {
+
private LongestCommonSubsequence() {
}
+ /**
+ * Returns the Longest Common Subsequence (LCS) of two given strings.
+ *
+ * @param str1 The first string.
+ * @param str2 The second string.
+ * @return The LCS of the two strings, or null if one of the strings is null.
+ */
public static String getLCS(String str1, String str2) {
- // At least one string is null
+ // If either string is null, return null as LCS can't be computed.
if (str1 == null || str2 == null) {
return null;
}
-
- // At least one string is empty
+ // If either string is empty, return an empty string as LCS.
if (str1.length() == 0 || str2.length() == 0) {
return "";
}
+ // Convert the strings into arrays of characters
String[] arr1 = str1.split("");
String[] arr2 = str2.split("");
- // lcsMatrix[i][j] = LCS of first i elements of arr1 and first j characters of arr2
+ // lcsMatrix[i][j] = LCS(first i characters of str1, first j characters of str2)
int[][] lcsMatrix = new int[arr1.length + 1][arr2.length + 1];
+ // Base Case: Fill the LCS matrix 0th row & 0th column with 0s
+ // as LCS of any string with an empty string is 0.
for (int i = 0; i < arr1.length + 1; i++) {
lcsMatrix[i][0] = 0;
}
for (int j = 1; j < arr2.length + 1; j++) {
lcsMatrix[0][j] = 0;
}
+
+ // Build the LCS matrix by comparing characters of str1 & str2
for (int i = 1; i < arr1.length + 1; i++) {
for (int j = 1; j < arr2.length + 1; j++) {
+ // If characters match, the LCS increases by 1
if (arr1[i - 1].equals(arr2[j - 1])) {
lcsMatrix[i][j] = lcsMatrix[i - 1][j - 1] + 1;
} else {
+ // Otherwise, take the maximum of the left or above values
lcsMatrix[i][j] = Math.max(lcsMatrix[i - 1][j], lcsMatrix[i][j - 1]);
}
}
}
+
+ // Call helper function to reconstruct the LCS from the matrix
return lcsString(str1, str2, lcsMatrix);
}
+ /**
+ * Reconstructs the LCS string from the LCS matrix.
+ *
+ * @param str1 The first string.
+ * @param str2 The second string.
+ * @param lcsMatrix The matrix storing the lengths of LCSs
+ * of substrings of str1 and str2.
+ * @return The LCS string.
+ */
public static String lcsString(String str1, String str2, int[][] lcsMatrix) {
- StringBuilder lcs = new StringBuilder();
- int i = str1.length();
- int j = str2.length();
+ StringBuilder lcs = new StringBuilder(); // Hold the LCS characters.
+ int i = str1.length(); // Start from the end of str1.
+ int j = str2.length(); // Start from the end of str2.
+
+ // Trace back through the LCS matrix to reconstruct the LCS
while (i > 0 && j > 0) {
+ // If characters match, add to the LCS and move diagonally in the matrix
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
lcs.append(str1.charAt(i - 1));
i--;
j--;
} else if (lcsMatrix[i - 1][j] > lcsMatrix[i][j - 1]) {
+ // If the value above is larger, move up
i--;
} else {
+ // If the value to the left is larger, move left
j--;
}
}
- return lcs.reverse().toString();
- }
- public static void main(String[] args) {
- String str1 = "DSGSHSRGSRHTRD";
- String str2 = "DATRGAGTSHS";
- String lcs = getLCS(str1, str2);
-
- // Print LCS
- if (lcs != null) {
- System.out.println("String 1: " + str1);
- System.out.println("String 2: " + str2);
- System.out.println("LCS: " + lcs);
- System.out.println("LCS length: " + lcs.length());
- }
+ return lcs.reverse().toString(); // LCS built in reverse, so reverse it back
}
}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java b/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java
index dd48008bd21e..e9c15c1b4f24 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java
@@ -1,9 +1,35 @@
package com.thealgorithms.dynamicprogramming;
+/**
+ * A utility class that contains the Sum of Subset problem solution using
+ * recursion.
+ *
+ * The Sum of Subset problem determines whether a subset of elements from a
+ * given array sums up to a specific target value.
+ *
+ * Wikipedia: https://en.wikipedia.org/wiki/Subset_sum_problem
+ */
public final class SumOfSubset {
+
private SumOfSubset() {
}
+ /**
+ * Determines if there exists a subset of elements in the array `arr` that
+ * adds up to the given `key` value using recursion.
+ *
+ * @param arr The array of integers.
+ * @param num The index of the current element being considered.
+ * @param key The target sum we are trying to achieve.
+ * @return true if a subset of `arr` adds up to `key`, false otherwise.
+ *
+ * This is a recursive solution that checks for two possibilities at
+ * each step:
+ * 1. Include the current element in the subset and check if the
+ * remaining elements can sum up to the remaining target.
+ * 2. Exclude the current element and check if the remaining elements
+ * can sum up to the target without this element.
+ */
public static boolean subsetSum(int[] arr, int num, int key) {
if (key == 0) {
return true;
@@ -14,7 +40,6 @@ public static boolean subsetSum(int[] arr, int num, int key) {
boolean include = subsetSum(arr, num - 1, key - arr[num]);
boolean exclude = subsetSum(arr, num - 1, key);
-
return include || exclude;
}
}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java b/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java
new file mode 100644
index 000000000000..bee5f98cd2ee
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java
@@ -0,0 +1,40 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class provides methods to separate the digits of a large positive number into a list.
+ */
+public class DigitSeparation {
+ public DigitSeparation() {
+ }
+ /**
+ * Separates the digits of a large positive number into a list in reverse order.
+ * @param largeNumber The large number to separate digits from.
+ * @return A list of digits in reverse order.
+ */
+ public List digitSeparationReverseOrder(long largeNumber) {
+ List result = new ArrayList<>();
+ if (largeNumber != 0) {
+ while (largeNumber != 0) {
+ result.add(Math.abs(largeNumber % 10));
+ largeNumber = largeNumber / 10;
+ }
+ } else {
+ result.add(0L);
+ }
+ return result;
+ }
+ /**
+ * Separates the digits of a large positive number into a list in forward order.
+ * @param largeNumber The large number to separate digits from.
+ * @return A list of digits in forward order.
+ */
+ public List digitSeparationForwardOrder(long largeNumber) {
+ List result = this.digitSeparationReverseOrder(largeNumber);
+ Collections.reverse(result);
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java
new file mode 100644
index 000000000000..07bd0b73326f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java
@@ -0,0 +1,64 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Problem Statement:
+ * Given an array of intervals where intervals[i] = [starti, endi].
+ *
+ * Merge all overlapping intervals and return an array of the non-overlapping
+ * intervals
+ * that cover all the intervals in the input.
+ */
+public final class MergeIntervals {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ */
+ private MergeIntervals() {
+ }
+
+ /**
+ * Merges overlapping intervals from the given array of intervals.
+ *
+ * The method sorts the intervals by their start time, then iterates through the
+ * sorted intervals
+ * and merges overlapping intervals. If an interval overlaps with the last
+ * merged interval,
+ * it updates the end time of the last merged interval. Otherwise, it adds the
+ * interval as a new entry.
+ *
+ * @param intervals A 2D array representing intervals where each element is an
+ * interval [starti, endi].
+ * @return A 2D array of merged intervals where no intervals overlap.
+ *
+ * Example:
+ * Input: {{1, 3}, {2, 6}, {8, 10}, {15, 18}}
+ * Output: {{1, 6}, {8, 10}, {15, 18}}
+ */
+ public static int[][] merge(int[][] intervals) {
+ // Sort the intervals by their start time (ascending order)
+ Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0]));
+
+ // List to store merged intervals
+ List merged = new ArrayList<>();
+
+ for (int[] interval : intervals) { // Each interval
+ // If the merged list is empty or the current interval does not overlap with
+ // the last merged interval, add it to the merged list.
+ if (merged.isEmpty() || interval[0] > merged.get(merged.size() - 1)[1]) {
+ merged.add(interval);
+ } else {
+ // If there is an overlap, merge the intervals by updating the end time
+ // of the last merged interval to the maximum end time between the two
+ // intervals.
+ merged.get(merged.size() - 1)[1] = Math.max(merged.get(merged.size() - 1)[1], interval[1]);
+ }
+ }
+
+ // Convert the list of merged intervals back to a 2D array and return it
+ return merged.toArray(new int[merged.size()][]);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/misc/Sort012D.java b/src/main/java/com/thealgorithms/misc/Sort012D.java
deleted file mode 100644
index 706e877e40c1..000000000000
--- a/src/main/java/com/thealgorithms/misc/Sort012D.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.thealgorithms.misc;
-
-import java.util.Scanner;
-
-/**
- * The array is divided into four sections: a[1..Lo-1] zeroes a[Lo..Mid-1] ones
- * a[Mid..Hi] unknown a[Hi+1..N] twos If array [mid] =0, then swap array [mid]
- * with array [low] and increment both pointers once. If array [mid] = 1, then
- * no swapping is required. Increment mid pointer once. If array [mid] = 2, then
- * we swap array [mid] with array [high] and decrement the high pointer once.
- * For more information on the Dutch national flag algorithm refer
- * https://en.wikipedia.org/wiki/Dutch_national_flag_problem
- */
-public final class Sort012D {
- private Sort012D() {
- }
-
- public static void main(String[] args) {
- Scanner np = new Scanner(System.in);
- int n = np.nextInt();
- int[] a = new int[n];
- for (int i = 0; i < n; i++) {
- a[i] = np.nextInt();
- }
- sort012(a);
- np.close();
- }
-
- public static void sort012(int[] a) {
- int l = 0;
- int h = a.length - 1;
- int mid = 0;
- int temp;
- while (mid <= h) {
- switch (a[mid]) {
- case 0:
- temp = a[l];
- a[l] = a[mid];
- a[mid] = temp;
- l++;
- mid++;
- break;
-
- case 1:
- mid++;
- break;
- case 2:
- temp = a[mid];
- a[mid] = a[h];
- a[h] = temp;
- h--;
- break;
-
- default:
- throw new IllegalArgumentException("Unexpected value: " + a[mid]);
- }
- }
- System.out.println("the Sorted array is ");
- for (int i = 0; i < a.length; i++) {
- System.out.print(+a[i] + " ");
- }
- }
-}
diff --git a/src/test/java/com/thealgorithms/others/ArrayRightRotation.java b/src/main/java/com/thealgorithms/others/ArrayRightRotation.java
similarity index 52%
rename from src/test/java/com/thealgorithms/others/ArrayRightRotation.java
rename to src/main/java/com/thealgorithms/others/ArrayRightRotation.java
index 11e4f44500b1..125edadb6e73 100644
--- a/src/test/java/com/thealgorithms/others/ArrayRightRotation.java
+++ b/src/main/java/com/thealgorithms/others/ArrayRightRotation.java
@@ -1,8 +1,23 @@
package com.thealgorithms.others;
+/**
+ * Provides a method to perform a right rotation on an array.
+ * A left rotation operation shifts each element of the array
+ * by a specified number of positions to the right.
+ *
+ * https://en.wikipedia.org/wiki/Right_rotation *
+ */
public final class ArrayRightRotation {
private ArrayRightRotation() {
}
+
+ /**
+ * Performs a right rotation on the given array by the specified number of positions.
+ *
+ * @param arr the array to be rotated
+ * @param k the number of positions to rotate the array to the left
+ * @return a new array containing the elements of the input array rotated to the left
+ */
public static int[] rotateRight(int[] arr, int k) {
if (arr == null || arr.length == 0 || k < 0) {
throw new IllegalArgumentException("Invalid input");
@@ -18,6 +33,12 @@ public static int[] rotateRight(int[] arr, int k) {
return arr;
}
+ /**
+ * Performs reversing of a array
+ * @param arr the array to be reversed
+ * @param start starting position
+ * @param end ending position
+ */
private static void reverseArray(int[] arr, int start, int end) {
while (start < end) {
int temp = arr[start];
diff --git a/src/main/java/com/thealgorithms/others/Sudoku.java b/src/main/java/com/thealgorithms/others/Sudoku.java
index 0839a376c5de..0e88aee46f4d 100644
--- a/src/main/java/com/thealgorithms/others/Sudoku.java
+++ b/src/main/java/com/thealgorithms/others/Sudoku.java
@@ -1,33 +1,47 @@
package com.thealgorithms.others;
+/**
+ * A class that provides methods to solve Sudoku puzzles of any n x n size
+ * using a backtracking approach, where n must be a perfect square.
+ * The algorithm checks for safe number placements in rows, columns,
+ * and subgrids (which are sqrt(n) x sqrt(n) in size) and recursively solves the puzzle.
+ * Though commonly used for 9x9 grids, it is adaptable to other valid Sudoku dimensions.
+ */
final class Sudoku {
+
private Sudoku() {
}
+ /**
+ * Checks if placing a number in a specific position on the Sudoku board is safe.
+ * The number is considered safe if it does not violate any of the Sudoku rules:
+ * - It should not be present in the same row.
+ * - It should not be present in the same column.
+ * - It should not be present in the corresponding 3x3 subgrid.
+ * - It should not be present in the corresponding subgrid, which is sqrt(n) x sqrt(n) in size (e.g., for a 9x9 grid, the subgrid will be 3x3).
+ *
+ * @param board The current state of the Sudoku board.
+ * @param row The row index where the number is to be placed.
+ * @param col The column index where the number is to be placed.
+ * @param num The number to be placed on the board.
+ * @return True if the placement is safe, otherwise false.
+ */
public static boolean isSafe(int[][] board, int row, int col, int num) {
- // Row has the unique (row-clash)
+ // Check the row for duplicates
for (int d = 0; d < board.length; d++) {
- // Check if the number we are trying to
- // place is already present in
- // that row, return false;
if (board[row][d] == num) {
return false;
}
}
- // Column has the unique numbers (column-clash)
+ // Check the column for duplicates
for (int r = 0; r < board.length; r++) {
- // Check if the number
- // we are trying to
- // place is already present in
- // that column, return false;
if (board[r][col] == num) {
return false;
}
}
- // Corresponding square has
- // unique number (box-clash)
+ // Check the corresponding 3x3 subgrid for duplicates
int sqrt = (int) Math.sqrt(board.length);
int boxRowStart = row - row % sqrt;
int boxColStart = col - col % sqrt;
@@ -40,22 +54,37 @@ public static boolean isSafe(int[][] board, int row, int col, int num) {
}
}
- // if there is no clash, it's safe
return true;
}
+ /**
+ * Solves the Sudoku puzzle using backtracking.
+ * The algorithm finds an empty cell and tries placing numbers
+ * from 1 to n, where n is the size of the board
+ * (for example, from 1 to 9 in a standard 9x9 Sudoku).
+ * The algorithm finds an empty cell and tries placing numbers from 1 to 9.
+ * The standard version of Sudoku uses numbers from 1 to 9, so the algorithm can be
+ * easily modified for other variations of the game.
+ * If a number placement is valid (checked via `isSafe`), the number is
+ * placed and the function recursively attempts to solve the rest of the puzzle.
+ * If no solution is possible, the number is removed (backtracked),
+ * and the process is repeated.
+ *
+ * @param board The current state of the Sudoku board.
+ * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
+ * @return True if the Sudoku puzzle is solvable, false otherwise.
+ */
public static boolean solveSudoku(int[][] board, int n) {
int row = -1;
int col = -1;
boolean isEmpty = true;
+
+ // Find the next empty cell
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (board[i][j] == 0) {
row = i;
col = j;
-
- // We still have some remaining
- // missing values in Sudoku
isEmpty = false;
break;
}
@@ -70,12 +99,12 @@ public static boolean solveSudoku(int[][] board, int n) {
return true;
}
- // Else for each-row backtrack
+ // Try placing numbers 1 to n in the empty cell (n should be a perfect square)
+ // Eg: n=9 for a standard 9x9 Sudoku puzzle, n=16 for a 16x16 puzzle, etc.
for (int num = 1; num <= n; num++) {
if (isSafe(board, row, col, num)) {
board[row][col] = num;
if (solveSudoku(board, n)) {
- // print(board, n);
return true;
} else {
// replace it
@@ -86,8 +115,17 @@ public static boolean solveSudoku(int[][] board, int n) {
return false;
}
+ /**
+ * Prints the current state of the Sudoku board in a readable format.
+ * Each row is printed on a new line, with numbers separated by spaces.
+ *
+ * @param board The current state of the Sudoku board.
+ * @param n The size of the Sudoku board (typically 9 for a standard puzzle).
+ */
public static void print(int[][] board, int n) {
- // We got the answer, just print it
+ // Print the board in a nxn grid format
+ // if n=9, print the board in a 9x9 grid format
+ // if n=16, print the board in a 16x16 grid format
for (int r = 0; r < n; r++) {
for (int d = 0; d < n; d++) {
System.out.print(board[r][d]);
@@ -101,7 +139,13 @@ public static void print(int[][] board, int n) {
}
}
- // Driver Code
+ /**
+ * The driver method to demonstrate solving a Sudoku puzzle.
+ * A sample 9x9 Sudoku puzzle is provided, and the program attempts to solve it
+ * using the `solveSudoku` method. If a solution is found, it is printed to the console.
+ *
+ * @param args Command-line arguments (not used in this program).
+ */
public static void main(String[] args) {
int[][] board = new int[][] {
{3, 0, 6, 5, 0, 8, 4, 0, 0},
@@ -117,7 +161,6 @@ public static void main(String[] args) {
int n = board.length;
if (solveSudoku(board, n)) {
- // print solution
print(board, n);
} else {
System.out.println("No solution");
diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java b/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java
index 53f5d7c8434e..aa938447b864 100644
--- a/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java
+++ b/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java
@@ -1,87 +1,127 @@
package com.thealgorithms.searches;
-/*
-To apply this method, the provided array must be strictly sorted. In this method, two pointers, one
-at 0th row & the other at the last row are taken & the searching is done on the basis of the middle
-element of the middle column. If that element is equal to target, its coordinates are returned, else
-if it is smaller than the target, the rows above that element are ignored (because the elements
-above it will also be smaller than the target), else that element is greater than the target, then
-the rows below it are ignored.
+/**
+ * This class provides a method to search for a target value in a 2D sorted
+ * array.
+ * The search is performed using a combination of binary search on rows and
+ * columns.
+ * The 2D array must be strictly sorted in both rows and columns.
+ *
+ * The algorithm works by:
+ * 1. Performing a binary search on the middle column of the 2D array.
+ * 2. Depending on the value found, it eliminates rows above or below the middle
+ * element.
+ * 3. After finding or eliminating rows, it further applies binary search in the
+ * relevant columns.
*/
public final class BinarySearch2dArray {
+
private BinarySearch2dArray() {
}
+ /**
+ * Performs a binary search on a 2D sorted array to find the target value.
+ * The array must be sorted in ascending order in both rows and columns.
+ *
+ * @param arr The 2D array to search in.
+ * @param target The value to search for.
+ * @return An array containing the row and column indices of the target, or [-1,
+ * -1] if the target is not found.
+ */
static int[] binarySearch(int[][] arr, int target) {
int rowCount = arr.length;
int colCount = arr[0].length;
+ // Edge case: If there's only one row, search that row directly.
if (rowCount == 1) {
return binarySearch(arr, target, 0, 0, colCount);
}
+ // Set initial boundaries for binary search on rows.
int startRow = 0;
int endRow = rowCount - 1;
- int midCol = colCount / 2;
+ int midCol = colCount / 2; // Middle column index for comparison.
+ // Perform binary search on rows based on the middle column.
while (startRow < endRow - 1) {
- int midRow = startRow + (endRow - startRow) / 2; // getting the index of middle row
+ int midRow = startRow + (endRow - startRow) / 2;
+ // If the middle element matches the target, return its position.
if (arr[midRow][midCol] == target) {
return new int[] {midRow, midCol};
- } else if (arr[midRow][midCol] < target) {
+ }
+ // If the middle element is smaller than the target, discard the upper half.
+ else if (arr[midRow][midCol] < target) {
startRow = midRow;
- } else {
+ }
+ // If the middle element is larger than the target, discard the lower half.
+ else {
endRow = midRow;
}
}
- /*
- if the above search fails to find the target element, these conditions will be used to
- find the target element, which further uses the binary search algorithm in the places
- which were left unexplored.
- */
+
+ // If the target wasn't found during the row search, check the middle column of
+ // startRow and endRow.
if (arr[startRow][midCol] == target) {
- return new int[] {
- startRow,
- midCol,
- };
+ return new int[] {startRow, midCol};
}
if (arr[endRow][midCol] == target) {
return new int[] {endRow, midCol};
}
+ // If target is smaller than the element in the left of startRow, perform a
+ // binary search on the left of startRow.
if (target <= arr[startRow][midCol - 1]) {
return binarySearch(arr, target, startRow, 0, midCol - 1);
}
+ // If target is between midCol and the last column of startRow, perform a binary
+ // search on that part of the row.
if (target >= arr[startRow][midCol + 1] && target <= arr[startRow][colCount - 1]) {
return binarySearch(arr, target, startRow, midCol + 1, colCount - 1);
}
+ // If target is smaller than the element in the left of endRow, perform a binary
+ // search on the left of endRow.
if (target <= arr[endRow][midCol - 1]) {
return binarySearch(arr, target, endRow, 0, midCol - 1);
} else {
+ // Otherwise, search on the right of endRow.
return binarySearch(arr, target, endRow, midCol + 1, colCount - 1);
}
}
+ /**
+ * Performs a binary search on a specific row of the 2D array.
+ *
+ * @param arr The 2D array to search in.
+ * @param target The value to search for.
+ * @param row The row index where the target will be searched.
+ * @param colStart The starting column index for the search.
+ * @param colEnd The ending column index for the search.
+ * @return An array containing the row and column indices of the target, or [-1,
+ * -1] if the target is not found.
+ */
static int[] binarySearch(int[][] arr, int target, int row, int colStart, int colEnd) {
+ // Perform binary search within the specified column range.
while (colStart <= colEnd) {
int midIndex = colStart + (colEnd - colStart) / 2;
+ // If the middle element matches the target, return its position.
if (arr[row][midIndex] == target) {
- return new int[] {
- row,
- midIndex,
- };
- } else if (arr[row][midIndex] < target) {
+ return new int[] {row, midIndex};
+ }
+ // If the middle element is smaller than the target, move to the right half.
+ else if (arr[row][midIndex] < target) {
colStart = midIndex + 1;
- } else {
+ }
+ // If the middle element is larger than the target, move to the left half.
+ else {
colEnd = midIndex - 1;
}
}
- return new int[] {-1, -1};
+ return new int[] {-1, -1}; // Target not found
}
}
diff --git a/src/main/java/com/thealgorithms/sorts/DNFSort.java b/src/main/java/com/thealgorithms/sorts/DNFSort.java
deleted file mode 100644
index 4b1e913cf3e0..000000000000
--- a/src/main/java/com/thealgorithms/sorts/DNFSort.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.thealgorithms.sorts;
-
-public final class DNFSort {
- private DNFSort() {
- }
-
- // Sort the input array, the array is assumed to
- // have values in {0, 1, 2}
- static void sort012(int[] a, int arrSize) {
- int low = 0;
- int high = arrSize - 1;
- int mid = 0;
- int temp;
- while (mid <= high) {
- switch (a[mid]) {
- case 0:
- temp = a[low];
- a[low] = a[mid];
- a[mid] = temp;
- low++;
- mid++;
- break;
-
- case 1:
- mid++;
- break;
- case 2:
- temp = a[mid];
- a[mid] = a[high];
- a[high] = temp;
- high--;
- break;
-
- default:
- throw new IllegalArgumentException("Unexpected value: " + a[mid]);
- }
- }
- }
-
- /* Utility function to print array arr[] */
- static void printArray(int[] arr, int arrSize) {
- for (int i = 0; i < arrSize; i++) {
- System.out.print(arr[i] + " ");
- }
- System.out.println();
- }
-
- /*Driver function to check for above functions*/
- public static void main(String[] args) {
- int[] arr = {0, 1, 1, 0, 1, 2, 1, 2, 0, 0, 0, 1};
- int arrSize = arr.length;
- sort012(arr, arrSize);
- System.out.println("Array after seggregation ");
- printArray(arr, arrSize);
- }
-}
diff --git a/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java
new file mode 100644
index 000000000000..3d90d14e0d1e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java
@@ -0,0 +1,92 @@
+package com.thealgorithms.stacks;
+
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class InfixToPrefix {
+ private InfixToPrefix() {
+ }
+
+ /**
+ * Convert an infix expression to a prefix expression using stack.
+ *
+ * @param infixExpression the infix expression to convert
+ * @return the prefix expression
+ * @throws IllegalArgumentException if the infix expression has unbalanced brackets
+ * @throws NullPointerException if the infix expression is null
+ */
+ public static String infix2Prefix(String infixExpression) throws IllegalArgumentException {
+ if (infixExpression == null) {
+ throw new NullPointerException("Input expression cannot be null.");
+ }
+ infixExpression = infixExpression.trim();
+ if (infixExpression.isEmpty()) {
+ return "";
+ }
+ if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) {
+ throw new IllegalArgumentException("Invalid expression: unbalanced brackets.");
+ }
+
+ StringBuilder output = new StringBuilder();
+ Stack stack = new Stack<>();
+ // Reverse the infix expression for prefix conversion
+ String reversedInfix = new StringBuilder(infixExpression).reverse().toString();
+ for (char element : reversedInfix.toCharArray()) {
+ if (Character.isLetterOrDigit(element)) {
+ output.append(element);
+ } else if (element == ')') {
+ stack.push(element);
+ } else if (element == '(') {
+ while (!stack.isEmpty() && stack.peek() != ')') {
+ output.append(stack.pop());
+ }
+ stack.pop();
+ } else {
+ while (!stack.isEmpty() && precedence(element) < precedence(stack.peek())) {
+ output.append(stack.pop());
+ }
+ stack.push(element);
+ }
+ }
+ while (!stack.isEmpty()) {
+ output.append(stack.pop());
+ }
+
+ // Reverse the result to get the prefix expression
+ return output.reverse().toString();
+ }
+
+ /**
+ * Determines the precedence of an operator.
+ *
+ * @param operator the operator whose precedence is to be determined
+ * @return the precedence of the operator
+ */
+ private static int precedence(char operator) {
+ switch (operator) {
+ case '+':
+ case '-':
+ return 0;
+ case '*':
+ case '/':
+ return 1;
+ case '^':
+ return 2;
+ default:
+ return -1;
+ }
+ }
+
+ /**
+ * Filters out all characters from the input string except brackets.
+ *
+ * @param input the input string to filter
+ * @return a string containing only brackets from the input string
+ */
+ private static String filterBrackets(String input) {
+ Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]");
+ Matcher matcher = pattern.matcher(input);
+ return matcher.replaceAll("");
+ }
+}
diff --git a/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java b/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java
new file mode 100644
index 000000000000..41eb974b0e5b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.stacks;
+
+import java.util.Stack;
+
+/**
+ * Converts a prefix expression to an infix expression using a stack.
+ *
+ * The input prefix expression should consist of
+ * valid operands (letters or digits) and operators (+, -, *, /, ^).
+ * Parentheses are not required in the prefix string.
+ */
+public final class PrefixToInfix {
+ private PrefixToInfix() {
+ }
+
+ /**
+ * Determines if a given character is a valid arithmetic operator.
+ *
+ * @param token the character to check
+ * @return true if the character is an operator, false otherwise
+ */
+ public static boolean isOperator(char token) {
+ return token == '+' || token == '-' || token == '/' || token == '*' || token == '^';
+ }
+
+ /**
+ * Converts a valid prefix expression to an infix expression.
+ *
+ * @param prefix the prefix expression to convert
+ * @return the equivalent infix expression
+ * @throws NullPointerException if the prefix expression is null
+ */
+ public static String getPrefixToInfix(String prefix) {
+ if (prefix == null) {
+ throw new NullPointerException("Null prefix expression");
+ }
+ if (prefix.isEmpty()) {
+ return "";
+ }
+
+ Stack stack = new Stack<>();
+
+ // Iterate over the prefix expression from right to left
+ for (int i = prefix.length() - 1; i >= 0; i--) {
+ char token = prefix.charAt(i);
+
+ if (isOperator(token)) {
+ // Pop two operands from stack
+ String operandA = stack.pop();
+ String operandB = stack.pop();
+
+ // Form the infix expression with parentheses
+ String infix = "(" + operandA + token + operandB + ")";
+
+ // Push the resulting infix expression back onto the stack
+ stack.push(infix);
+ } else {
+ // Push operand onto stack
+ stack.push(Character.toString(token));
+ }
+ }
+
+ if (stack.size() != 1) {
+ throw new ArithmeticException("Malformed prefix expression");
+ }
+
+ return stack.pop(); // final element on the stack is the full infix expression
+ }
+}
diff --git a/src/main/java/com/thealgorithms/others/CountChar.java b/src/main/java/com/thealgorithms/strings/CountChar.java
similarity index 93%
rename from src/main/java/com/thealgorithms/others/CountChar.java
rename to src/main/java/com/thealgorithms/strings/CountChar.java
index 00cff6860216..348905445347 100644
--- a/src/main/java/com/thealgorithms/others/CountChar.java
+++ b/src/main/java/com/thealgorithms/strings/CountChar.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
public final class CountChar {
private CountChar() {
diff --git a/src/main/java/com/thealgorithms/others/CountWords.java b/src/main/java/com/thealgorithms/strings/CountWords.java
similarity index 97%
rename from src/main/java/com/thealgorithms/others/CountWords.java
rename to src/main/java/com/thealgorithms/strings/CountWords.java
index 515c5d33fbf3..8ab0700f5586 100644
--- a/src/main/java/com/thealgorithms/others/CountWords.java
+++ b/src/main/java/com/thealgorithms/strings/CountWords.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
/**
* @author Marcus
diff --git a/src/main/java/com/thealgorithms/others/ReturnSubsequence.java b/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java
similarity index 97%
rename from src/main/java/com/thealgorithms/others/ReturnSubsequence.java
rename to src/main/java/com/thealgorithms/strings/ReturnSubsequence.java
index 7ef660ce6579..afa8c5f98678 100644
--- a/src/main/java/com/thealgorithms/others/ReturnSubsequence.java
+++ b/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
/**
* Class for generating all subsequences of a given string.
diff --git a/src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java b/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java
similarity index 99%
rename from src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java
rename to src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java
index 561845f41a07..719898a1fd74 100644
--- a/src/main/java/com/thealgorithms/others/StringMatchFiniteAutomata.java
+++ b/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
import java.util.Set;
import java.util.TreeSet;
diff --git a/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java b/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java
new file mode 100644
index 000000000000..d4bc7e488f80
--- /dev/null
+++ b/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.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 GenerateSubsetsTest {
+
+ @Test
+ void subsetRecursionTestOne() {
+ String str = "abc";
+ String[] expected = new String[] {"abc", "ab", "ac", "a", "bc", "b", "c", ""};
+
+ List ans = GenerateSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+
+ @Test
+ void subsetRecursionTestTwo() {
+ String str = "cbf";
+ String[] expected = new String[] {"cbf", "cb", "cf", "c", "bf", "b", "f", ""};
+
+ List ans = GenerateSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+
+ @Test
+ void subsetRecursionTestThree() {
+ String str = "aba";
+ String[] expected = new String[] {"aba", "ab", "aa", "a", "ba", "b", "a", ""};
+
+ List ans = GenerateSubsets.subsetRecursion(str);
+ assertArrayEquals(ans.toArray(), expected);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/others/CountSetBitsTest.java b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
similarity index 90%
rename from src/test/java/com/thealgorithms/others/CountSetBitsTest.java
rename to src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
index ab34c6ba7876..412312109bec 100644
--- a/src/test/java/com/thealgorithms/others/CountSetBitsTest.java
+++ b/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.bitmanipulation;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java b/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java
new file mode 100644
index 000000000000..8121b6177aa9
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class HillCipherTest {
+
+ HillCipher hillCipher = new HillCipher();
+
+ @Test
+ void hillCipherEncryptTest() {
+ // given
+ String message = "ACT"; // Plaintext message
+ int[][] keyMatrix = {{6, 24, 1}, {13, 16, 10}, {20, 17, 15}}; // Encryption key matrix
+
+ // when
+ String cipherText = hillCipher.encrypt(message, keyMatrix);
+
+ // then
+ assertEquals("POH", cipherText);
+ }
+
+ @Test
+ void hillCipherDecryptTest() {
+ // given
+ String cipherText = "POH"; // Ciphertext message
+ int[][] inverseKeyMatrix = {{8, 5, 10}, {21, 8, 21}, {21, 12, 8}}; // Decryption (inverse key) matrix
+
+ // when
+ String plainText = hillCipher.decrypt(cipherText, inverseKeyMatrix);
+
+ // then
+ assertEquals("ACT", plainText);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java
new file mode 100644
index 000000000000..15e27d5d6778
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class XORCipherTest {
+
+ @Test
+ void xorEncryptTest() {
+ // given
+ String plaintext = "My t&xt th@t will be ençrypted...";
+ String key = "My ç&cret key!";
+
+ // when
+ String cipherText = XORCipher.encrypt(plaintext, key);
+
+ // then
+ assertEquals("000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed", cipherText);
+ }
+
+ @Test
+ void xorDecryptTest() {
+ // given
+ String cipherText = "000000b7815e1752111c601f450e48211500a1c206061ca6d35212150d4429570eed";
+ String key = "My ç&cret key!";
+
+ // when
+ String plainText = XORCipher.decrypt(cipherText, key);
+
+ // then
+ assertEquals("My t&xt th@t will be ençrypted...", plainText);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java b/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java
new file mode 100644
index 000000000000..49c43402aeca
--- /dev/null
+++ b/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java
@@ -0,0 +1,15 @@
+package com.thealgorithms.conversions;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class IntegerToEnglishTest {
+
+ @Test
+ public void testIntegerToEnglish() {
+ assertEquals("Two Billion One Hundred Forty Seven Million Four Hundred Eighty Three Thousand Six Hundred Forty Seven", IntegerToEnglish.integerToEnglishWords(2147483647));
+ assertEquals("One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven", IntegerToEnglish.integerToEnglishWords(1234567));
+ assertEquals("Twelve Thousand Three Hundred Forty Five", IntegerToEnglish.integerToEnglishWords(12345));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java
new file mode 100644
index 000000000000..4a7232447e50
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java
@@ -0,0 +1,119 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the EdmondsBlossomAlgorithm class.
+ *
+ * These tests ensure that the Edmonds' Blossom Algorithm implementation
+ * works as expected for various graph structures, returning the correct
+ * maximum matching.
+ */
+public class EdmondsBlossomAlgorithmTest {
+
+ /**
+ * Helper method to convert a list of matching pairs into a sorted 2D array.
+ * Sorting ensures consistent ordering of pairs and vertices for easier comparison in tests.
+ *
+ * @param matching List of matched pairs returned by the algorithm.
+ * @return A sorted 2D array of matching pairs.
+ */
+ private int[][] convertMatchingToArray(List matching) {
+ // Convert the list of pairs into an array
+ int[][] result = matching.toArray(new int[0][]);
+
+ // Sort each individual pair for consistency
+ for (int[] pair : result) {
+ Arrays.sort(pair);
+ }
+
+ // Sort the array of pairs to ensure consistent order
+ Arrays.sort(result, (a, b) -> Integer.compare(a[0], b[0]));
+ return result;
+ }
+
+ /**
+ * Test Case 1: A triangle graph where vertices 0, 1, and 2 form a cycle.
+ * The expected maximum matching is a single pair (0, 1) or any equivalent pair from the cycle.
+ */
+ @Test
+ public void testCase1() {
+ List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0});
+ List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3);
+
+ int[][] expected = new int[][] {{0, 1}};
+ assertArrayEquals(expected, convertMatchingToArray(matching));
+ }
+
+ /**
+ * Test Case 2: A disconnected graph where vertices 0, 1, 2 form one component,
+ * and vertices 3, 4 form another. The expected maximum matching is two pairs:
+ * (0, 1) and (3, 4).
+ */
+ @Test
+ public void testCase2() {
+ List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4});
+ List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 5);
+
+ int[][] expected = new int[][] {{0, 1}, {3, 4}};
+ assertArrayEquals(expected, convertMatchingToArray(matching));
+ }
+
+ /**
+ * Test Case 3: A cycle graph involving vertices 0, 1, 2, 3 forming a cycle,
+ * with an additional edge (4, 5) outside the cycle.
+ * The expected maximum matching is (0, 1) and (4, 5).
+ */
+ @Test
+ public void testCase3() {
+ List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5});
+ List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6);
+
+ // Updated expected output to include the maximum matching pairs
+ int[][] expected = new int[][] {{0, 1}, {2, 3}, {4, 5}};
+ assertArrayEquals(expected, convertMatchingToArray(matching));
+ }
+
+ /**
+ * Test Case 4: A graph with no edges.
+ * Since there are no edges, the expected matching is an empty set.
+ */
+ @Test
+ public void testCaseNoMatching() {
+ List edges = Collections.emptyList(); // No edges
+ List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3);
+
+ int[][] expected = new int[][] {}; // No pairs expected
+ assertArrayEquals(expected, convertMatchingToArray(matching));
+ }
+
+ /**
+ * Test Case 5: A more complex graph with multiple cycles and extra edges.
+ * This tests the algorithm's ability to handle larger, more intricate graphs.
+ * The expected matching is {{0, 1}, {2, 5}, {3, 4}}.
+ */
+ @Test
+ public void testCaseLargeGraph() {
+ List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 4}, new int[] {4, 5}, new int[] {5, 0}, new int[] {1, 4}, new int[] {2, 5});
+ List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6);
+
+ // Check if the size of the matching is correct (i.e., 3 pairs)
+ assertEquals(3, matching.size());
+
+ // Check that the result contains valid pairs (any order is fine)
+ // Valid maximum matchings could be {{0, 1}, {2, 5}, {3, 4}} or {{0, 1}, {2, 3}, {4, 5}}, etc.
+ int[][] possibleMatching1 = new int[][] {{0, 1}, {2, 5}, {3, 4}};
+ int[][] possibleMatching2 = new int[][] {{0, 1}, {2, 3}, {4, 5}};
+ int[][] result = convertMatchingToArray(matching);
+
+ // Assert that the result is one of the valid maximum matchings
+ assertTrue(Arrays.deepEquals(result, possibleMatching1) || Arrays.deepEquals(result, possibleMatching2));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java
new file mode 100644
index 000000000000..4877e6db4ec4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java
@@ -0,0 +1,67 @@
+package com.thealgorithms.datastructures.lists;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class SortedLinkedListTest {
+
+ @Test
+ public void testInsert() {
+ SortedLinkedList list = new SortedLinkedList();
+ list.insert(5);
+ list.insert(3);
+ list.insert(7);
+ assertEquals("[3, 5, 7]", list.toString());
+ }
+
+ @Test
+ public void testDelete() {
+ SortedLinkedList list = new SortedLinkedList();
+ list.insert(5);
+ list.insert(3);
+ list.insert(7);
+ assertTrue(list.delete(5));
+ assertEquals("[3, 7]", list.toString());
+ assertFalse(list.delete(10));
+ }
+
+ @Test
+ public void testSearch() {
+ SortedLinkedList list = new SortedLinkedList();
+ list.insert(5);
+ list.insert(3);
+ list.insert(7);
+ assertTrue(list.search(5));
+ assertFalse(list.search(10));
+ }
+ @Test
+ public void testEmptyList() {
+ SortedLinkedList list = new SortedLinkedList();
+ assertEquals("[]", list.toString());
+ assertFalse(list.delete(5));
+ assertFalse(list.search(5));
+ }
+ @Test
+ public void testIsEmptyOnEmptyList() {
+ SortedLinkedList list = new SortedLinkedList();
+ assertTrue(list.isEmpty());
+ }
+
+ @Test
+ public void testIsEmptyOnNonEmptyList() {
+ SortedLinkedList list = new SortedLinkedList();
+ list.insert(10);
+ assertFalse(list.isEmpty());
+ }
+
+ @Test
+ public void testIsEmptyAfterDeletion() {
+ SortedLinkedList list = new SortedLinkedList();
+ list.insert(10);
+ list.delete(10);
+ assertTrue(list.isEmpty());
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java b/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java
new file mode 100644
index 000000000000..600fdef0a718
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java
@@ -0,0 +1,76 @@
+package com.thealgorithms.datastructures.trees;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class TrieImpTest {
+ private TrieImp trie;
+
+ @BeforeEach
+ public void setUp() {
+ trie = new TrieImp();
+ }
+
+ @Test
+ public void testInsertAndSearchBasic() {
+ String word = "hello";
+ trie.insert(word);
+ assertTrue(trie.search(word), "Search should return true for an inserted word.");
+ }
+
+ @Test
+ public void testSearchNonExistentWord() {
+ String word = "world";
+ assertFalse(trie.search(word), "Search should return false for a non-existent word.");
+ }
+
+ @Test
+ public void testInsertAndSearchMultipleWords() {
+ String word1 = "cat";
+ String word2 = "car";
+ trie.insert(word1);
+ trie.insert(word2);
+
+ assertTrue(trie.search(word1), "Search should return true for an inserted word.");
+ assertTrue(trie.search(word2), "Search should return true for another inserted word.");
+ assertFalse(trie.search("dog"), "Search should return false for a word not in the Trie.");
+ }
+
+ @Test
+ public void testDeleteExistingWord() {
+ String word = "remove";
+ trie.insert(word);
+ assertTrue(trie.delete(word), "Delete should return true for an existing word.");
+ assertFalse(trie.search(word), "Search should return false after deletion.");
+ }
+
+ @Test
+ public void testDeleteNonExistentWord() {
+ String word = "nonexistent";
+ assertFalse(trie.delete(word), "Delete should return false for a non-existent word.");
+ }
+
+ @Test
+ public void testInsertAndSearchPrefix() {
+ String prefix = "pre";
+ String word = "prefix";
+ trie.insert(prefix);
+ trie.insert(word);
+
+ assertTrue(trie.search(prefix), "Search should return true for an inserted prefix.");
+ assertTrue(trie.search(word), "Search should return true for a word with the prefix.");
+ assertFalse(trie.search("pref"), "Search should return false for a prefix that is not a full word.");
+ }
+
+ @Test
+ public void testIsValidWord() {
+ assertTrue(TrieImp.isValid("validword"), "Word should be valid (only lowercase letters).");
+ assertFalse(TrieImp.isValid("InvalidWord"), "Word should be invalid (contains uppercase letters).");
+ assertFalse(TrieImp.isValid("123abc"), "Word should be invalid (contains numbers).");
+ assertFalse(TrieImp.isValid("hello!"), "Word should be invalid (contains special characters).");
+ assertFalse(TrieImp.isValid(""), "Empty string should be invalid.");
+ }
+}
diff --git a/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java b/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java
new file mode 100644
index 000000000000..f85515110b70
--- /dev/null
+++ b/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java
@@ -0,0 +1,102 @@
+package com.thealgorithms.divideandconquer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class SkylineAlgorithmTest {
+
+ private SkylineAlgorithm skylineAlgorithm;
+
+ @BeforeEach
+ public void setUp() {
+ skylineAlgorithm = new SkylineAlgorithm();
+ }
+
+ @Test
+ public void testProduceSubSkyLinesSinglePoint() {
+ // Test with a single point
+ ArrayList points = new ArrayList<>();
+ points.add(new SkylineAlgorithm.Point(1, 10));
+
+ ArrayList result = skylineAlgorithm.produceSubSkyLines(points);
+
+ assertEquals(1, result.size());
+ assertEquals(1, result.get(0).getX());
+ assertEquals(10, result.get(0).getY());
+ }
+
+ @Test
+ public void testProduceSubSkyLinesTwoPoints() {
+ // Test with two points, one dominated by the other
+ ArrayList points = new ArrayList<>();
+ points.add(new SkylineAlgorithm.Point(1, 10));
+ points.add(new SkylineAlgorithm.Point(1, 5));
+
+ ArrayList result = skylineAlgorithm.produceSubSkyLines(points);
+
+ assertEquals(1, result.size());
+ assertEquals(1, result.get(0).getX());
+ assertEquals(5, result.get(0).getY());
+ }
+
+ @Test
+ public void testProduceSubSkyLinesMultiplePoints() {
+ // Test with more than two points
+ ArrayList points = new ArrayList<>();
+ points.add(new SkylineAlgorithm.Point(1, 10));
+ points.add(new SkylineAlgorithm.Point(2, 15));
+ points.add(new SkylineAlgorithm.Point(3, 5));
+ points.add(new SkylineAlgorithm.Point(4, 20));
+
+ ArrayList result = skylineAlgorithm.produceSubSkyLines(points);
+
+ assertEquals(2, result.size());
+
+ // Assert the correct points in skyline
+ assertEquals(1, result.get(0).getX());
+ assertEquals(10, result.get(0).getY());
+ assertEquals(3, result.get(1).getX());
+ assertEquals(5, result.get(1).getY());
+ }
+
+ @Test
+ public void testProduceFinalSkyLine() {
+ // Test merging two skylines
+ ArrayList left = new ArrayList<>();
+ left.add(new SkylineAlgorithm.Point(1, 10));
+ left.add(new SkylineAlgorithm.Point(2, 5));
+
+ ArrayList right = new ArrayList<>();
+ right.add(new SkylineAlgorithm.Point(3, 8));
+ right.add(new SkylineAlgorithm.Point(4, 3));
+
+ ArrayList result = skylineAlgorithm.produceFinalSkyLine(left, right);
+
+ assertEquals(3, result.size());
+
+ // Assert the correct points in the final skyline
+ assertEquals(1, result.get(0).getX());
+ assertEquals(10, result.get(0).getY());
+ assertEquals(2, result.get(1).getX());
+ assertEquals(5, result.get(1).getY());
+ assertEquals(4, result.get(2).getX());
+ assertEquals(3, result.get(2).getY());
+ }
+
+ @Test
+ public void testXComparator() {
+ // Test the XComparator used for sorting the points
+ SkylineAlgorithm.XComparator comparator = new SkylineAlgorithm().new XComparator();
+
+ SkylineAlgorithm.Point p1 = new SkylineAlgorithm.Point(1, 10);
+ SkylineAlgorithm.Point p2 = new SkylineAlgorithm.Point(2, 5);
+
+ // Check if the XComparator sorts points by their x-value
+ assertEquals(-1, comparator.compare(p1, p2)); // p1.x < p2.x
+ assertEquals(1, comparator.compare(p2, p1)); // p2.x > p1.x
+ assertEquals(0, comparator.compare(p1, new SkylineAlgorithm.Point(1, 15))); // p1.x == p2.x
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java
new file mode 100644
index 000000000000..6384fe2afebe
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java
@@ -0,0 +1,35 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class LongestArithmeticSubsequenceTest {
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testGetLongestArithmeticSubsequenceLength(int[] nums, int expected) {
+ assertEquals(expected, LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(nums));
+ }
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testGetLongestArithmeticSubsequenceLengthReversedInput(int[] nums, int expected) {
+ ArrayUtils.reverse(nums);
+ assertEquals(expected, LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(nums));
+ }
+
+ @Test
+ void testGetLongestArithmeticSubsequenceLengthThrowsForNullInput() {
+ assertThrows(IllegalArgumentException.class, () -> LongestArithmeticSubsequence.getLongestArithmeticSubsequenceLength(null));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(Arguments.of(new int[] {3, 6, 9, 12, 15}, 5), Arguments.of(new int[] {1, 7, 10, 13, 14, 19}, 4), Arguments.of(new int[] {1, 2, 3, 4}, 4), Arguments.of(new int[] {}, 0), Arguments.of(new int[] {10}, 1), Arguments.of(new int[] {9, 4, 7, 2, 10}, 3),
+ Arguments.of(new int[] {1, 2, 2, 2, 2, 5}, 4));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java
new file mode 100644
index 000000000000..40bbdff15ca6
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java
@@ -0,0 +1,89 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class LongestCommonSubsequenceTest {
+
+ @Test
+ public void testLCSBasic() {
+ String str1 = "ABCBDAB";
+ String str2 = "BDCAB";
+ String expected = "BDAB"; // The longest common subsequence
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSIdenticalStrings() {
+ String str1 = "AGGTAB";
+ String str2 = "AGGTAB";
+ String expected = "AGGTAB"; // LCS is the same as the strings
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSNoCommonCharacters() {
+ String str1 = "ABC";
+ String str2 = "XYZ";
+ String expected = ""; // No common subsequence
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithEmptyString() {
+ String str1 = "";
+ String str2 = "XYZ";
+ String expected = ""; // LCS with an empty string should be empty
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithBothEmptyStrings() {
+ String str1 = "";
+ String str2 = "";
+ String expected = ""; // LCS with both strings empty should be empty
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithNullFirstString() {
+ String str1 = null;
+ String str2 = "XYZ";
+ String expected = null; // Should return null if first string is null
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithNullSecondString() {
+ String str1 = "ABC";
+ String str2 = null;
+ String expected = null; // Should return null if second string is null
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithNullBothStrings() {
+ String str1 = null;
+ String str2 = null;
+ String expected = null; // Should return null if both strings are null
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+
+ @Test
+ public void testLCSWithLongerStringContainingCommonSubsequence() {
+ String str1 = "ABCDEF";
+ String str2 = "AEBDF";
+ String expected = "ABDF"; // Common subsequence is "ABDF"
+ String result = LongestCommonSubsequence.getLCS(str1, str2);
+ assertEquals(expected, result);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java
new file mode 100644
index 000000000000..1fe018ecce18
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java
@@ -0,0 +1,78 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+public class DigitSeparationTest {
+
+ @Test
+ public void testDigitSeparationReverseOrderSingleDigit() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationReverseOrder(5);
+ assertEquals(List.of(5L), result);
+ }
+
+ @Test
+ public void testDigitSeparationReverseOrderMultipleDigits() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationReverseOrder(123);
+ assertEquals(List.of(3L, 2L, 1L), result);
+ }
+
+ @Test
+ public void testDigitSeparationReverseOrderLargeNumber() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationReverseOrder(123456789);
+ assertEquals(List.of(9L, 8L, 7L, 6L, 5L, 4L, 3L, 2L, 1L), result);
+ }
+
+ @Test
+ public void testDigitSeparationReverseOrderZero() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationReverseOrder(0);
+ assertEquals(List.of(0L), result);
+ }
+
+ @Test
+ public void testDigitSeparationReverseOrderNegativeNumbers() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationReverseOrder(-123);
+ assertEquals(List.of(3L, 2L, 1L), result);
+ }
+
+ @Test
+ public void testDigitSeparationForwardOrderSingleDigit() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationForwardOrder(5);
+ assertEquals(List.of(5L), result);
+ }
+
+ @Test
+ public void testDigitSeparationForwardOrderMultipleDigits() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationForwardOrder(123);
+ assertEquals(List.of(1L, 2L, 3L), result);
+ }
+
+ @Test
+ public void testDigitSeparationForwardOrderLargeNumber() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationForwardOrder(123456789);
+ assertEquals(List.of(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L), result);
+ }
+
+ @Test
+ public void testDigitSeparationForwardOrderZero() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationForwardOrder(0);
+ assertEquals(List.of(0L), result);
+ }
+
+ @Test
+ public void testDigitSeparationForwardOrderNegativeNumber() {
+ DigitSeparation digitSeparation = new DigitSeparation();
+ List result = digitSeparation.digitSeparationForwardOrder(-123);
+ assertEquals(List.of(1L, 2L, 3L), result);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java
new file mode 100644
index 000000000000..0135f9d73260
--- /dev/null
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java
@@ -0,0 +1,71 @@
+package com.thealgorithms.greedyalgorithms;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class MergeIntervalsTest {
+
+ @Test
+ public void testMergeIntervalsWithOverlappingIntervals() {
+ // Test case where some intervals overlap and should be merged
+ int[][] intervals = {{1, 3}, {2, 6}, {8, 10}, {15, 18}};
+ int[][] expected = {{1, 6}, {8, 10}, {15, 18}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithNoOverlap() {
+ // Test case where intervals do not overlap
+ int[][] intervals = {{1, 2}, {3, 4}, {5, 6}};
+ int[][] expected = {{1, 2}, {3, 4}, {5, 6}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithCompleteOverlap() {
+ // Test case where intervals completely overlap
+ int[][] intervals = {{1, 5}, {2, 4}, {3, 6}};
+ int[][] expected = {{1, 6}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithSingleInterval() {
+ // Test case where only one interval is given
+ int[][] intervals = {{1, 2}};
+ int[][] expected = {{1, 2}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithEmptyArray() {
+ // Test case where the input array is empty
+ int[][] intervals = {};
+ int[][] expected = {};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithIdenticalIntervals() {
+ // Test case where multiple identical intervals are given
+ int[][] intervals = {{1, 3}, {1, 3}, {1, 3}};
+ int[][] expected = {{1, 3}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testMergeIntervalsWithRandomIntervals() {
+ // Test case with a mix of overlapping and non-overlapping intervals
+ int[][] intervals = {{1, 4}, {5, 7}, {2, 6}, {8, 10}};
+ int[][] expected = {{1, 7}, {8, 10}};
+ int[][] result = MergeIntervals.merge(intervals);
+ assertArrayEquals(expected, result);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java
new file mode 100644
index 000000000000..91be8a63da62
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class InfixToPrefixTest {
+
+ @ParameterizedTest
+ @MethodSource("provideValidExpressions")
+ void testValidExpressions(String infix, String expectedPrefix) throws Exception {
+ assertEquals(expectedPrefix, InfixToPrefix.infix2Prefix(infix));
+ }
+
+ @Test
+ void testEmptyString() {
+ // Assuming that an empty string returns an empty prefix or throws an exception
+ assertEquals("", InfixToPrefix.infix2Prefix(""));
+ }
+
+ @Test
+ void testNullValue() {
+ // Assuming that a null input throws a NullPointerException
+ assertThrows(NullPointerException.class, () -> InfixToPrefix.infix2Prefix(null));
+ }
+
+ private static Stream provideValidExpressions() {
+ return Stream.of(Arguments.of("3+2", "+32"), // Simple addition
+ Arguments.of("1+(2+3)", "+1+23"), // Parentheses
+ Arguments.of("(3+4)*5-6", "-*+3456"), // Nested operations
+ Arguments.of("a+b*c", "+a*bc"), // Multiplication precedence
+ Arguments.of("a+b*c/d", "+a/*bcd"), // Division precedence
+ Arguments.of("a+b*c-d", "-+a*bcd"), // Subtraction precedence
+ Arguments.of("a+b*c/d-e", "-+a/*bcde"), // Mixed precedence
+ Arguments.of("a+b*(c-d)", "+a*b-cd"), // Parentheses precedence
+ Arguments.of("a+b*(c-d)/e", "+a/*b-cde") // Mixed precedence with parentheses
+ );
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java b/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java
new file mode 100644
index 000000000000..83fd09e1bbf6
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class PrefixToInfixTest {
+
+ @ParameterizedTest
+ @MethodSource("provideValidPrefixToInfixTestCases")
+ void testValidPrefixToInfixConversion(String prefix, String expectedInfix) {
+ assertEquals(expectedInfix, PrefixToInfix.getPrefixToInfix(prefix));
+ }
+
+ static Stream provideValidPrefixToInfixTestCases() {
+ return Stream.of(Arguments.of("A", "A"), // Single operand
+ Arguments.of("+AB", "(A+B)"), // Addition
+ Arguments.of("*+ABC", "((A+B)*C)"), // Addition and multiplication
+ Arguments.of("-+A*BCD", "((A+(B*C))-D)"), // Mixed operators
+ Arguments.of("/-A*BC+DE", "((A-(B*C))/(D+E))"), // Mixed operators
+ Arguments.of("^+AB*CD", "((A+B)^(C*D))") // Mixed operators
+ );
+ }
+
+ @Test
+ void testEmptyPrefixExpression() {
+ assertEquals("", PrefixToInfix.getPrefixToInfix(""));
+ }
+
+ @Test
+ void testNullPrefixExpression() {
+ assertThrows(NullPointerException.class, () -> PrefixToInfix.getPrefixToInfix(null));
+ }
+
+ @Test
+ void testMalformedPrefixExpression() {
+ assertThrows(ArithmeticException.class, () -> PrefixToInfix.getPrefixToInfix("+ABC"));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/others/CountCharTest.java b/src/test/java/com/thealgorithms/strings/CountCharTest.java
similarity index 96%
rename from src/test/java/com/thealgorithms/others/CountCharTest.java
rename to src/test/java/com/thealgorithms/strings/CountCharTest.java
index 2b87d3806002..c84f2d01c2c5 100644
--- a/src/test/java/com/thealgorithms/others/CountCharTest.java
+++ b/src/test/java/com/thealgorithms/strings/CountCharTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/com/thealgorithms/others/CountWordsTest.java b/src/test/java/com/thealgorithms/strings/CountWordsTest.java
similarity index 97%
rename from src/test/java/com/thealgorithms/others/CountWordsTest.java
rename to src/test/java/com/thealgorithms/strings/CountWordsTest.java
index 17bb3aa692e7..a8aca1ae6092 100644
--- a/src/test/java/com/thealgorithms/others/CountWordsTest.java
+++ b/src/test/java/com/thealgorithms/strings/CountWordsTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java b/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java
similarity index 96%
rename from src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java
rename to src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java
index 0ae30c48c2a6..d4e1248d05ad 100644
--- a/src/test/java/com/thealgorithms/others/ReturnSubsequenceTest.java
+++ b/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
diff --git a/src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java b/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java
similarity index 97%
rename from src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java
rename to src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java
index 6e1947b76a38..be460c7c4d91 100644
--- a/src/test/java/com/thealgorithms/others/StringMatchFiniteAutomataTest.java
+++ b/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java
@@ -1,4 +1,4 @@
-package com.thealgorithms.others;
+package com.thealgorithms.strings;
import static org.junit.jupiter.api.Assertions.assertEquals;