diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000000..6313b56c5784
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/pom.xml b/pom.xml
index 170e3900b77f..978c774d6caa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,6 +76,7 @@
-Xlint:all
-Xlint:-auxiliaryclass
-Werror
+
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
index 624a4e2b858a..7cf1e43dabc1 100644
--- a/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
@@ -1,68 +1,68 @@
-package com.thealgorithms.bitmanipulation;
-
-/**
- * A utility class for performing single-bit operations on integers.
- * These operations include flipping, setting, clearing, and getting
- * individual bits at specified positions.
- *
- * Bit positions are zero-indexed (i.e., the least significant bit is at position 0).
- * These methods leverage bitwise operations for optimal performance.
- *
- * Examples:
- * - `flipBit(3, 1)` flips the bit at index 1 in binary `11` (result: `1`).
- * - `setBit(4, 0)` sets the bit at index 0 in `100` (result: `101` or 5).
- * - `clearBit(7, 1)` clears the bit at index 1 in `111` (result: `101` or 5).
- * - `getBit(6, 0)` checks if the least significant bit is set (result: `0`).
- *
- * Time Complexity: O(1) for all operations.
- *
- * Author: lukasb1b (https://github.com/lukasb1b)
- */
-public final class SingleBitOperations {
- private SingleBitOperations() {
- }
-
- /**
- * Flips (toggles) the bit at the specified position.
- *
- * @param num the input number
- * @param bit the position of the bit to flip (0-indexed)
- * @return the new number after flipping the specified bit
- */
- public static int flipBit(final int num, final int bit) {
- return num ^ (1 << bit);
- }
-
- /**
- * Sets the bit at the specified position to 1.
- *
- * @param num the input number
- * @param bit the position of the bit to set (0-indexed)
- * @return the new number after setting the specified bit to 1
- */
- public static int setBit(final int num, final int bit) {
- return num | (1 << bit);
- }
-
- /**
- * Clears the bit at the specified position (sets it to 0).
- *
- * @param num the input number
- * @param bit the position of the bit to clear (0-indexed)
- * @return the new number after clearing the specified bit
- */
- public static int clearBit(final int num, final int bit) {
- return num & ~(1 << bit);
- }
-
- /**
- * Gets the bit value (0 or 1) at the specified position.
- *
- * @param num the input number
- * @param bit the position of the bit to retrieve (0-indexed)
- * @return 1 if the bit is set, 0 otherwise
- */
- public static int getBit(final int num, final int bit) {
- return (num >> bit) & 1;
- }
-}
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class for performing single-bit operations on integers.
+ * These operations include flipping, setting, clearing, and getting
+ * individual bits at specified positions.
+ *
+ * Bit positions are zero-indexed (i.e., the least significant bit is at position 0).
+ * These methods leverage bitwise operations for optimal performance.
+ *
+ * Examples:
+ * - `flipBit(3, 1)` flips the bit at index 1 in binary `11` (result: `1`).
+ * - `setBit(4, 0)` sets the bit at index 0 in `100` (result: `101` or 5).
+ * - `clearBit(7, 1)` clears the bit at index 1 in `111` (result: `101` or 5).
+ * - `getBit(6, 0)` checks if the least significant bit is set (result: `0`).
+ *
+ * Time Complexity: O(1) for all operations.
+ *
+ * Author: lukasb1b (https://github.com/lukasb1b)
+ */
+public final class SingleBitOperations {
+ private SingleBitOperations() {
+ }
+
+ /**
+ * Flips (toggles) the bit at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to flip (0-indexed)
+ * @return the new number after flipping the specified bit
+ */
+ public static int flipBit(final int num, final int bit) {
+ return num ^ (1 << bit);
+ }
+
+ /**
+ * Sets the bit at the specified position to 1.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to set (0-indexed)
+ * @return the new number after setting the specified bit to 1
+ */
+ public static int setBit(final int num, final int bit) {
+ return num | (1 << bit);
+ }
+
+ /**
+ * Clears the bit at the specified position (sets it to 0).
+ *
+ * @param num the input number
+ * @param bit the position of the bit to clear (0-indexed)
+ * @return the new number after clearing the specified bit
+ */
+ public static int clearBit(final int num, final int bit) {
+ return num & ~(1 << bit);
+ }
+
+ /**
+ * Gets the bit value (0 or 1) at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to retrieve (0-indexed)
+ * @return 1 if the bit is set, 0 otherwise
+ */
+ public static int getBit(final int num, final int bit) {
+ return (num >> bit) & 1;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
index 9169aa82bd75..7e7baaa6f7d5 100644
--- a/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
@@ -1,101 +1,101 @@
-package com.thealgorithms.ciphers;
-
-/**
- * The Atbash cipher is a classic substitution cipher that substitutes each letter
- * with its opposite letter in the alphabet.
- *
- * For example:
- * - 'A' becomes 'Z', 'B' becomes 'Y', 'C' becomes 'X', and so on.
- * - Similarly, 'a' becomes 'z', 'b' becomes 'y', and so on.
- *
- * The cipher works identically for both uppercase and lowercase letters.
- * Non-alphabetical characters remain unchanged in the output.
- *
- * This cipher is symmetric, meaning that applying the cipher twice will return
- * the original text. Therefore, the same function is used for both encryption and decryption.
- *
- *
Usage Example:
- *
- * AtbashCipher cipher = new AtbashCipher("Hello World!");
- * String encrypted = cipher.convert(); // Output: "Svool Dliow!"
- *
- *
- * @author Krounosity
- * @see Atbash Cipher (Wikipedia)
- */
-public class AtbashCipher {
-
- private String toConvert;
-
- public AtbashCipher() {
- }
-
- /**
- * Constructor with a string parameter.
- *
- * @param str The string to be converted using the Atbash cipher
- */
- public AtbashCipher(String str) {
- this.toConvert = str;
- }
-
- /**
- * Returns the current string set for conversion.
- *
- * @return The string to be converted
- */
- public String getString() {
- return toConvert;
- }
-
- /**
- * Sets the string to be converted using the Atbash cipher.
- *
- * @param str The new string to convert
- */
- public void setString(String str) {
- this.toConvert = str;
- }
-
- /**
- * Checks if a character is uppercase.
- *
- * @param ch The character to check
- * @return {@code true} if the character is uppercase, {@code false} otherwise
- */
- private boolean isCapital(char ch) {
- return ch >= 'A' && ch <= 'Z';
- }
-
- /**
- * Checks if a character is lowercase.
- *
- * @param ch The character to check
- * @return {@code true} if the character is lowercase, {@code false} otherwise
- */
- private boolean isSmall(char ch) {
- return ch >= 'a' && ch <= 'z';
- }
-
- /**
- * Converts the input string using the Atbash cipher.
- * Alphabetic characters are substituted with their opposite in the alphabet,
- * while non-alphabetic characters remain unchanged.
- *
- * @return The converted string after applying the Atbash cipher
- */
- public String convert() {
- StringBuilder convertedString = new StringBuilder();
-
- for (char ch : toConvert.toCharArray()) {
- if (isSmall(ch)) {
- convertedString.append((char) ('z' - (ch - 'a')));
- } else if (isCapital(ch)) {
- convertedString.append((char) ('Z' - (ch - 'A')));
- } else {
- convertedString.append(ch);
- }
- }
- return convertedString.toString();
- }
-}
+package com.thealgorithms.ciphers;
+
+/**
+ * The Atbash cipher is a classic substitution cipher that substitutes each letter
+ * with its opposite letter in the alphabet.
+ *
+ * For example:
+ * - 'A' becomes 'Z', 'B' becomes 'Y', 'C' becomes 'X', and so on.
+ * - Similarly, 'a' becomes 'z', 'b' becomes 'y', and so on.
+ *
+ * The cipher works identically for both uppercase and lowercase letters.
+ * Non-alphabetical characters remain unchanged in the output.
+ *
+ * This cipher is symmetric, meaning that applying the cipher twice will return
+ * the original text. Therefore, the same function is used for both encryption and decryption.
+ *
+ * Usage Example:
+ *
+ * AtbashCipher cipher = new AtbashCipher("Hello World!");
+ * String encrypted = cipher.convert(); // Output: "Svool Dliow!"
+ *
+ *
+ * @author Krounosity
+ * @see Atbash Cipher (Wikipedia)
+ */
+public class AtbashCipher {
+
+ private String toConvert;
+
+ public AtbashCipher() {
+ }
+
+ /**
+ * Constructor with a string parameter.
+ *
+ * @param str The string to be converted using the Atbash cipher
+ */
+ public AtbashCipher(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Returns the current string set for conversion.
+ *
+ * @return The string to be converted
+ */
+ public String getString() {
+ return toConvert;
+ }
+
+ /**
+ * Sets the string to be converted using the Atbash cipher.
+ *
+ * @param str The new string to convert
+ */
+ public void setString(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Checks if a character is uppercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is uppercase, {@code false} otherwise
+ */
+ private boolean isCapital(char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ /**
+ * Checks if a character is lowercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is lowercase, {@code false} otherwise
+ */
+ private boolean isSmall(char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ /**
+ * Converts the input string using the Atbash cipher.
+ * Alphabetic characters are substituted with their opposite in the alphabet,
+ * while non-alphabetic characters remain unchanged.
+ *
+ * @return The converted string after applying the Atbash cipher
+ */
+ public String convert() {
+ StringBuilder convertedString = new StringBuilder();
+
+ for (char ch : toConvert.toCharArray()) {
+ if (isSmall(ch)) {
+ convertedString.append((char) ('z' - (ch - 'a')));
+ } else if (isCapital(ch)) {
+ convertedString.append((char) ('Z' - (ch - 'A')));
+ } else {
+ convertedString.append(ch);
+ }
+ }
+ return convertedString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java b/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java
index ce443545db1d..26497f0f9955 100644
--- a/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/PermutationCipher.java
@@ -1,194 +1,194 @@
-package com.thealgorithms.ciphers;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A Java implementation of Permutation Cipher.
- * It is a type of transposition cipher in which the plaintext is divided into blocks
- * and the characters within each block are rearranged according to a fixed permutation key.
- *
- * For example, with key {3, 1, 2} and plaintext "HELLO", the text is divided into blocks
- * of 3 characters: "HEL" and "LO" (with padding). The characters are then rearranged
- * according to the key positions.
- *
- * @author GitHub Copilot
- */
-public class PermutationCipher {
-
- private static final char PADDING_CHAR = 'X';
-
- /**
- * Encrypts the given plaintext using the permutation cipher with the specified key.
- *
- * @param plaintext the text to encrypt
- * @param key the permutation key (array of integers representing positions)
- * @return the encrypted text
- * @throws IllegalArgumentException if the key is invalid
- */
- public String encrypt(String plaintext, int[] key) {
- validateKey(key);
-
- if (plaintext == null || plaintext.isEmpty()) {
- return plaintext;
- }
-
- // Remove spaces and convert to uppercase for consistent processing
- String cleanText = plaintext.replaceAll("\\s+", "").toUpperCase();
-
- // Pad the text to make it divisible by key length
- String paddedText = padText(cleanText, key.length);
-
- StringBuilder encrypted = new StringBuilder();
-
- // Process text in blocks of key length
- for (int i = 0; i < paddedText.length(); i += key.length) {
- String block = paddedText.substring(i, Math.min(i + key.length, paddedText.length()));
- encrypted.append(permuteBlock(block, key));
- }
-
- return encrypted.toString();
- }
-
- /**
- * Decrypts the given ciphertext using the permutation cipher with the specified key.
- *
- * @param ciphertext the text to decrypt
- * @param key the permutation key (array of integers representing positions)
- * @return the decrypted text
- * @throws IllegalArgumentException if the key is invalid
- */
- public String decrypt(String ciphertext, int[] key) {
- validateKey(key);
-
- if (ciphertext == null || ciphertext.isEmpty()) {
- return ciphertext;
- }
-
- // Create the inverse permutation
- int[] inverseKey = createInverseKey(key);
-
- StringBuilder decrypted = new StringBuilder();
-
- // Process text in blocks of key length
- for (int i = 0; i < ciphertext.length(); i += key.length) {
- String block = ciphertext.substring(i, Math.min(i + key.length, ciphertext.length()));
- decrypted.append(permuteBlock(block, inverseKey));
- }
-
- // Remove padding characters from the end
- return removePadding(decrypted.toString());
- }
- /**
- * Validates that the permutation key is valid.
- * A valid key must contain all integers from 1 to n exactly once, where n is the key length.
- *
- * @param key the permutation key to validate
- * @throws IllegalArgumentException if the key is invalid
- */
- private void validateKey(int[] key) {
- if (key == null || key.length == 0) {
- throw new IllegalArgumentException("Key cannot be null or empty");
- }
-
- Set keySet = new HashSet<>();
- for (int position : key) {
- if (position < 1 || position > key.length) {
- throw new IllegalArgumentException("Key must contain integers from 1 to " + key.length);
- }
- if (!keySet.add(position)) {
- throw new IllegalArgumentException("Key must contain each position exactly once");
- }
- }
- }
-
- /**
- * Pads the text with padding characters to make its length divisible by the block size.
- *
- * @param text the text to pad
- * @param blockSize the size of each block
- * @return the padded text
- */
- private String padText(String text, int blockSize) {
- int remainder = text.length() % blockSize;
- if (remainder == 0) {
- return text;
- }
-
- int paddingNeeded = blockSize - remainder;
- StringBuilder padded = new StringBuilder(text);
- for (int i = 0; i < paddingNeeded; i++) {
- padded.append(PADDING_CHAR);
- }
-
- return padded.toString();
- }
- /**
- * Applies the permutation to a single block of text.
- *
- * @param block the block to permute
- * @param key the permutation key
- * @return the permuted block
- */
- private String permuteBlock(String block, int[] key) {
- if (block.length() != key.length) {
- // Handle case where block is shorter than key (shouldn't happen with proper padding)
- block = padText(block, key.length);
- }
-
- char[] result = new char[key.length];
- char[] blockChars = block.toCharArray();
-
- for (int i = 0; i < key.length; i++) {
- // Key positions are 1-based, so subtract 1 for 0-based array indexing
- result[i] = blockChars[key[i] - 1];
- }
-
- return new String(result);
- }
-
- /**
- * Creates the inverse permutation key for decryption.
- *
- * @param key the original permutation key
- * @return the inverse key
- */
- private int[] createInverseKey(int[] key) {
- int[] inverse = new int[key.length];
-
- for (int i = 0; i < key.length; i++) {
- // The inverse key maps each position to where it should go
- inverse[key[i] - 1] = i + 1;
- }
-
- return inverse;
- }
-
- /**
- * Removes padding characters from the end of the decrypted text.
- *
- * @param text the text to remove padding from
- * @return the text without padding
- */
- private String removePadding(String text) {
- if (text.isEmpty()) {
- return text;
- }
-
- int i = text.length() - 1;
- while (i >= 0 && text.charAt(i) == PADDING_CHAR) {
- i--;
- }
-
- return text.substring(0, i + 1);
- }
-
- /**
- * Gets the padding character used by this cipher.
- *
- * @return the padding character
- */
- public char getPaddingChar() {
- return PADDING_CHAR;
- }
-}
+package com.thealgorithms.ciphers;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A Java implementation of Permutation Cipher.
+ * It is a type of transposition cipher in which the plaintext is divided into blocks
+ * and the characters within each block are rearranged according to a fixed permutation key.
+ *
+ * For example, with key {3, 1, 2} and plaintext "HELLO", the text is divided into blocks
+ * of 3 characters: "HEL" and "LO" (with padding). The characters are then rearranged
+ * according to the key positions.
+ *
+ * @author GitHub Copilot
+ */
+public class PermutationCipher {
+
+ private static final char PADDING_CHAR = 'X';
+
+ /**
+ * Encrypts the given plaintext using the permutation cipher with the specified key.
+ *
+ * @param plaintext the text to encrypt
+ * @param key the permutation key (array of integers representing positions)
+ * @return the encrypted text
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ public String encrypt(String plaintext, int[] key) {
+ validateKey(key);
+
+ if (plaintext == null || plaintext.isEmpty()) {
+ return plaintext;
+ }
+
+ // Remove spaces and convert to uppercase for consistent processing
+ String cleanText = plaintext.replaceAll("\\s+", "").toUpperCase();
+
+ // Pad the text to make it divisible by key length
+ String paddedText = padText(cleanText, key.length);
+
+ StringBuilder encrypted = new StringBuilder();
+
+ // Process text in blocks of key length
+ for (int i = 0; i < paddedText.length(); i += key.length) {
+ String block = paddedText.substring(i, Math.min(i + key.length, paddedText.length()));
+ encrypted.append(permuteBlock(block, key));
+ }
+
+ return encrypted.toString();
+ }
+
+ /**
+ * Decrypts the given ciphertext using the permutation cipher with the specified key.
+ *
+ * @param ciphertext the text to decrypt
+ * @param key the permutation key (array of integers representing positions)
+ * @return the decrypted text
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ public String decrypt(String ciphertext, int[] key) {
+ validateKey(key);
+
+ if (ciphertext == null || ciphertext.isEmpty()) {
+ return ciphertext;
+ }
+
+ // Create the inverse permutation
+ int[] inverseKey = createInverseKey(key);
+
+ StringBuilder decrypted = new StringBuilder();
+
+ // Process text in blocks of key length
+ for (int i = 0; i < ciphertext.length(); i += key.length) {
+ String block = ciphertext.substring(i, Math.min(i + key.length, ciphertext.length()));
+ decrypted.append(permuteBlock(block, inverseKey));
+ }
+
+ // Remove padding characters from the end
+ return removePadding(decrypted.toString());
+ }
+ /**
+ * Validates that the permutation key is valid.
+ * A valid key must contain all integers from 1 to n exactly once, where n is the key length.
+ *
+ * @param key the permutation key to validate
+ * @throws IllegalArgumentException if the key is invalid
+ */
+ private void validateKey(int[] key) {
+ if (key == null || key.length == 0) {
+ throw new IllegalArgumentException("Key cannot be null or empty");
+ }
+
+ Set keySet = new HashSet<>();
+ for (int position : key) {
+ if (position < 1 || position > key.length) {
+ throw new IllegalArgumentException("Key must contain integers from 1 to " + key.length);
+ }
+ if (!keySet.add(position)) {
+ throw new IllegalArgumentException("Key must contain each position exactly once");
+ }
+ }
+ }
+
+ /**
+ * Pads the text with padding characters to make its length divisible by the block size.
+ *
+ * @param text the text to pad
+ * @param blockSize the size of each block
+ * @return the padded text
+ */
+ private String padText(String text, int blockSize) {
+ int remainder = text.length() % blockSize;
+ if (remainder == 0) {
+ return text;
+ }
+
+ int paddingNeeded = blockSize - remainder;
+ StringBuilder padded = new StringBuilder(text);
+ for (int i = 0; i < paddingNeeded; i++) {
+ padded.append(PADDING_CHAR);
+ }
+
+ return padded.toString();
+ }
+ /**
+ * Applies the permutation to a single block of text.
+ *
+ * @param block the block to permute
+ * @param key the permutation key
+ * @return the permuted block
+ */
+ private String permuteBlock(String block, int[] key) {
+ if (block.length() != key.length) {
+ // Handle case where block is shorter than key (shouldn't happen with proper padding)
+ block = padText(block, key.length);
+ }
+
+ char[] result = new char[key.length];
+ char[] blockChars = block.toCharArray();
+
+ for (int i = 0; i < key.length; i++) {
+ // Key positions are 1-based, so subtract 1 for 0-based array indexing
+ result[i] = blockChars[key[i] - 1];
+ }
+
+ return new String(result);
+ }
+
+ /**
+ * Creates the inverse permutation key for decryption.
+ *
+ * @param key the original permutation key
+ * @return the inverse key
+ */
+ private int[] createInverseKey(int[] key) {
+ int[] inverse = new int[key.length];
+
+ for (int i = 0; i < key.length; i++) {
+ // The inverse key maps each position to where it should go
+ inverse[key[i] - 1] = i + 1;
+ }
+
+ return inverse;
+ }
+
+ /**
+ * Removes padding characters from the end of the decrypted text.
+ *
+ * @param text the text to remove padding from
+ * @return the text without padding
+ */
+ private String removePadding(String text) {
+ if (text.isEmpty()) {
+ return text;
+ }
+
+ int i = text.length() - 1;
+ while (i >= 0 && text.charAt(i) == PADDING_CHAR) {
+ i--;
+ }
+
+ return text.substring(0, i + 1);
+ }
+
+ /**
+ * Gets the padding character used by this cipher.
+ *
+ * @return the padding character
+ */
+ public char getPaddingChar() {
+ return PADDING_CHAR;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
index f81252980468..2ccdc866ad4c 100644
--- a/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
@@ -1,147 +1,147 @@
-package com.thealgorithms.ciphers;
-
-import java.util.Arrays;
-
-/**
- * The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
- * It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
- * https://en.wikipedia.org/wiki/Rail_fence_cipher
- * @author https://github.com/Krounosity
- */
-
-public class RailFenceCipher {
-
- // Encrypts the input string using the rail fence cipher method with the given number of rails.
- public String encrypt(String str, int rails) {
-
- // Base case of single rail or rails are more than the number of characters in the string
- if (rails == 1 || rails >= str.length()) {
- return str;
- }
-
- // Boolean flag to determine if the movement is downward or upward in the rail matrix.
- boolean down = true;
- // Create a 2D array to represent the rails (rows) and the length of the string (columns).
- char[][] strRail = new char[rails][str.length()];
-
- // Initialize all positions in the rail matrix with a placeholder character ('\n').
- for (int i = 0; i < rails; i++) {
- Arrays.fill(strRail[i], '\n');
- }
-
- int row = 0; // Start at the first row
- int col = 0; // Start at the first column
-
- int i = 0;
-
- // Fill the rail matrix with characters from the string based on the rail pattern.
- while (col < str.length()) {
- // Change direction to down when at the first row.
- if (row == 0) {
- down = true;
- }
- // Change direction to up when at the last row.
- else if (row == rails - 1) {
- down = false;
- }
-
- // Place the character in the current position of the rail matrix.
- strRail[row][col] = str.charAt(i);
- col++; // Move to the next column.
- // Move to the next row based on the direction.
- if (down) {
- row++;
- } else {
- row--;
- }
-
- i++;
- }
-
- // Construct the encrypted string by reading characters row by row.
- StringBuilder encryptedString = new StringBuilder();
- for (char[] chRow : strRail) {
- for (char ch : chRow) {
- if (ch != '\n') {
- encryptedString.append(ch);
- }
- }
- }
- return encryptedString.toString();
- }
- // Decrypts the input string using the rail fence cipher method with the given number of rails.
- public String decrypt(String str, int rails) {
-
- // Base case of single rail or rails are more than the number of characters in the string
- if (rails == 1 || rails >= str.length()) {
- return str;
- }
- // Boolean flag to determine if the movement is downward or upward in the rail matrix.
- boolean down = true;
-
- // Create a 2D array to represent the rails (rows) and the length of the string (columns).
- char[][] strRail = new char[rails][str.length()];
-
- int row = 0; // Start at the first row
- int col = 0; // Start at the first column
-
- // Mark the pattern on the rail matrix using '*'.
- while (col < str.length()) {
- // Change direction to down when at the first row.
- if (row == 0) {
- down = true;
- }
- // Change direction to up when at the last row.
- else if (row == rails - 1) {
- down = false;
- }
-
- // Mark the current position in the rail matrix.
- strRail[row][col] = '*';
- col++; // Move to the next column.
- // Move to the next row based on the direction.
- if (down) {
- row++;
- } else {
- row--;
- }
- }
-
- int index = 0; // Index to track characters from the input string.
- // Fill the rail matrix with characters from the input string based on the marked pattern.
- for (int i = 0; i < rails; i++) {
- for (int j = 0; j < str.length(); j++) {
- if (strRail[i][j] == '*') {
- strRail[i][j] = str.charAt(index++);
- }
- }
- }
-
- // Construct the decrypted string by following the zigzag pattern.
- StringBuilder decryptedString = new StringBuilder();
- row = 0; // Reset to the first row
- col = 0; // Reset to the first column
-
- while (col < str.length()) {
- // Change direction to down when at the first row.
- if (row == 0) {
- down = true;
- }
- // Change direction to up when at the last row.
- else if (row == rails - 1) {
- down = false;
- }
- // Append the character from the rail matrix to the decrypted string.
- decryptedString.append(strRail[row][col]);
- col++; // Move to the next column.
- // Move to the next row based on the direction.
- if (down) {
- row++;
- } else {
- row--;
- }
- }
-
- return decryptedString.toString();
- }
-}
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+
+/**
+ * The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
+ * It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
+ * https://en.wikipedia.org/wiki/Rail_fence_cipher
+ * @author https://github.com/Krounosity
+ */
+
+public class RailFenceCipher {
+
+ // Encrypts the input string using the rail fence cipher method with the given number of rails.
+ public String encrypt(String str, int rails) {
+
+ // Base case of single rail or rails are more than the number of characters in the string
+ if (rails == 1 || rails >= str.length()) {
+ return str;
+ }
+
+ // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+ boolean down = true;
+ // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+ char[][] strRail = new char[rails][str.length()];
+
+ // Initialize all positions in the rail matrix with a placeholder character ('\n').
+ for (int i = 0; i < rails; i++) {
+ Arrays.fill(strRail[i], '\n');
+ }
+
+ int row = 0; // Start at the first row
+ int col = 0; // Start at the first column
+
+ int i = 0;
+
+ // Fill the rail matrix with characters from the string based on the rail pattern.
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+
+ // Place the character in the current position of the rail matrix.
+ strRail[row][col] = str.charAt(i);
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+
+ i++;
+ }
+
+ // Construct the encrypted string by reading characters row by row.
+ StringBuilder encryptedString = new StringBuilder();
+ for (char[] chRow : strRail) {
+ for (char ch : chRow) {
+ if (ch != '\n') {
+ encryptedString.append(ch);
+ }
+ }
+ }
+ return encryptedString.toString();
+ }
+ // Decrypts the input string using the rail fence cipher method with the given number of rails.
+ public String decrypt(String str, int rails) {
+
+ // Base case of single rail or rails are more than the number of characters in the string
+ if (rails == 1 || rails >= str.length()) {
+ return str;
+ }
+ // Boolean flag to determine if the movement is downward or upward in the rail matrix.
+ boolean down = true;
+
+ // Create a 2D array to represent the rails (rows) and the length of the string (columns).
+ char[][] strRail = new char[rails][str.length()];
+
+ int row = 0; // Start at the first row
+ int col = 0; // Start at the first column
+
+ // Mark the pattern on the rail matrix using '*'.
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+
+ // Mark the current position in the rail matrix.
+ strRail[row][col] = '*';
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+ }
+
+ int index = 0; // Index to track characters from the input string.
+ // Fill the rail matrix with characters from the input string based on the marked pattern.
+ for (int i = 0; i < rails; i++) {
+ for (int j = 0; j < str.length(); j++) {
+ if (strRail[i][j] == '*') {
+ strRail[i][j] = str.charAt(index++);
+ }
+ }
+ }
+
+ // Construct the decrypted string by following the zigzag pattern.
+ StringBuilder decryptedString = new StringBuilder();
+ row = 0; // Reset to the first row
+ col = 0; // Reset to the first column
+
+ while (col < str.length()) {
+ // Change direction to down when at the first row.
+ if (row == 0) {
+ down = true;
+ }
+ // Change direction to up when at the last row.
+ else if (row == rails - 1) {
+ down = false;
+ }
+ // Append the character from the rail matrix to the decrypted string.
+ decryptedString.append(strRail[row][col]);
+ col++; // Move to the next column.
+ // Move to the next row based on the direction.
+ if (down) {
+ row++;
+ } else {
+ row--;
+ }
+ }
+
+ return decryptedString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySize.java b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySize.java
index 71951f67dfc8..44665c548e4d 100644
--- a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySize.java
+++ b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySize.java
@@ -1,83 +1,83 @@
-package com.thealgorithms.datastructures.disjointsetunion;
-
-/**
- * Disjoint Set Union (DSU) with Union by Size.
- * This data structure tracks a set of elements partitioned into disjoint (non-overlapping) subsets.
- * It supports two primary operations efficiently:
- *
- *
- * - Find: Determine which subset a particular element belongs to.
- * - Union: Merge two subsets into a single subset using union by size.
- *
- *
- * Union by size always attaches the smaller tree under the root of the larger tree.
- * This helps keep the tree shallow, improving the efficiency of find operations.
- *
- * @see Disjoint Set Union (Wikipedia)
- */
-public class DisjointSetUnionBySize {
- /**
- * Node class for DSU by size.
- * Each node keeps track of its parent and the size of the set it represents.
- */
- public static class Node {
- public T value;
- public Node parent;
- public int size; // size of the set
-
- public Node(T value) {
- this.value = value;
- this.parent = this;
- this.size = 1; // initially, the set size is 1
- }
- }
-
- /**
- * Creates a new disjoint set containing the single specified element.
- * @param value the element to be placed in a new singleton set
- * @return a node representing the new set
- */
- public Node makeSet(final T value) {
- return new Node<>(value);
- }
-
- /**
- * Finds and returns the representative (root) of the set containing the given node.
- * This method applies path compression to flatten the tree structure for future efficiency.
- * @param node the node whose set representative is to be found
- * @return the representative (root) node of the set
- */
- public Node findSet(Node node) {
- if (node != node.parent) {
- node.parent = findSet(node.parent); // path compression
- }
- return node.parent;
- }
-
- /**
- * Merges the sets containing the two given nodes using union by size.
- * The root of the smaller set is attached to the root of the larger set.
- * @param x a node in the first set
- * @param y a node in the second set
- */
- public void unionSets(Node x, Node y) {
- Node rootX = findSet(x);
- Node rootY = findSet(y);
-
- if (rootX == rootY) {
- return; // They are already in the same set
- }
- // Union by size: attach smaller tree under the larger one
- if (rootX.size < rootY.size) {
- rootX.parent = rootY;
- rootY.size += rootX.size; // update size
- } else {
- rootY.parent = rootX;
- rootX.size += rootY.size; // update size
- }
- }
-}
-// This implementation uses union by size instead of union by rank.
-// The size field tracks the number of elements in each set.
-// When two sets are merged, the smaller set is always attached to the larger set's root.
-// This helps keep the tree shallow and improves the efficiency of find operations.
+package com.thealgorithms.datastructures.disjointsetunion;
+
+/**
+ * Disjoint Set Union (DSU) with Union by Size.
+ * This data structure tracks a set of elements partitioned into disjoint (non-overlapping) subsets.
+ * It supports two primary operations efficiently:
+ *
+ *
+ * - Find: Determine which subset a particular element belongs to.
+ * - Union: Merge two subsets into a single subset using union by size.
+ *
+ *
+ * Union by size always attaches the smaller tree under the root of the larger tree.
+ * This helps keep the tree shallow, improving the efficiency of find operations.
+ *
+ * @see Disjoint Set Union (Wikipedia)
+ */
+public class DisjointSetUnionBySize {
+ /**
+ * Node class for DSU by size.
+ * Each node keeps track of its parent and the size of the set it represents.
+ */
+ public static class Node {
+ public T value;
+ public Node parent;
+ public int size; // size of the set
+
+ public Node(T value) {
+ this.value = value;
+ this.parent = this;
+ this.size = 1; // initially, the set size is 1
+ }
+ }
+
+ /**
+ * Creates a new disjoint set containing the single specified element.
+ * @param value the element to be placed in a new singleton set
+ * @return a node representing the new set
+ */
+ public Node makeSet(final T value) {
+ return new Node<>(value);
+ }
+
+ /**
+ * Finds and returns the representative (root) of the set containing the given node.
+ * This method applies path compression to flatten the tree structure for future efficiency.
+ * @param node the node whose set representative is to be found
+ * @return the representative (root) node of the set
+ */
+ public Node findSet(Node node) {
+ if (node != node.parent) {
+ node.parent = findSet(node.parent); // path compression
+ }
+ return node.parent;
+ }
+
+ /**
+ * Merges the sets containing the two given nodes using union by size.
+ * The root of the smaller set is attached to the root of the larger set.
+ * @param x a node in the first set
+ * @param y a node in the second set
+ */
+ public void unionSets(Node x, Node y) {
+ Node rootX = findSet(x);
+ Node rootY = findSet(y);
+
+ if (rootX == rootY) {
+ return; // They are already in the same set
+ }
+ // Union by size: attach smaller tree under the larger one
+ if (rootX.size < rootY.size) {
+ rootX.parent = rootY;
+ rootY.size += rootX.size; // update size
+ } else {
+ rootY.parent = rootX;
+ rootX.size += rootY.size; // update size
+ }
+ }
+}
+// This implementation uses union by size instead of union by rank.
+// The size field tracks the number of elements in each set.
+// When two sets are merged, the smaller set is always attached to the larger set's root.
+// This helps keep the tree shallow and improves the efficiency of find operations.
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java b/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java
index aea2b74bd13b..a9b2390dfbbc 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java
@@ -1,59 +1,42 @@
package com.thealgorithms.datastructures.graphs;
import java.util.ArrayList;
-import java.util.Scanner;
+import java.util.List;
class Cycle {
private final int nodes;
- private int[][] adjacencyMatrix;
- private boolean[] visited;
- ArrayList> cycles = new ArrayList>();
-
- Cycle() {
- Scanner in = new Scanner(System.in);
- System.out.print("Enter the no. of nodes: ");
- nodes = in.nextInt();
- System.out.print("Enter the no. of Edges: ");
- final int edges = in.nextInt();
-
- adjacencyMatrix = new int[nodes][nodes];
- visited = new boolean[nodes];
+ private final int[][] adjacencyMatrix;
+ private final boolean[] visited;
+ private final List> cycles = new ArrayList<>();
+ Cycle(int nodes, int[][] adjacencyMatrix) {
+ this.nodes = nodes;
+ this.adjacencyMatrix = new int[nodes][nodes];
+ // Deep copy matrix to avoid side-effects
for (int i = 0; i < nodes; i++) {
- visited[i] = false;
- }
-
- System.out.println("Enter the details of each edges ");
-
- for (int i = 0; i < edges; i++) {
- int start;
- int end;
- start = in.nextInt();
- end = in.nextInt();
- adjacencyMatrix[start][end] = 1;
+ System.arraycopy(adjacencyMatrix[i], 0, this.adjacencyMatrix[i], 0, nodes);
}
- in.close();
+ this.visited = new boolean[nodes];
}
public void start() {
for (int i = 0; i < nodes; i++) {
- ArrayList temp = new ArrayList<>();
- dfs(i, i, temp);
+ dfs(i, i, new ArrayList<>());
for (int j = 0; j < nodes; j++) {
- adjacencyMatrix[i][j] = 0;
- adjacencyMatrix[j][i] = 0;
+ this.adjacencyMatrix[i][j] = 0;
+ this.adjacencyMatrix[j][i] = 0;
}
}
}
- private void dfs(Integer start, Integer curr, ArrayList temp) {
+ private void dfs(int start, int curr, List temp) {
temp.add(curr);
visited[curr] = true;
for (int i = 0; i < nodes; i++) {
if (adjacencyMatrix[curr][i] == 1) {
if (i == start) {
- cycles.add(new ArrayList(temp));
+ cycles.add(new ArrayList<>(temp));
} else {
if (!visited[i]) {
dfs(start, i, temp);
@@ -62,18 +45,24 @@ private void dfs(Integer start, Integer curr, ArrayList temp) {
}
}
- if (temp.size() > 0) {
+ if (!temp.isEmpty()) {
temp.remove(temp.size() - 1);
}
visited[curr] = false;
}
+ public List> getCycles() {
+ return cycles;
+ }
+
public void printAll() {
- for (int i = 0; i < cycles.size(); i++) {
- for (int j = 0; j < cycles.get(i).size(); j++) {
- System.out.print(cycles.get(i).get(j) + " -> ");
+ for (List cycle : cycles) {
+ for (Integer node : cycle) {
+ System.out.print(node + " -> ");
+ }
+ if (!cycle.isEmpty()) {
+ System.out.println(cycle.get(0));
}
- System.out.println(cycles.get(i).get(0));
System.out.println();
}
}
@@ -84,7 +73,11 @@ private Cycles() {
}
public static void main(String[] args) {
- Cycle c = new Cycle();
+ // Example usage with a triangle graph: 0 -> 1 -> 2 -> 0
+ int nodes = 3;
+ int[][] matrix = {{0, 1, 1}, {1, 0, 1}, {1, 1, 0}};
+
+ Cycle c = new Cycle(nodes, matrix);
c.start();
c.printAll();
}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java b/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
index 8c7ea6179e3f..5d0784796cdb 100755
--- a/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
@@ -1,98 +1,98 @@
-package com.thealgorithms.dynamicprogramming;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Utility class to find the number of unique subsequences that can be
- * produced from a given string.
- *
- * This class contains static methods to compute the unique subsequence count
- * using dynamic programming and recursion. It ensures that duplicate characters
- * are not counted multiple times in the subsequences.
- *
- * Author: https://github.com/Tuhinm2002
- */
-public final class UniqueSubsequencesCount {
-
- /**
- * Private constructor to prevent instantiation of this utility class.
- * This class should only be used in a static context.
- *
- * @throws UnsupportedOperationException if attempted to instantiate.
- */
- private UniqueSubsequencesCount() {
- throw new UnsupportedOperationException("Utility class");
- }
-
- /**
- * Finds the number of unique subsequences that can be generated from
- * the given string.
- *
- * This method initializes a dynamic programming (DP) array and invokes
- * the recursive helper function to compute the subsequence count.
- *
- * @param str the input string from which subsequences are generated
- * @return the total count of unique subsequences
- */
- public static int countSubseq(String str) {
-
- // DP array initialized to store intermediate results
- int[] dp = new int[str.length() + 1];
- Arrays.fill(dp, -1);
-
- // Calls the recursive function to compute the result
- return countSubsequences(str, 0, dp);
- }
-
- /**
- * Recursive helper function to count the number of unique subsequences
- * starting from the given index.
- *
- * Uses a HashSet to avoid counting duplicate characters within
- * a single subsequence.
- *
- * @param st the input string
- * @param idx the current index from which to calculate subsequences
- * @param dp dynamic programming array used to memoize results
- * @return the total number of unique subsequences starting from the
- * current index
- */
- public static int countSubsequences(String st, int idx, int[] dp) {
-
- // Base case: when index exceeds the string length
- if (idx >= st.length()) {
- return 0;
- }
-
- // If result is already calculated, return the memoized value
- if (dp[idx] != -1) {
- return dp[idx];
- }
-
- // Set to store characters to avoid duplicates
- Set set = new HashSet<>();
-
- int res = 0;
-
- // Iterate over the string starting from current index
- for (int j = idx; j < st.length(); j++) {
-
- // If character is already in the set, skip it
- if (set.contains(st.charAt(j))) {
- continue;
- }
-
- // Add character to set and recursively calculate subsequences
- set.add(st.charAt(j));
-
- // 1 for the current subsequence + recursive call for the rest of the string
- res = 1 + countSubsequences(st, j + 1, dp) + res;
- }
-
- // Memoize the result
- dp[idx] = res;
- return dp[idx];
- }
-}
+package com.thealgorithms.dynamicprogramming;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Utility class to find the number of unique subsequences that can be
+ * produced from a given string.
+ *
+ * This class contains static methods to compute the unique subsequence count
+ * using dynamic programming and recursion. It ensures that duplicate characters
+ * are not counted multiple times in the subsequences.
+ *
+ * Author: https://github.com/Tuhinm2002
+ */
+public final class UniqueSubsequencesCount {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ * This class should only be used in a static context.
+ *
+ * @throws UnsupportedOperationException if attempted to instantiate.
+ */
+ private UniqueSubsequencesCount() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Finds the number of unique subsequences that can be generated from
+ * the given string.
+ *
+ * This method initializes a dynamic programming (DP) array and invokes
+ * the recursive helper function to compute the subsequence count.
+ *
+ * @param str the input string from which subsequences are generated
+ * @return the total count of unique subsequences
+ */
+ public static int countSubseq(String str) {
+
+ // DP array initialized to store intermediate results
+ int[] dp = new int[str.length() + 1];
+ Arrays.fill(dp, -1);
+
+ // Calls the recursive function to compute the result
+ return countSubsequences(str, 0, dp);
+ }
+
+ /**
+ * Recursive helper function to count the number of unique subsequences
+ * starting from the given index.
+ *
+ * Uses a HashSet to avoid counting duplicate characters within
+ * a single subsequence.
+ *
+ * @param st the input string
+ * @param idx the current index from which to calculate subsequences
+ * @param dp dynamic programming array used to memoize results
+ * @return the total number of unique subsequences starting from the
+ * current index
+ */
+ public static int countSubsequences(String st, int idx, int[] dp) {
+
+ // Base case: when index exceeds the string length
+ if (idx >= st.length()) {
+ return 0;
+ }
+
+ // If result is already calculated, return the memoized value
+ if (dp[idx] != -1) {
+ return dp[idx];
+ }
+
+ // Set to store characters to avoid duplicates
+ Set set = new HashSet<>();
+
+ int res = 0;
+
+ // Iterate over the string starting from current index
+ for (int j = idx; j < st.length(); j++) {
+
+ // If character is already in the set, skip it
+ if (set.contains(st.charAt(j))) {
+ continue;
+ }
+
+ // Add character to set and recursively calculate subsequences
+ set.add(st.charAt(j));
+
+ // 1 for the current subsequence + recursive call for the rest of the string
+ res = 1 + countSubsequences(st, j + 1, dp) + res;
+ }
+
+ // Memoize the result
+ dp[idx] = res;
+ return dp[idx];
+ }
+}
diff --git a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
index 3f685f418a3d..53f370f5991f 100644
--- a/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
+++ b/src/main/java/com/thealgorithms/others/IterativeFloodFill.java
@@ -1,102 +1,102 @@
-package com.thealgorithms.others;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * Implementation of the Flood Fill algorithm using an iterative BFS (Breadth-First Search) approach.
- *
- * The Flood Fill algorithm is used to fill connected areas in an image with a new color, starting from a specified point.
- * This implementation uses an iterative BFS approach with a queue
- * instead of recursion to avoid stack overflow issues with large images.
- *
- * Implementation Features:
- *
- * - Supports 8-connected filling (horizontal, vertical, and diagonal directions)
- * - Uses BFS traversal through {@link java.util.Queue}
- * - Includes nested {@code Point} class to represent pixel coordinates
- * - Iterative approach avoids stack overflow for large images
- *
- *
- * Time Complexity: O(M × N) where M and N are the dimensions of the image
- * Space Complexity: O(M × N) in the worst case the queue stores every pixel
- *
- * @see Flood Fill Algorithm - GeeksforGeeks
- * @see Flood Fill Algorithm - Wikipedia
- */
-public final class IterativeFloodFill {
- private IterativeFloodFill() {
- }
-
- /**
- * Iteratively fill the 2D image with new color
- *
- * @param image The image to be filled
- * @param x The x coordinate at which color is to be filled
- * @param y The y coordinate at which color is to be filled
- * @param newColor The new color which to be filled in the image
- * @param oldColor The old color which is to be replaced in the image
- * @see FloodFill BFS
- */
- public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
- if (image.length == 0 || image[0].length == 0 || newColor == oldColor || shouldSkipPixel(image, x, y, oldColor)) {
- return;
- }
-
- Queue queue = new LinkedList<>();
- queue.add(new Point(x, y));
-
- int[] dx = {0, 0, -1, 1, 1, -1, 1, -1};
- int[] dy = {-1, 1, 0, 0, -1, 1, 1, -1};
-
- while (!queue.isEmpty()) {
- Point currPoint = queue.poll();
-
- if (shouldSkipPixel(image, currPoint.x, currPoint.y, oldColor)) {
- continue;
- }
-
- image[currPoint.x][currPoint.y] = newColor;
-
- for (int i = 0; i < 8; i++) {
- int curX = currPoint.x + dx[i];
- int curY = currPoint.y + dy[i];
-
- if (!shouldSkipPixel(image, curX, curY, oldColor)) {
- queue.add(new Point(curX, curY));
- }
- }
- }
- }
-
- /**
- * Represents a point in 2D space with integer coordinates.
- */
- private static class Point {
- final int x;
- final int y;
-
- Point(final int x, final int y) {
- this.x = x;
- this.y = y;
- }
- }
-
- /**
- * Checks if a pixel should be skipped during flood fill operation.
- *
- * @param image The image to get boundaries
- * @param x The x coordinate of pixel to check
- * @param y The y coordinate of pixel to check
- * @param oldColor The old color which is to be replaced in the image
- * @return {@code true} if pixel should be skipped, else {@code false}
- */
- private static boolean shouldSkipPixel(final int[][] image, final int x, final int y, final int oldColor) {
-
- if (x < 0 || x >= image.length || y < 0 || y >= image[0].length || image[x][y] != oldColor) {
- return true;
- }
-
- return false;
- }
-}
+package com.thealgorithms.others;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * Implementation of the Flood Fill algorithm using an iterative BFS (Breadth-First Search) approach.
+ *
+ * The Flood Fill algorithm is used to fill connected areas in an image with a new color, starting from a specified point.
+ * This implementation uses an iterative BFS approach with a queue
+ * instead of recursion to avoid stack overflow issues with large images.
+ *
+ * Implementation Features:
+ *
+ * - Supports 8-connected filling (horizontal, vertical, and diagonal directions)
+ * - Uses BFS traversal through {@link java.util.Queue}
+ * - Includes nested {@code Point} class to represent pixel coordinates
+ * - Iterative approach avoids stack overflow for large images
+ *
+ *
+ * Time Complexity: O(M × N) where M and N are the dimensions of the image
+ * Space Complexity: O(M × N) in the worst case the queue stores every pixel
+ *
+ * @see Flood Fill Algorithm - GeeksforGeeks
+ * @see Flood Fill Algorithm - Wikipedia
+ */
+public final class IterativeFloodFill {
+ private IterativeFloodFill() {
+ }
+
+ /**
+ * Iteratively fill the 2D image with new color
+ *
+ * @param image The image to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
+ * @param newColor The new color which to be filled in the image
+ * @param oldColor The old color which is to be replaced in the image
+ * @see FloodFill BFS
+ */
+ public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
+ if (image.length == 0 || image[0].length == 0 || newColor == oldColor || shouldSkipPixel(image, x, y, oldColor)) {
+ return;
+ }
+
+ Queue queue = new LinkedList<>();
+ queue.add(new Point(x, y));
+
+ int[] dx = {0, 0, -1, 1, 1, -1, 1, -1};
+ int[] dy = {-1, 1, 0, 0, -1, 1, 1, -1};
+
+ while (!queue.isEmpty()) {
+ Point currPoint = queue.poll();
+
+ if (shouldSkipPixel(image, currPoint.x, currPoint.y, oldColor)) {
+ continue;
+ }
+
+ image[currPoint.x][currPoint.y] = newColor;
+
+ for (int i = 0; i < 8; i++) {
+ int curX = currPoint.x + dx[i];
+ int curY = currPoint.y + dy[i];
+
+ if (!shouldSkipPixel(image, curX, curY, oldColor)) {
+ queue.add(new Point(curX, curY));
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents a point in 2D space with integer coordinates.
+ */
+ private static class Point {
+ final int x;
+ final int y;
+
+ Point(final int x, final int y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ /**
+ * Checks if a pixel should be skipped during flood fill operation.
+ *
+ * @param image The image to get boundaries
+ * @param x The x coordinate of pixel to check
+ * @param y The y coordinate of pixel to check
+ * @param oldColor The old color which is to be replaced in the image
+ * @return {@code true} if pixel should be skipped, else {@code false}
+ */
+ private static boolean shouldSkipPixel(final int[][] image, final int x, final int y, final int oldColor) {
+
+ if (x < 0 || x >= image.length || y < 0 || y >= image[0].length || image[x][y] != oldColor) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
index b53c7e5256ca..048ddd9bdaa8 100644
--- a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
+++ b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
@@ -1,32 +1,32 @@
-package com.thealgorithms.searches;
-
-public class SearchInARowAndColWiseSortedMatrix {
- /**
- * Search a key in row and column wise sorted matrix
- *
- * @param matrix matrix to be searched
- * @param value Key being searched for
- * @author Sadiul Hakim : https://github.com/sadiul-hakim
- */
- public int[] search(int[][] matrix, int value) {
- int n = matrix.length;
- // This variable iterates over rows
- int i = 0;
- // This variable iterates over columns
- int j = n - 1;
- int[] result = {-1, -1};
- while (i < n && j >= 0) {
- if (matrix[i][j] == value) {
- result[0] = i;
- result[1] = j;
- return result;
- }
- if (value > matrix[i][j]) {
- i++;
- } else {
- j--;
- }
- }
- return result;
- }
-}
+package com.thealgorithms.searches;
+
+public class SearchInARowAndColWiseSortedMatrix {
+ /**
+ * Search a key in row and column wise sorted matrix
+ *
+ * @param matrix matrix to be searched
+ * @param value Key being searched for
+ * @author Sadiul Hakim : https://github.com/sadiul-hakim
+ */
+ public int[] search(int[][] matrix, int value) {
+ int n = matrix.length;
+ // This variable iterates over rows
+ int i = 0;
+ // This variable iterates over columns
+ int j = n - 1;
+ int[] result = {-1, -1};
+ while (i < n && j >= 0) {
+ if (matrix[i][j] == value) {
+ result[0] = i;
+ result[1] = j;
+ return result;
+ }
+ if (value > matrix[i][j]) {
+ i++;
+ } else {
+ j--;
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/strings/AhoCorasick.java b/src/main/java/com/thealgorithms/strings/AhoCorasick.java
index a68d0823a00d..b01cc1f01335 100644
--- a/src/main/java/com/thealgorithms/strings/AhoCorasick.java
+++ b/src/main/java/com/thealgorithms/strings/AhoCorasick.java
@@ -1,246 +1,246 @@
-/*
- * Aho-Corasick String Matching Algorithm Implementation
- *
- * This code implements the Aho-Corasick algorithm, which is used for efficient
- * string matching in a given text. It can find multiple patterns simultaneously
- * and records their positions in the text.
- *
- * Author: Prabhat-Kumar-42
- * GitHub: https://github.com/Prabhat-Kumar-42
- */
-
-package com.thealgorithms.strings;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-
-public final class AhoCorasick {
- private AhoCorasick() {
- }
-
- // Trie Node Class
- private static class Node {
- // Represents a character in the trie
- private final Map child = new HashMap<>(); // Child nodes of the current node
- private Node suffixLink; // Suffix link to another node in the trie
- private Node outputLink; // Output link to another node in the trie
- private int patternInd; // Index of the pattern that ends at this node
-
- Node() {
- this.suffixLink = null;
- this.outputLink = null;
- this.patternInd = -1;
- }
-
- public Map getChild() {
- return child;
- }
-
- public Node getSuffixLink() {
- return suffixLink;
- }
-
- public void setSuffixLink(final Node suffixLink) {
- this.suffixLink = suffixLink;
- }
-
- public Node getOutputLink() {
- return outputLink;
- }
-
- public void setOutputLink(final Node outputLink) {
- this.outputLink = outputLink;
- }
-
- public int getPatternInd() {
- return patternInd;
- }
-
- public void setPatternInd(final int patternInd) {
- this.patternInd = patternInd;
- }
- }
-
- // Trie Class
- public static class Trie {
-
- private Node root = null; // Root node of the trie
- private final String[] patterns; // patterns according to which Trie is constructed
-
- public Trie(final String[] patterns) {
- root = new Node(); // Initialize the root of the trie
- this.patterns = patterns;
- buildTrie();
- buildSuffixAndOutputLinks();
- }
-
- // builds AhoCorasick Trie
- private void buildTrie() {
-
- // Loop through each input pattern and building Trie
- for (int i = 0; i < patterns.length; i++) {
- Node curr = root; // Start at the root of the trie for each pattern
-
- // Loop through each character in the current pattern
- for (int j = 0; j < patterns[i].length(); j++) {
- char c = patterns[i].charAt(j); // Get the current character
-
- // Check if the current node has a child for the current character
- if (curr.getChild().containsKey(c)) {
- curr = curr.getChild().get(c); // Update the current node to the child node
- } else {
- // If no child node exists, create a new one and add it to the current node's children
- Node nn = new Node();
- curr.getChild().put(c, nn);
- curr = nn; // Update the current node to the new child node
- }
- }
- curr.setPatternInd(i); // Store the index of the pattern in the current leaf node
- }
- }
-
- private void initializeSuffixLinksForChildNodesOfTheRoot(Queue q) {
- for (char rc : root.getChild().keySet()) {
- Node childNode = root.getChild().get(rc);
- q.add(childNode); // Add child node to the queue
- childNode.setSuffixLink(root); // Set suffix link to the root
- }
- }
-
- private void buildSuffixAndOutputLinks() {
- root.setSuffixLink(root); // Initialize the suffix link of the root to itself
- Queue q = new LinkedList<>(); // Initialize a queue for BFS traversal
-
- initializeSuffixLinksForChildNodesOfTheRoot(q);
-
- while (!q.isEmpty()) {
- Node currentState = q.poll(); // Get the current node for processing
-
- // Iterate through child nodes of the current node
- for (char cc : currentState.getChild().keySet()) {
- Node currentChild = currentState.getChild().get(cc); // Get the child node
- Node parentSuffix = currentState.getSuffixLink(); // Get the parent's suffix link
-
- // Calculate the suffix link for the child based on the parent's suffix link
- while (!parentSuffix.getChild().containsKey(cc) && parentSuffix != root) {
- parentSuffix = parentSuffix.getSuffixLink();
- }
-
- // Set the calculated suffix link or default to root
- if (parentSuffix.getChild().containsKey(cc)) {
- currentChild.setSuffixLink(parentSuffix.getChild().get(cc));
- } else {
- currentChild.setSuffixLink(root);
- }
-
- q.add(currentChild); // Add the child node to the queue for further processing
- }
-
- // Establish output links for nodes to efficiently identify patterns within patterns
- if (currentState.getSuffixLink().getPatternInd() >= 0) {
- currentState.setOutputLink(currentState.getSuffixLink());
- } else {
- currentState.setOutputLink(currentState.getSuffixLink().getOutputLink());
- }
- }
- }
-
- private List> initializePositionByStringIndexValue() {
- List> positionByStringIndexValue = new ArrayList<>(patterns.length); // Stores positions where patterns are found in the text
- for (int i = 0; i < patterns.length; i++) {
- positionByStringIndexValue.add(new ArrayList<>());
- }
- return positionByStringIndexValue;
- }
-
- // Searches for patterns in the input text and records their positions
- public List> searchIn(final String text) {
- var positionByStringIndexValue = initializePositionByStringIndexValue(); // Initialize a list to store positions of the current pattern
- Node parent = root; // Start searching from the root node
-
- PatternPositionRecorder positionRecorder = new PatternPositionRecorder(positionByStringIndexValue);
-
- for (int i = 0; i < text.length(); i++) {
- char ch = text.charAt(i); // Get the current character in the text
-
- // Check if the current node has a child for the current character
- if (parent.getChild().containsKey(ch)) {
- parent = parent.getChild().get(ch); // Update the current node to the child node
- positionRecorder.recordPatternPositions(parent, i); // Use the method in PatternPositionRecorder to record positions
- } else {
- // If no child node exists for the character, backtrack using suffix links
- while (parent != root && !parent.getChild().containsKey(ch)) {
- parent = parent.getSuffixLink();
- }
- if (parent.getChild().containsKey(ch)) {
- i--; // Decrement i to reprocess the same character
- }
- }
- }
-
- setUpStartPoints(positionByStringIndexValue);
- return positionByStringIndexValue;
- }
-
- // by default positionByStringIndexValue contains end-points. This function converts those
- // endpoints to start points
- private void setUpStartPoints(List> positionByStringIndexValue) {
- for (int i = 0; i < patterns.length; i++) {
- for (int j = 0; j < positionByStringIndexValue.get(i).size(); j++) {
- int endpoint = positionByStringIndexValue.get(i).get(j);
- positionByStringIndexValue.get(i).set(j, endpoint - patterns[i].length() + 1);
- }
- }
- }
- }
-
- // Class to handle pattern position recording
- private record PatternPositionRecorder(List> positionByStringIndexValue) {
- // Constructor to initialize the recorder with the position list
-
- /**
- * Records positions for a pattern when it's found in the input text and follows
- * output links to record positions of other patterns.
- *
- * @param parent The current node representing a character in the pattern trie.
- * @param currentPosition The current position in the input text.
- */
- public void recordPatternPositions(final Node parent, final int currentPosition) {
- // Check if the current node represents the end of a pattern
- if (parent.getPatternInd() > -1) {
- // Add the current position to the list of positions for the found pattern
- positionByStringIndexValue.get(parent.getPatternInd()).add(currentPosition);
- }
-
- Node outputLink = parent.getOutputLink();
- // Follow output links to find and record positions of other patterns
- while (outputLink != null) {
- // Add the current position to the list of positions for the pattern linked by outputLink
- positionByStringIndexValue.get(outputLink.getPatternInd()).add(currentPosition);
- outputLink = outputLink.getOutputLink();
- }
- }
- }
-
- // method to search for patterns in text
- public static Map> search(final String text, final String[] patterns) {
- final var trie = new Trie(patterns);
- final var positionByStringIndexValue = trie.searchIn(text);
- return convert(positionByStringIndexValue, patterns);
- }
-
- // method for converting results to a map
- private static Map> convert(final List> positionByStringIndexValue, final String[] patterns) {
- Map> positionByString = new HashMap<>();
- for (int i = 0; i < patterns.length; i++) {
- String pattern = patterns[i];
- List positions = positionByStringIndexValue.get(i);
- positionByString.put(pattern, new ArrayList<>(positions));
- }
- return positionByString;
- }
-}
+/*
+ * Aho-Corasick String Matching Algorithm Implementation
+ *
+ * This code implements the Aho-Corasick algorithm, which is used for efficient
+ * string matching in a given text. It can find multiple patterns simultaneously
+ * and records their positions in the text.
+ *
+ * Author: Prabhat-Kumar-42
+ * GitHub: https://github.com/Prabhat-Kumar-42
+ */
+
+package com.thealgorithms.strings;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+public final class AhoCorasick {
+ private AhoCorasick() {
+ }
+
+ // Trie Node Class
+ private static class Node {
+ // Represents a character in the trie
+ private final Map child = new HashMap<>(); // Child nodes of the current node
+ private Node suffixLink; // Suffix link to another node in the trie
+ private Node outputLink; // Output link to another node in the trie
+ private int patternInd; // Index of the pattern that ends at this node
+
+ Node() {
+ this.suffixLink = null;
+ this.outputLink = null;
+ this.patternInd = -1;
+ }
+
+ public Map getChild() {
+ return child;
+ }
+
+ public Node getSuffixLink() {
+ return suffixLink;
+ }
+
+ public void setSuffixLink(final Node suffixLink) {
+ this.suffixLink = suffixLink;
+ }
+
+ public Node getOutputLink() {
+ return outputLink;
+ }
+
+ public void setOutputLink(final Node outputLink) {
+ this.outputLink = outputLink;
+ }
+
+ public int getPatternInd() {
+ return patternInd;
+ }
+
+ public void setPatternInd(final int patternInd) {
+ this.patternInd = patternInd;
+ }
+ }
+
+ // Trie Class
+ public static class Trie {
+
+ private Node root = null; // Root node of the trie
+ private final String[] patterns; // patterns according to which Trie is constructed
+
+ public Trie(final String[] patterns) {
+ root = new Node(); // Initialize the root of the trie
+ this.patterns = patterns;
+ buildTrie();
+ buildSuffixAndOutputLinks();
+ }
+
+ // builds AhoCorasick Trie
+ private void buildTrie() {
+
+ // Loop through each input pattern and building Trie
+ for (int i = 0; i < patterns.length; i++) {
+ Node curr = root; // Start at the root of the trie for each pattern
+
+ // Loop through each character in the current pattern
+ for (int j = 0; j < patterns[i].length(); j++) {
+ char c = patterns[i].charAt(j); // Get the current character
+
+ // Check if the current node has a child for the current character
+ if (curr.getChild().containsKey(c)) {
+ curr = curr.getChild().get(c); // Update the current node to the child node
+ } else {
+ // If no child node exists, create a new one and add it to the current node's children
+ Node nn = new Node();
+ curr.getChild().put(c, nn);
+ curr = nn; // Update the current node to the new child node
+ }
+ }
+ curr.setPatternInd(i); // Store the index of the pattern in the current leaf node
+ }
+ }
+
+ private void initializeSuffixLinksForChildNodesOfTheRoot(Queue q) {
+ for (char rc : root.getChild().keySet()) {
+ Node childNode = root.getChild().get(rc);
+ q.add(childNode); // Add child node to the queue
+ childNode.setSuffixLink(root); // Set suffix link to the root
+ }
+ }
+
+ private void buildSuffixAndOutputLinks() {
+ root.setSuffixLink(root); // Initialize the suffix link of the root to itself
+ Queue q = new LinkedList<>(); // Initialize a queue for BFS traversal
+
+ initializeSuffixLinksForChildNodesOfTheRoot(q);
+
+ while (!q.isEmpty()) {
+ Node currentState = q.poll(); // Get the current node for processing
+
+ // Iterate through child nodes of the current node
+ for (char cc : currentState.getChild().keySet()) {
+ Node currentChild = currentState.getChild().get(cc); // Get the child node
+ Node parentSuffix = currentState.getSuffixLink(); // Get the parent's suffix link
+
+ // Calculate the suffix link for the child based on the parent's suffix link
+ while (!parentSuffix.getChild().containsKey(cc) && parentSuffix != root) {
+ parentSuffix = parentSuffix.getSuffixLink();
+ }
+
+ // Set the calculated suffix link or default to root
+ if (parentSuffix.getChild().containsKey(cc)) {
+ currentChild.setSuffixLink(parentSuffix.getChild().get(cc));
+ } else {
+ currentChild.setSuffixLink(root);
+ }
+
+ q.add(currentChild); // Add the child node to the queue for further processing
+ }
+
+ // Establish output links for nodes to efficiently identify patterns within patterns
+ if (currentState.getSuffixLink().getPatternInd() >= 0) {
+ currentState.setOutputLink(currentState.getSuffixLink());
+ } else {
+ currentState.setOutputLink(currentState.getSuffixLink().getOutputLink());
+ }
+ }
+ }
+
+ private List> initializePositionByStringIndexValue() {
+ List> positionByStringIndexValue = new ArrayList<>(patterns.length); // Stores positions where patterns are found in the text
+ for (int i = 0; i < patterns.length; i++) {
+ positionByStringIndexValue.add(new ArrayList<>());
+ }
+ return positionByStringIndexValue;
+ }
+
+ // Searches for patterns in the input text and records their positions
+ public List> searchIn(final String text) {
+ var positionByStringIndexValue = initializePositionByStringIndexValue(); // Initialize a list to store positions of the current pattern
+ Node parent = root; // Start searching from the root node
+
+ PatternPositionRecorder positionRecorder = new PatternPositionRecorder(positionByStringIndexValue);
+
+ for (int i = 0; i < text.length(); i++) {
+ char ch = text.charAt(i); // Get the current character in the text
+
+ // Check if the current node has a child for the current character
+ if (parent.getChild().containsKey(ch)) {
+ parent = parent.getChild().get(ch); // Update the current node to the child node
+ positionRecorder.recordPatternPositions(parent, i); // Use the method in PatternPositionRecorder to record positions
+ } else {
+ // If no child node exists for the character, backtrack using suffix links
+ while (parent != root && !parent.getChild().containsKey(ch)) {
+ parent = parent.getSuffixLink();
+ }
+ if (parent.getChild().containsKey(ch)) {
+ i--; // Decrement i to reprocess the same character
+ }
+ }
+ }
+
+ setUpStartPoints(positionByStringIndexValue);
+ return positionByStringIndexValue;
+ }
+
+ // by default positionByStringIndexValue contains end-points. This function converts those
+ // endpoints to start points
+ private void setUpStartPoints(List> positionByStringIndexValue) {
+ for (int i = 0; i < patterns.length; i++) {
+ for (int j = 0; j < positionByStringIndexValue.get(i).size(); j++) {
+ int endpoint = positionByStringIndexValue.get(i).get(j);
+ positionByStringIndexValue.get(i).set(j, endpoint - patterns[i].length() + 1);
+ }
+ }
+ }
+ }
+
+ // Class to handle pattern position recording
+ private record PatternPositionRecorder(List> positionByStringIndexValue) {
+ // Constructor to initialize the recorder with the position list
+
+ /**
+ * Records positions for a pattern when it's found in the input text and follows
+ * output links to record positions of other patterns.
+ *
+ * @param parent The current node representing a character in the pattern trie.
+ * @param currentPosition The current position in the input text.
+ */
+ public void recordPatternPositions(final Node parent, final int currentPosition) {
+ // Check if the current node represents the end of a pattern
+ if (parent.getPatternInd() > -1) {
+ // Add the current position to the list of positions for the found pattern
+ positionByStringIndexValue.get(parent.getPatternInd()).add(currentPosition);
+ }
+
+ Node outputLink = parent.getOutputLink();
+ // Follow output links to find and record positions of other patterns
+ while (outputLink != null) {
+ // Add the current position to the list of positions for the pattern linked by outputLink
+ positionByStringIndexValue.get(outputLink.getPatternInd()).add(currentPosition);
+ outputLink = outputLink.getOutputLink();
+ }
+ }
+ }
+
+ // method to search for patterns in text
+ public static Map> search(final String text, final String[] patterns) {
+ final var trie = new Trie(patterns);
+ final var positionByStringIndexValue = trie.searchIn(text);
+ return convert(positionByStringIndexValue, patterns);
+ }
+
+ // method for converting results to a map
+ private static Map> convert(final List> positionByStringIndexValue, final String[] patterns) {
+ Map> positionByString = new HashMap<>();
+ for (int i = 0; i < patterns.length; i++) {
+ String pattern = patterns[i];
+ List positions = positionByStringIndexValue.get(i);
+ positionByString.put(pattern, new ArrayList<>(positions));
+ }
+ return positionByString;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/AtbashTest.java b/src/test/java/com/thealgorithms/ciphers/AtbashTest.java
index ec34bc26ad72..490dbbc63197 100644
--- a/src/test/java/com/thealgorithms/ciphers/AtbashTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/AtbashTest.java
@@ -1,43 +1,43 @@
-package com.thealgorithms.ciphers;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.util.stream.Stream;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-public class AtbashTest {
-
- @ParameterizedTest
- @MethodSource("cipherTestProvider")
- public void testAtbashCipher(String input, String expected) {
- AtbashCipher cipher = new AtbashCipher(input);
- assertEquals(expected, cipher.convert());
- }
-
- private static Stream cipherTestProvider() {
- return Stream.of(
- // Basic tests with lowercase and uppercase
- Arguments.of("Hello", "Svool"), Arguments.of("WORLD", "DLIOW"),
-
- // Mixed case with spaces and punctuation
- Arguments.of("Hello World!", "Svool Dliow!"), Arguments.of("123 ABC xyz", "123 ZYX cba"),
-
- // Palindromes and mixed cases
- Arguments.of("madam", "nzwzn"), Arguments.of("Palindrome", "Kzormwilnv"),
-
- // Non-alphabetic characters should remain unchanged
- Arguments.of("@cipher 123!", "@xrksvi 123!"), Arguments.of("no-change", "ml-xszmtv"),
-
- // Empty string and single characters
- Arguments.of("", ""), Arguments.of("A", "Z"), Arguments.of("z", "a"),
-
- // Numbers and symbols
- Arguments.of("!@#123", "!@#123"),
-
- // Full sentence with uppercase, lowercase, symbols, and numbers
- Arguments.of("Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!", "Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!"),
- Arguments.of("Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!", "Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!"));
- }
-}
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class AtbashTest {
+
+ @ParameterizedTest
+ @MethodSource("cipherTestProvider")
+ public void testAtbashCipher(String input, String expected) {
+ AtbashCipher cipher = new AtbashCipher(input);
+ assertEquals(expected, cipher.convert());
+ }
+
+ private static Stream cipherTestProvider() {
+ return Stream.of(
+ // Basic tests with lowercase and uppercase
+ Arguments.of("Hello", "Svool"), Arguments.of("WORLD", "DLIOW"),
+
+ // Mixed case with spaces and punctuation
+ Arguments.of("Hello World!", "Svool Dliow!"), Arguments.of("123 ABC xyz", "123 ZYX cba"),
+
+ // Palindromes and mixed cases
+ Arguments.of("madam", "nzwzn"), Arguments.of("Palindrome", "Kzormwilnv"),
+
+ // Non-alphabetic characters should remain unchanged
+ Arguments.of("@cipher 123!", "@xrksvi 123!"), Arguments.of("no-change", "ml-xszmtv"),
+
+ // Empty string and single characters
+ Arguments.of("", ""), Arguments.of("A", "Z"), Arguments.of("z", "a"),
+
+ // Numbers and symbols
+ Arguments.of("!@#123", "!@#123"),
+
+ // Full sentence with uppercase, lowercase, symbols, and numbers
+ Arguments.of("Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!", "Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!"),
+ Arguments.of("Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!", "Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!"));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
index ecb7455c1ba2..83e8fdc43c88 100644
--- a/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/PermutationCipherTest.java
@@ -1,324 +1,324 @@
-package com.thealgorithms.ciphers;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import org.junit.jupiter.api.Test;
-
-class PermutationCipherTest {
-
- private final PermutationCipher cipher = new PermutationCipher();
-
- @Test
- void testBasicEncryption() {
- // given
- String plaintext = "HELLO";
- int[] key = {3, 1, 2}; // Move 3rd position to 1st, 1st to 2nd, 2nd to 3rd
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
-
- // then
- // "HELLO" becomes "HEL" + "LOX" (padded)
- // "HEL" with key {3,1,2} becomes "LHE" (L=3rd, H=1st, E=2nd)
- // "LOX" with key {3,1,2} becomes "XLO" (X=3rd, L=1st, O=2nd)
- assertEquals("LHEXLO", encrypted);
- }
-
- @Test
- void testBasicDecryption() {
- // given
- String ciphertext = "LHEXLO";
- int[] key = {3, 1, 2};
-
- // when
- String decrypted = cipher.decrypt(ciphertext, key);
-
- // then
- assertEquals("HELLO", decrypted);
- }
-
- @Test
- void testEncryptDecryptRoundTrip() {
- // given
- String plaintext = "THIS IS A TEST MESSAGE";
- int[] key = {4, 2, 1, 3};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("THISISATESTMESSAGE", decrypted); // Spaces are removed during encryption
- }
-
- @Test
- void testSingleCharacterKey() {
- // given
- String plaintext = "ABCDEF";
- int[] key = {1}; // Identity permutation
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("ABCDEF", encrypted); // Should remain unchanged
- assertEquals("ABCDEF", decrypted);
- }
-
- @Test
- void testLargerKey() {
- // given
- String plaintext = "PERMUTATION";
- int[] key = {5, 3, 1, 4, 2}; // 5-character permutation
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("PERMUTATION", decrypted);
- }
-
- @Test
- void testExactBlockSize() {
- // given
- String plaintext = "ABCDEF"; // Length 6, divisible by key length 3
- int[] key = {2, 3, 1};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("ABCDEF", decrypted);
- }
-
- @Test
- void testEmptyString() {
- // given
- String plaintext = "";
- int[] key = {2, 1, 3};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("", encrypted);
- assertEquals("", decrypted);
- }
-
- @Test
- void testNullString() {
- // given
- String plaintext = null;
- int[] key = {2, 1, 3};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertNull(encrypted);
- assertNull(decrypted);
- }
-
- @Test
- void testStringWithSpaces() {
- // given
- String plaintext = "A B C D E F";
- int[] key = {2, 1};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("ABCDEF", decrypted); // Spaces should be removed
- }
-
- @Test
- void testLowercaseConversion() {
- // given
- String plaintext = "hello world";
- int[] key = {3, 1, 2};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("HELLOWORLD", decrypted); // Should be converted to uppercase
- }
-
- @Test
- void testInvalidKeyNull() {
- // given
- String plaintext = "HELLO";
- int[] key = null;
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testInvalidKeyEmpty() {
- // given
- String plaintext = "HELLO";
- int[] key = {};
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testInvalidKeyOutOfRange() {
- // given
- String plaintext = "HELLO";
- int[] key = {1, 2, 4}; // 4 is out of range for key length 3
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testInvalidKeyZero() {
- // given
- String plaintext = "HELLO";
- int[] key = {0, 1, 2}; // 0 is invalid (should be 1-based)
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testInvalidKeyDuplicate() {
- // given
- String plaintext = "HELLO";
- int[] key = {1, 2, 2}; // Duplicate position
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testInvalidKeyMissingPosition() {
- // given
- String plaintext = "HELLO";
- int[] key = {1, 3}; // Missing position 2
-
- // when & then
- assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
- assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
- }
-
- @Test
- void testReverseKey() {
- // given
- String plaintext = "ABCD";
- int[] key = {4, 3, 2, 1}; // Reverse order
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("DCBA", encrypted); // Should be reversed
- assertEquals("ABCD", decrypted);
- }
-
- @Test
- void testSpecificExampleFromDescription() {
- // given
- String plaintext = "HELLO";
- int[] key = {3, 1, 2};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
-
- // then
- // Block 1: "HEL" -> positions {3,1,2} -> "LHE"
- // Block 2: "LOX" -> positions {3,1,2} -> "XLO"
- assertEquals("LHEXLO", encrypted);
- // Verify decryption
- String decrypted = cipher.decrypt(encrypted, key);
- assertEquals("HELLO", decrypted);
- }
-
- @Test
- void testPaddingCharacterGetter() {
- // when
- char paddingChar = cipher.getPaddingChar();
-
- // then
- assertEquals('X', paddingChar);
- }
-
- @Test
- void testLongText() {
- // given
- String plaintext = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
- int[] key = {4, 1, 3, 2};
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG", decrypted);
- }
-
- @Test
- void testIdentityPermutation() {
- // given
- String plaintext = "IDENTITY";
- int[] key = {1, 2, 3, 4}; // Identity permutation
-
- // when
- String encrypted = cipher.encrypt(plaintext, key);
- String decrypted = cipher.decrypt(encrypted, key);
-
- // then
- assertEquals("IDENTITY", encrypted); // Should remain unchanged
- assertEquals("IDENTITY", decrypted);
- }
-
- @Test
- void testEmptyStringRemovePadding() {
- // given - Test to cover line 178 (empty string case in removePadding)
- String ciphertext = "";
- int[] key = {2, 1, 3};
-
- // when
- String decrypted = cipher.decrypt(ciphertext, key);
-
- // then
- assertEquals("", decrypted); // Should return empty string directly
- }
-
- @Test
- void testBlockShorterThanKey() {
- // given - Test to cover line 139 (block length != key length case)
- // This is a defensive case where permuteBlock might receive a block shorter than key
- // We can test this by manually creating a scenario with malformed ciphertext
- String malformedCiphertext = "AB"; // Length 2, but key length is 3
- int[] key = {3, 1, 2}; // Key length is 3
-
- // when - This should trigger the padding logic in permuteBlock during decryption
- String decrypted = cipher.decrypt(malformedCiphertext, key);
-
- // then - The method should handle the short block gracefully
- // "AB" gets padded to "ABX", then permuted with inverse key {2,3,1}
- // inverse key {2,3,1} means: pos 2→1st, pos 3→2nd, pos 1→3rd = "BXA"
- // Padding removal only removes trailing X's, so "BXA" remains as is
- assertEquals("BXA", decrypted);
- }
-}
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+class PermutationCipherTest {
+
+ private final PermutationCipher cipher = new PermutationCipher();
+
+ @Test
+ void testBasicEncryption() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {3, 1, 2}; // Move 3rd position to 1st, 1st to 2nd, 2nd to 3rd
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+
+ // then
+ // "HELLO" becomes "HEL" + "LOX" (padded)
+ // "HEL" with key {3,1,2} becomes "LHE" (L=3rd, H=1st, E=2nd)
+ // "LOX" with key {3,1,2} becomes "XLO" (X=3rd, L=1st, O=2nd)
+ assertEquals("LHEXLO", encrypted);
+ }
+
+ @Test
+ void testBasicDecryption() {
+ // given
+ String ciphertext = "LHEXLO";
+ int[] key = {3, 1, 2};
+
+ // when
+ String decrypted = cipher.decrypt(ciphertext, key);
+
+ // then
+ assertEquals("HELLO", decrypted);
+ }
+
+ @Test
+ void testEncryptDecryptRoundTrip() {
+ // given
+ String plaintext = "THIS IS A TEST MESSAGE";
+ int[] key = {4, 2, 1, 3};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("THISISATESTMESSAGE", decrypted); // Spaces are removed during encryption
+ }
+
+ @Test
+ void testSingleCharacterKey() {
+ // given
+ String plaintext = "ABCDEF";
+ int[] key = {1}; // Identity permutation
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("ABCDEF", encrypted); // Should remain unchanged
+ assertEquals("ABCDEF", decrypted);
+ }
+
+ @Test
+ void testLargerKey() {
+ // given
+ String plaintext = "PERMUTATION";
+ int[] key = {5, 3, 1, 4, 2}; // 5-character permutation
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("PERMUTATION", decrypted);
+ }
+
+ @Test
+ void testExactBlockSize() {
+ // given
+ String plaintext = "ABCDEF"; // Length 6, divisible by key length 3
+ int[] key = {2, 3, 1};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("ABCDEF", decrypted);
+ }
+
+ @Test
+ void testEmptyString() {
+ // given
+ String plaintext = "";
+ int[] key = {2, 1, 3};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("", encrypted);
+ assertEquals("", decrypted);
+ }
+
+ @Test
+ void testNullString() {
+ // given
+ String plaintext = null;
+ int[] key = {2, 1, 3};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertNull(encrypted);
+ assertNull(decrypted);
+ }
+
+ @Test
+ void testStringWithSpaces() {
+ // given
+ String plaintext = "A B C D E F";
+ int[] key = {2, 1};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("ABCDEF", decrypted); // Spaces should be removed
+ }
+
+ @Test
+ void testLowercaseConversion() {
+ // given
+ String plaintext = "hello world";
+ int[] key = {3, 1, 2};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("HELLOWORLD", decrypted); // Should be converted to uppercase
+ }
+
+ @Test
+ void testInvalidKeyNull() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = null;
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testInvalidKeyEmpty() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {};
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testInvalidKeyOutOfRange() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {1, 2, 4}; // 4 is out of range for key length 3
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testInvalidKeyZero() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {0, 1, 2}; // 0 is invalid (should be 1-based)
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testInvalidKeyDuplicate() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {1, 2, 2}; // Duplicate position
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testInvalidKeyMissingPosition() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {1, 3}; // Missing position 2
+
+ // when & then
+ assertThrows(IllegalArgumentException.class, () -> cipher.encrypt(plaintext, key));
+ assertThrows(IllegalArgumentException.class, () -> cipher.decrypt(plaintext, key));
+ }
+
+ @Test
+ void testReverseKey() {
+ // given
+ String plaintext = "ABCD";
+ int[] key = {4, 3, 2, 1}; // Reverse order
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("DCBA", encrypted); // Should be reversed
+ assertEquals("ABCD", decrypted);
+ }
+
+ @Test
+ void testSpecificExampleFromDescription() {
+ // given
+ String plaintext = "HELLO";
+ int[] key = {3, 1, 2};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+
+ // then
+ // Block 1: "HEL" -> positions {3,1,2} -> "LHE"
+ // Block 2: "LOX" -> positions {3,1,2} -> "XLO"
+ assertEquals("LHEXLO", encrypted);
+ // Verify decryption
+ String decrypted = cipher.decrypt(encrypted, key);
+ assertEquals("HELLO", decrypted);
+ }
+
+ @Test
+ void testPaddingCharacterGetter() {
+ // when
+ char paddingChar = cipher.getPaddingChar();
+
+ // then
+ assertEquals('X', paddingChar);
+ }
+
+ @Test
+ void testLongText() {
+ // given
+ String plaintext = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG";
+ int[] key = {4, 1, 3, 2};
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG", decrypted);
+ }
+
+ @Test
+ void testIdentityPermutation() {
+ // given
+ String plaintext = "IDENTITY";
+ int[] key = {1, 2, 3, 4}; // Identity permutation
+
+ // when
+ String encrypted = cipher.encrypt(plaintext, key);
+ String decrypted = cipher.decrypt(encrypted, key);
+
+ // then
+ assertEquals("IDENTITY", encrypted); // Should remain unchanged
+ assertEquals("IDENTITY", decrypted);
+ }
+
+ @Test
+ void testEmptyStringRemovePadding() {
+ // given - Test to cover line 178 (empty string case in removePadding)
+ String ciphertext = "";
+ int[] key = {2, 1, 3};
+
+ // when
+ String decrypted = cipher.decrypt(ciphertext, key);
+
+ // then
+ assertEquals("", decrypted); // Should return empty string directly
+ }
+
+ @Test
+ void testBlockShorterThanKey() {
+ // given - Test to cover line 139 (block length != key length case)
+ // This is a defensive case where permuteBlock might receive a block shorter than key
+ // We can test this by manually creating a scenario with malformed ciphertext
+ String malformedCiphertext = "AB"; // Length 2, but key length is 3
+ int[] key = {3, 1, 2}; // Key length is 3
+
+ // when - This should trigger the padding logic in permuteBlock during decryption
+ String decrypted = cipher.decrypt(malformedCiphertext, key);
+
+ // then - The method should handle the short block gracefully
+ // "AB" gets padded to "ABX", then permuted with inverse key {2,3,1}
+ // inverse key {2,3,1} means: pos 2→1st, pos 3→2nd, pos 1→3rd = "BXA"
+ // Padding removal only removes trailing X's, so "BXA" remains as is
+ assertEquals("BXA", decrypted);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java b/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
index 2bfa704e3d0b..173c91078491 100644
--- a/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
@@ -1,62 +1,62 @@
-package com.thealgorithms.ciphers;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.jupiter.api.Test;
-
-public class RailFenceTest {
-
- @Test
- void testEncryption() {
- RailFenceCipher cipher = new RailFenceCipher();
-
- String input = "We are discovered! Flee at once";
- int rails = 3;
- String encrypted = cipher.encrypt(input, rails);
- assertEquals("Wrivdlaneaedsoee!Fe toc cr e e", encrypted);
-
- String singleChar = "A";
- int singleRail = 2;
- String encryptedSingleChar = cipher.encrypt(singleChar, singleRail);
- assertEquals("A", encryptedSingleChar);
-
- String shortString = "Hello";
- int moreRails = 10;
- String encryptedShortString = cipher.encrypt(shortString, moreRails);
- assertEquals("Hello", encryptedShortString);
-
- String inputSingleRail = "Single line";
- int singleRailOnly = 1;
- String encryptedSingleRail = cipher.encrypt(inputSingleRail, singleRailOnly);
- assertEquals("Single line", encryptedSingleRail);
- }
-
- @Test
- void testDecryption() {
- RailFenceCipher cipher = new RailFenceCipher();
-
- // Scenario 1: Basic decryption with multiple rails
- String encryptedInput = "Wrivdlaneaedsoee!Fe toc cr e e";
- int rails = 3;
- String decrypted = cipher.decrypt(encryptedInput, rails);
- assertEquals("We are discovered! Flee at once", decrypted);
-
- // Scenario 2: Single character string decryption
- String encryptedSingleChar = "A";
- int singleRail = 2; // More than 1 rail
- String decryptedSingleChar = cipher.decrypt(encryptedSingleChar, singleRail);
- assertEquals("A", decryptedSingleChar);
-
- // Scenario 3: String length less than the number of rails
- String encryptedShortString = "Hello";
- int moreRails = 10; // More rails than characters
- String decryptedShortString = cipher.decrypt(encryptedShortString, moreRails);
- assertEquals("Hello", decryptedShortString);
-
- // Scenario 4: Single rail decryption (output should be the same as input)
- String encryptedSingleRail = "Single line";
- int singleRailOnly = 1;
- String decryptedSingleRail = cipher.decrypt(encryptedSingleRail, singleRailOnly);
- assertEquals("Single line", decryptedSingleRail);
- }
-}
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class RailFenceTest {
+
+ @Test
+ void testEncryption() {
+ RailFenceCipher cipher = new RailFenceCipher();
+
+ String input = "We are discovered! Flee at once";
+ int rails = 3;
+ String encrypted = cipher.encrypt(input, rails);
+ assertEquals("Wrivdlaneaedsoee!Fe toc cr e e", encrypted);
+
+ String singleChar = "A";
+ int singleRail = 2;
+ String encryptedSingleChar = cipher.encrypt(singleChar, singleRail);
+ assertEquals("A", encryptedSingleChar);
+
+ String shortString = "Hello";
+ int moreRails = 10;
+ String encryptedShortString = cipher.encrypt(shortString, moreRails);
+ assertEquals("Hello", encryptedShortString);
+
+ String inputSingleRail = "Single line";
+ int singleRailOnly = 1;
+ String encryptedSingleRail = cipher.encrypt(inputSingleRail, singleRailOnly);
+ assertEquals("Single line", encryptedSingleRail);
+ }
+
+ @Test
+ void testDecryption() {
+ RailFenceCipher cipher = new RailFenceCipher();
+
+ // Scenario 1: Basic decryption with multiple rails
+ String encryptedInput = "Wrivdlaneaedsoee!Fe toc cr e e";
+ int rails = 3;
+ String decrypted = cipher.decrypt(encryptedInput, rails);
+ assertEquals("We are discovered! Flee at once", decrypted);
+
+ // Scenario 2: Single character string decryption
+ String encryptedSingleChar = "A";
+ int singleRail = 2; // More than 1 rail
+ String decryptedSingleChar = cipher.decrypt(encryptedSingleChar, singleRail);
+ assertEquals("A", decryptedSingleChar);
+
+ // Scenario 3: String length less than the number of rails
+ String encryptedShortString = "Hello";
+ int moreRails = 10; // More rails than characters
+ String decryptedShortString = cipher.decrypt(encryptedShortString, moreRails);
+ assertEquals("Hello", decryptedShortString);
+
+ // Scenario 4: Single rail decryption (output should be the same as input)
+ String encryptedSingleRail = "Single line";
+ int singleRailOnly = 1;
+ String decryptedSingleRail = cipher.decrypt(encryptedSingleRail, singleRailOnly);
+ assertEquals("Single line", decryptedSingleRail);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySizeTest.java b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySizeTest.java
index 71dade9796dc..a4d98215e259 100644
--- a/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySizeTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionBySizeTest.java
@@ -1,146 +1,146 @@
-package com.thealgorithms.datastructures.disjointsetunion;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-import org.junit.jupiter.api.Test;
-
-public class DisjointSetUnionBySizeTest {
-
- @Test
- public void testMakeSet() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node = dsu.makeSet(1);
- assertNotNull(node);
- assertEquals(node, node.parent);
- assertEquals(1, node.size);
- }
-
- @Test
- public void testUnionFindSet() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
- DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
- DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
- DisjointSetUnionBySize.Node node4 = dsu.makeSet(4);
-
- dsu.unionSets(node1, node2);
- dsu.unionSets(node3, node2);
- dsu.unionSets(node3, node4);
- dsu.unionSets(node1, node3);
-
- DisjointSetUnionBySize.Node root1 = dsu.findSet(node1);
- DisjointSetUnionBySize.Node root2 = dsu.findSet(node2);
- DisjointSetUnionBySize.Node root3 = dsu.findSet(node3);
- DisjointSetUnionBySize.Node root4 = dsu.findSet(node4);
-
- assertEquals(root1, root2);
- assertEquals(root1, root3);
- assertEquals(root1, root4);
- assertEquals(4, root1.size);
- }
-
- @Test
- public void testFindSetOnSingleNode() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node = dsu.makeSet("A");
- assertEquals(node, dsu.findSet(node));
- }
-
- @Test
- public void testUnionAlreadyConnectedNodes() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
- DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
- DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
-
- dsu.unionSets(node1, node2);
- dsu.unionSets(node2, node3);
-
- // Union nodes that are already connected
- dsu.unionSets(node1, node3);
-
- // All should have the same root
- DisjointSetUnionBySize.Node root = dsu.findSet(node1);
- assertEquals(root, dsu.findSet(node2));
- assertEquals(root, dsu.findSet(node3));
- assertEquals(3, root.size);
- }
-
- @Test
- public void testMultipleMakeSets() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
- DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
- DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
-
- assertNotEquals(node1, node2);
- assertNotEquals(node2, node3);
- assertNotEquals(node1, node3);
-
- assertEquals(node1, node1.parent);
- assertEquals(node2, node2.parent);
- assertEquals(node3, node3.parent);
- assertEquals(1, node1.size);
- assertEquals(1, node2.size);
- assertEquals(1, node3.size);
- }
-
- @Test
- public void testPathCompression() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
- DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
- DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
-
- dsu.unionSets(node1, node2);
- dsu.unionSets(node2, node3);
-
- // After findSet, path compression should update parent to root directly
- DisjointSetUnionBySize.Node root = dsu.findSet(node3);
- assertEquals(root, node1);
- assertEquals(node1, node3.parent);
- assertEquals(3, root.size);
- }
-
- @Test
- public void testMultipleDisjointSets() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
- DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
- DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
- DisjointSetUnionBySize.Node node4 = dsu.makeSet(4);
- DisjointSetUnionBySize.Node node5 = dsu.makeSet(5);
- DisjointSetUnionBySize.Node node6 = dsu.makeSet(6);
-
- // Create two separate components
- dsu.unionSets(node1, node2);
- dsu.unionSets(node2, node3);
-
- dsu.unionSets(node4, node5);
- dsu.unionSets(node5, node6);
-
- // Verify they are separate
- assertEquals(dsu.findSet(node1), dsu.findSet(node2));
- assertEquals(dsu.findSet(node2), dsu.findSet(node3));
- assertEquals(dsu.findSet(node4), dsu.findSet(node5));
- assertEquals(dsu.findSet(node5), dsu.findSet(node6));
-
- assertNotEquals(dsu.findSet(node1), dsu.findSet(node4));
- assertNotEquals(dsu.findSet(node3), dsu.findSet(node6));
- }
-
- @Test
- public void testEmptyValues() {
- DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
- DisjointSetUnionBySize.Node emptyNode = dsu.makeSet("");
- DisjointSetUnionBySize.Node nullNode = dsu.makeSet(null);
-
- assertEquals(emptyNode, dsu.findSet(emptyNode));
- assertEquals(nullNode, dsu.findSet(nullNode));
-
- dsu.unionSets(emptyNode, nullNode);
- assertEquals(dsu.findSet(emptyNode), dsu.findSet(nullNode));
- }
-}
+package com.thealgorithms.datastructures.disjointsetunion;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.Test;
+
+public class DisjointSetUnionBySizeTest {
+
+ @Test
+ public void testMakeSet() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node = dsu.makeSet(1);
+ assertNotNull(node);
+ assertEquals(node, node.parent);
+ assertEquals(1, node.size);
+ }
+
+ @Test
+ public void testUnionFindSet() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
+ DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
+ DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
+ DisjointSetUnionBySize.Node node4 = dsu.makeSet(4);
+
+ dsu.unionSets(node1, node2);
+ dsu.unionSets(node3, node2);
+ dsu.unionSets(node3, node4);
+ dsu.unionSets(node1, node3);
+
+ DisjointSetUnionBySize.Node root1 = dsu.findSet(node1);
+ DisjointSetUnionBySize.Node root2 = dsu.findSet(node2);
+ DisjointSetUnionBySize.Node root3 = dsu.findSet(node3);
+ DisjointSetUnionBySize.Node root4 = dsu.findSet(node4);
+
+ assertEquals(root1, root2);
+ assertEquals(root1, root3);
+ assertEquals(root1, root4);
+ assertEquals(4, root1.size);
+ }
+
+ @Test
+ public void testFindSetOnSingleNode() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node = dsu.makeSet("A");
+ assertEquals(node, dsu.findSet(node));
+ }
+
+ @Test
+ public void testUnionAlreadyConnectedNodes() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
+ DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
+ DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
+
+ dsu.unionSets(node1, node2);
+ dsu.unionSets(node2, node3);
+
+ // Union nodes that are already connected
+ dsu.unionSets(node1, node3);
+
+ // All should have the same root
+ DisjointSetUnionBySize.Node root = dsu.findSet(node1);
+ assertEquals(root, dsu.findSet(node2));
+ assertEquals(root, dsu.findSet(node3));
+ assertEquals(3, root.size);
+ }
+
+ @Test
+ public void testMultipleMakeSets() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
+ DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
+ DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
+
+ assertNotEquals(node1, node2);
+ assertNotEquals(node2, node3);
+ assertNotEquals(node1, node3);
+
+ assertEquals(node1, node1.parent);
+ assertEquals(node2, node2.parent);
+ assertEquals(node3, node3.parent);
+ assertEquals(1, node1.size);
+ assertEquals(1, node2.size);
+ assertEquals(1, node3.size);
+ }
+
+ @Test
+ public void testPathCompression() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
+ DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
+ DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
+
+ dsu.unionSets(node1, node2);
+ dsu.unionSets(node2, node3);
+
+ // After findSet, path compression should update parent to root directly
+ DisjointSetUnionBySize.Node root = dsu.findSet(node3);
+ assertEquals(root, node1);
+ assertEquals(node1, node3.parent);
+ assertEquals(3, root.size);
+ }
+
+ @Test
+ public void testMultipleDisjointSets() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node node1 = dsu.makeSet(1);
+ DisjointSetUnionBySize.Node node2 = dsu.makeSet(2);
+ DisjointSetUnionBySize.Node node3 = dsu.makeSet(3);
+ DisjointSetUnionBySize.Node node4 = dsu.makeSet(4);
+ DisjointSetUnionBySize.Node node5 = dsu.makeSet(5);
+ DisjointSetUnionBySize.Node node6 = dsu.makeSet(6);
+
+ // Create two separate components
+ dsu.unionSets(node1, node2);
+ dsu.unionSets(node2, node3);
+
+ dsu.unionSets(node4, node5);
+ dsu.unionSets(node5, node6);
+
+ // Verify they are separate
+ assertEquals(dsu.findSet(node1), dsu.findSet(node2));
+ assertEquals(dsu.findSet(node2), dsu.findSet(node3));
+ assertEquals(dsu.findSet(node4), dsu.findSet(node5));
+ assertEquals(dsu.findSet(node5), dsu.findSet(node6));
+
+ assertNotEquals(dsu.findSet(node1), dsu.findSet(node4));
+ assertNotEquals(dsu.findSet(node3), dsu.findSet(node6));
+ }
+
+ @Test
+ public void testEmptyValues() {
+ DisjointSetUnionBySize dsu = new DisjointSetUnionBySize<>();
+ DisjointSetUnionBySize.Node emptyNode = dsu.makeSet("");
+ DisjointSetUnionBySize.Node nullNode = dsu.makeSet(null);
+
+ assertEquals(emptyNode, dsu.findSet(emptyNode));
+ assertEquals(nullNode, dsu.findSet(nullNode));
+
+ dsu.unionSets(emptyNode, nullNode);
+ assertEquals(dsu.findSet(emptyNode), dsu.findSet(nullNode));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/CyclesTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/CyclesTest.java
new file mode 100644
index 000000000000..dfe81c9a85d2
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/CyclesTest.java
@@ -0,0 +1,81 @@
+package com.thealgorithms.datastructures.graphs;
+
+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 java.util.List;
+import org.junit.jupiter.api.Test;
+
+class CyclesTest {
+
+ @Test
+ void testTriangleCycle() {
+ // Triangle graph: 0-1, 1-2, 2-0
+ int nodes = 3;
+ int[][] matrix = {{0, 1, 1}, {1, 0, 1}, {1, 1, 0}};
+
+ Cycle c = new Cycle(nodes, matrix);
+ c.start();
+ List> cycles = c.getCycles();
+
+ // Should find at least one cycle: [0, 1, 2]
+ // Note: The algorithm modifies the matrix as it goes, so it finds elementary
+ // cycles.
+ // For a triangle, it finds 0-1-2.
+
+ assertFalse(cycles.isEmpty(), "Should detect at least one cycle");
+ // Verify the cycle content
+ boolean foundTriangle = false;
+ for (List cycle : cycles) {
+ if (cycle.size() == 3 && cycle.contains(0) && cycle.contains(1) && cycle.contains(2)) {
+ foundTriangle = true;
+ break;
+ }
+ }
+ assertTrue(foundTriangle, "Should detect the 0-1-2 triangle");
+ }
+
+ @Test
+ void testNoCycle() {
+ // Line graph: 0 -> 1 -> 2
+ int nodes = 3;
+ int[][] matrix = {{0, 1, 0}, {0, 0, 1}, {0, 0, 0}};
+
+ Cycle c = new Cycle(nodes, matrix);
+ c.start();
+ List> cycles = c.getCycles();
+
+ assertTrue(cycles.isEmpty(), "Should not detect any cycles in a line graph");
+ }
+
+ @Test
+ void testSelfLoop() {
+ // Node 0 has self loop
+ int nodes = 1;
+ int[][] matrix = {{1}};
+
+ Cycle c = new Cycle(nodes, matrix);
+ c.start();
+ List> cycles = c.getCycles();
+
+ assertFalse(cycles.isEmpty(), "Should detect self loop");
+ assertEquals(1, cycles.size());
+ assertEquals(1, cycles.get(0).size());
+ assertEquals(0, cycles.get(0).get(0));
+ }
+
+ @Test
+ void testPrintAll() {
+ int nodes = 3;
+ int[][] matrix = {{0, 1, 1}, {1, 0, 1}, {1, 1, 0}};
+ Cycle c = new Cycle(nodes, matrix);
+ c.start();
+ c.printAll(); // Ensure no exception
+ }
+
+ @Test
+ void testMain() {
+ Cycles.main(new String[] {});
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java
index faa2765a3264..aba411bb524b 100644
--- a/src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/lists/CircularDoublyLinkedListTest.java
@@ -1,120 +1,120 @@
-package com.thealgorithms.datastructures.lists;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-public class CircularDoublyLinkedListTest {
-
- private CircularDoublyLinkedList list;
-
- @BeforeEach
- public void setUp() {
- list = new CircularDoublyLinkedList<>();
- }
-
- @Test
- public void testInitialSize() {
- assertEquals(0, list.getSize(), "Initial size should be 0.");
- }
-
- @Test
- public void testAppendAndSize() {
- list.append(10);
- list.append(20);
- list.append(30);
-
- assertEquals(3, list.getSize(), "Size after appends should be 3.");
- assertEquals("[ 10, 20, 30 ]", list.toString(), "List content should match appended values.");
- }
-
- @Test
- public void testRemove() {
- list.append(10);
- list.append(20);
- list.append(30);
-
- int removed = list.remove(1);
- assertEquals(20, removed, "Removed element at index 1 should be 20.");
-
- assertEquals("[ 10, 30 ]", list.toString(), "List content should reflect removal.");
- assertEquals(2, list.getSize(), "Size after removal should be 2.");
-
- removed = list.remove(0);
- assertEquals(10, removed, "Removed element at index 0 should be 10.");
- assertEquals("[ 30 ]", list.toString(), "List content should reflect second removal.");
- assertEquals(1, list.getSize(), "Size after second removal should be 1.");
- }
-
- @Test
- public void testRemoveInvalidIndex() {
- list.append(10);
- list.append(20);
-
- assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2), "Removing at invalid index 2 should throw exception.");
- assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1), "Removing at negative index should throw exception.");
- }
-
- @Test
- public void testToStringEmpty() {
- assertEquals("[]", list.toString(), "Empty list should display as [].");
- }
-
- @Test
- public void testSingleElement() {
- list.append(10);
-
- assertEquals(1, list.getSize(), "Size after adding single element should be 1.");
- assertEquals("[ 10 ]", list.toString(), "Single element list string should be formatted correctly.");
- int removed = list.remove(0);
- assertEquals(10, removed, "Removed element should be the one appended.");
- assertEquals("[]", list.toString(), "List should be empty after removing last element.");
- assertEquals(0, list.getSize(), "Size after removing last element should be 0.");
- }
-
- @Test
- public void testNullAppend() {
- assertThrows(NullPointerException.class, () -> list.append(null), "Appending null should throw NullPointerException.");
- }
-
- @Test
- public void testRemoveLastPosition() {
- list.append(10);
- list.append(20);
- list.append(30);
- int removed = list.remove(list.getSize() - 1);
- assertEquals(30, removed, "Last element removed should be 30.");
- assertEquals(2, list.getSize(), "Size should decrease after removing last element.");
- }
-
- @Test
- public void testRemoveFromEmptyThrows() {
- assertThrows(IndexOutOfBoundsException.class, () -> list.remove(0), "Remove from empty list should throw.");
- }
-
- @Test
- public void testRepeatedAppendAndRemove() {
- for (int i = 0; i < 100; i++) {
- list.append(i);
- }
- assertEquals(100, list.getSize());
-
- for (int i = 99; i >= 0; i--) {
- int removed = list.remove(i);
- assertEquals(i, removed, "Removed element should match appended value.");
- }
- assertEquals(0, list.getSize(), "List should be empty after all removes.");
- }
-
- @Test
- public void testToStringAfterMultipleRemoves() {
- list.append(1);
- list.append(2);
- list.append(3);
- list.remove(2);
- list.remove(0);
- assertEquals("[ 2 ]", list.toString(), "ToString should correctly represent remaining elements.");
- }
-}
+package com.thealgorithms.datastructures.lists;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class CircularDoublyLinkedListTest {
+
+ private CircularDoublyLinkedList list;
+
+ @BeforeEach
+ public void setUp() {
+ list = new CircularDoublyLinkedList<>();
+ }
+
+ @Test
+ public void testInitialSize() {
+ assertEquals(0, list.getSize(), "Initial size should be 0.");
+ }
+
+ @Test
+ public void testAppendAndSize() {
+ list.append(10);
+ list.append(20);
+ list.append(30);
+
+ assertEquals(3, list.getSize(), "Size after appends should be 3.");
+ assertEquals("[ 10, 20, 30 ]", list.toString(), "List content should match appended values.");
+ }
+
+ @Test
+ public void testRemove() {
+ list.append(10);
+ list.append(20);
+ list.append(30);
+
+ int removed = list.remove(1);
+ assertEquals(20, removed, "Removed element at index 1 should be 20.");
+
+ assertEquals("[ 10, 30 ]", list.toString(), "List content should reflect removal.");
+ assertEquals(2, list.getSize(), "Size after removal should be 2.");
+
+ removed = list.remove(0);
+ assertEquals(10, removed, "Removed element at index 0 should be 10.");
+ assertEquals("[ 30 ]", list.toString(), "List content should reflect second removal.");
+ assertEquals(1, list.getSize(), "Size after second removal should be 1.");
+ }
+
+ @Test
+ public void testRemoveInvalidIndex() {
+ list.append(10);
+ list.append(20);
+
+ assertThrows(IndexOutOfBoundsException.class, () -> list.remove(2), "Removing at invalid index 2 should throw exception.");
+ assertThrows(IndexOutOfBoundsException.class, () -> list.remove(-1), "Removing at negative index should throw exception.");
+ }
+
+ @Test
+ public void testToStringEmpty() {
+ assertEquals("[]", list.toString(), "Empty list should display as [].");
+ }
+
+ @Test
+ public void testSingleElement() {
+ list.append(10);
+
+ assertEquals(1, list.getSize(), "Size after adding single element should be 1.");
+ assertEquals("[ 10 ]", list.toString(), "Single element list string should be formatted correctly.");
+ int removed = list.remove(0);
+ assertEquals(10, removed, "Removed element should be the one appended.");
+ assertEquals("[]", list.toString(), "List should be empty after removing last element.");
+ assertEquals(0, list.getSize(), "Size after removing last element should be 0.");
+ }
+
+ @Test
+ public void testNullAppend() {
+ assertThrows(NullPointerException.class, () -> list.append(null), "Appending null should throw NullPointerException.");
+ }
+
+ @Test
+ public void testRemoveLastPosition() {
+ list.append(10);
+ list.append(20);
+ list.append(30);
+ int removed = list.remove(list.getSize() - 1);
+ assertEquals(30, removed, "Last element removed should be 30.");
+ assertEquals(2, list.getSize(), "Size should decrease after removing last element.");
+ }
+
+ @Test
+ public void testRemoveFromEmptyThrows() {
+ assertThrows(IndexOutOfBoundsException.class, () -> list.remove(0), "Remove from empty list should throw.");
+ }
+
+ @Test
+ public void testRepeatedAppendAndRemove() {
+ for (int i = 0; i < 100; i++) {
+ list.append(i);
+ }
+ assertEquals(100, list.getSize());
+
+ for (int i = 99; i >= 0; i--) {
+ int removed = list.remove(i);
+ assertEquals(i, removed, "Removed element should match appended value.");
+ }
+ assertEquals(0, list.getSize(), "List should be empty after all removes.");
+ }
+
+ @Test
+ public void testToStringAfterMultipleRemoves() {
+ list.append(1);
+ list.append(2);
+ list.append(3);
+ list.remove(2);
+ list.remove(0);
+ assertEquals("[ 2 ]", list.toString(), "ToString should correctly represent remaining elements.");
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
index 049804f58b5a..100029971d8d 100755
--- a/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
@@ -1,15 +1,15 @@
-package com.thealgorithms.dynamicprogramming;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.CsvSource;
-
-public class UniqueSubsequencesCountTest {
-
- @ParameterizedTest
- @CsvSource({"abc, 7", "abcdashgdhas, 3592", "a, 1", "'a b', 7", "a1b2, 15", "AaBb, 15", "abab, 11"})
- void subseqCountParameterizedTest(String input, int expected) {
- assertEquals(expected, UniqueSubsequencesCount.countSubseq(input));
- }
-}
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+public class UniqueSubsequencesCountTest {
+
+ @ParameterizedTest
+ @CsvSource({"abc, 7", "abcdashgdhas, 3592", "a, 1", "'a b', 7", "a1b2, 15", "AaBb, 15", "abab, 11"})
+ void subseqCountParameterizedTest(String input, int expected) {
+ assertEquals(expected, UniqueSubsequencesCount.countSubseq(input));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/VampireNumberTest.java b/src/test/java/com/thealgorithms/maths/VampireNumberTest.java
index 6f331f1252cd..21976f9e57ad 100644
--- a/src/test/java/com/thealgorithms/maths/VampireNumberTest.java
+++ b/src/test/java/com/thealgorithms/maths/VampireNumberTest.java
@@ -1,32 +1,32 @@
-package com.thealgorithms.maths;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-class VampireNumberTest {
- @Test
- void areVampireNumbers() {
- Assertions.assertTrue(VampireNumber.isVampireNumber(15, 93, true));
- Assertions.assertTrue(VampireNumber.isVampireNumber(135, 801, true));
- Assertions.assertTrue(VampireNumber.isVampireNumber(201, 600, true));
- }
-
- @Test
- void arePseudoVampireNumbers() {
- Assertions.assertTrue(VampireNumber.isVampireNumber(150, 93, false));
- Assertions.assertTrue(VampireNumber.isVampireNumber(546, 84, false));
- Assertions.assertTrue(VampireNumber.isVampireNumber(641, 65, false));
- }
-
- @Test
- void areNotVampireNumbers() {
- Assertions.assertFalse(VampireNumber.isVampireNumber(51, 39, false));
- Assertions.assertFalse(VampireNumber.isVampireNumber(51, 39, true));
- }
-
- @Test
- void testSplitIntoSortedDigits() {
- Assertions.assertEquals("123", VampireNumber.splitIntoSortedDigits(321));
- Assertions.assertEquals("02234", VampireNumber.splitIntoSortedDigits(20, 324));
- }
-}
+package com.thealgorithms.maths;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class VampireNumberTest {
+ @Test
+ void areVampireNumbers() {
+ Assertions.assertTrue(VampireNumber.isVampireNumber(15, 93, true));
+ Assertions.assertTrue(VampireNumber.isVampireNumber(135, 801, true));
+ Assertions.assertTrue(VampireNumber.isVampireNumber(201, 600, true));
+ }
+
+ @Test
+ void arePseudoVampireNumbers() {
+ Assertions.assertTrue(VampireNumber.isVampireNumber(150, 93, false));
+ Assertions.assertTrue(VampireNumber.isVampireNumber(546, 84, false));
+ Assertions.assertTrue(VampireNumber.isVampireNumber(641, 65, false));
+ }
+
+ @Test
+ void areNotVampireNumbers() {
+ Assertions.assertFalse(VampireNumber.isVampireNumber(51, 39, false));
+ Assertions.assertFalse(VampireNumber.isVampireNumber(51, 39, true));
+ }
+
+ @Test
+ void testSplitIntoSortedDigits() {
+ Assertions.assertEquals("123", VampireNumber.splitIntoSortedDigits(321));
+ Assertions.assertEquals("02234", VampireNumber.splitIntoSortedDigits(20, 324));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/others/IterativeFloodFillTest.java b/src/test/java/com/thealgorithms/others/IterativeFloodFillTest.java
index 560f1df68e81..b86e154ad0d0 100644
--- a/src/test/java/com/thealgorithms/others/IterativeFloodFillTest.java
+++ b/src/test/java/com/thealgorithms/others/IterativeFloodFillTest.java
@@ -1,163 +1,163 @@
-package com.thealgorithms.others;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
-
-import org.junit.jupiter.api.Test;
-
-class IterativeFloodFillTest {
-
- @Test
- void testForEmptyImage() {
- int[][] image = {};
- int[][] expected = {};
-
- IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForSingleElementImage() {
- int[][] image = {{1}};
- int[][] expected = {{3}};
-
- IterativeFloodFill.floodFill(image, 0, 0, 3, 1);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForEmptyRow() {
- int[][] image = {{}};
- int[][] expected = {{}};
-
- IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForImageOne() {
- int[][] image = {
- {0, 0, 0, 0, 0, 0, 0},
- {0, 3, 3, 3, 3, 0, 0},
- {0, 3, 1, 1, 5, 0, 0},
- {0, 3, 1, 1, 5, 5, 3},
- {0, 3, 5, 5, 1, 1, 3},
- {0, 0, 0, 5, 1, 1, 3},
- {0, 0, 0, 3, 3, 3, 3},
- };
-
- int[][] expected = {
- {0, 0, 0, 0, 0, 0, 0},
- {0, 3, 3, 3, 3, 0, 0},
- {0, 3, 2, 2, 5, 0, 0},
- {0, 3, 2, 2, 5, 5, 3},
- {0, 3, 5, 5, 2, 2, 3},
- {0, 0, 0, 5, 2, 2, 3},
- {0, 0, 0, 3, 3, 3, 3},
- };
-
- IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForImageTwo() {
- int[][] image = {
- {0, 0, 1, 1, 0, 0, 0},
- {1, 1, 3, 3, 3, 0, 0},
- {1, 3, 1, 1, 5, 0, 0},
- {0, 3, 1, 1, 5, 5, 3},
- {0, 3, 5, 5, 1, 1, 3},
- {0, 0, 0, 5, 1, 1, 3},
- {0, 0, 0, 1, 3, 1, 3},
- };
-
- int[][] expected = {
- {0, 0, 2, 2, 0, 0, 0},
- {2, 2, 3, 3, 3, 0, 0},
- {2, 3, 2, 2, 5, 0, 0},
- {0, 3, 2, 2, 5, 5, 3},
- {0, 3, 5, 5, 2, 2, 3},
- {0, 0, 0, 5, 2, 2, 3},
- {0, 0, 0, 2, 3, 2, 3},
- };
-
- IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForImageThree() {
- int[][] image = {
- {1, 1, 2, 3, 1, 1, 1},
- {1, 0, 0, 1, 0, 0, 1},
- {1, 1, 1, 0, 3, 1, 2},
- };
-
- int[][] expected = {
- {4, 4, 2, 3, 4, 4, 4},
- {4, 0, 0, 4, 0, 0, 4},
- {4, 4, 4, 0, 3, 4, 2},
- };
-
- IterativeFloodFill.floodFill(image, 0, 1, 4, 1);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForSameNewAndOldColor() {
- int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- IterativeFloodFill.floodFill(image, 0, 1, 1, 1);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForBigImage() {
- int[][] image = new int[100][100];
-
- assertDoesNotThrow(() -> IterativeFloodFill.floodFill(image, 0, 0, 1, 0));
- }
-
- @Test
- void testForBelowZeroX() {
- int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- IterativeFloodFill.floodFill(image, -1, 1, 1, 0);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForBelowZeroY() {
- int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- IterativeFloodFill.floodFill(image, 1, -1, 1, 0);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForAboveBoundaryX() {
- int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- IterativeFloodFill.floodFill(image, 100, 1, 1, 0);
- assertArrayEquals(expected, image);
- }
-
- @Test
- void testForAboveBoundaryY() {
- int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
-
- IterativeFloodFill.floodFill(image, 1, 100, 1, 0);
- assertArrayEquals(expected, image);
- }
-}
+package com.thealgorithms.others;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+import org.junit.jupiter.api.Test;
+
+class IterativeFloodFillTest {
+
+ @Test
+ void testForEmptyImage() {
+ int[][] image = {};
+ int[][] expected = {};
+
+ IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForSingleElementImage() {
+ int[][] image = {{1}};
+ int[][] expected = {{3}};
+
+ IterativeFloodFill.floodFill(image, 0, 0, 3, 1);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForEmptyRow() {
+ int[][] image = {{}};
+ int[][] expected = {{}};
+
+ IterativeFloodFill.floodFill(image, 4, 5, 3, 2);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForImageOne() {
+ int[][] image = {
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 3, 3, 3, 3, 0, 0},
+ {0, 3, 1, 1, 5, 0, 0},
+ {0, 3, 1, 1, 5, 5, 3},
+ {0, 3, 5, 5, 1, 1, 3},
+ {0, 0, 0, 5, 1, 1, 3},
+ {0, 0, 0, 3, 3, 3, 3},
+ };
+
+ int[][] expected = {
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 3, 3, 3, 3, 0, 0},
+ {0, 3, 2, 2, 5, 0, 0},
+ {0, 3, 2, 2, 5, 5, 3},
+ {0, 3, 5, 5, 2, 2, 3},
+ {0, 0, 0, 5, 2, 2, 3},
+ {0, 0, 0, 3, 3, 3, 3},
+ };
+
+ IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForImageTwo() {
+ int[][] image = {
+ {0, 0, 1, 1, 0, 0, 0},
+ {1, 1, 3, 3, 3, 0, 0},
+ {1, 3, 1, 1, 5, 0, 0},
+ {0, 3, 1, 1, 5, 5, 3},
+ {0, 3, 5, 5, 1, 1, 3},
+ {0, 0, 0, 5, 1, 1, 3},
+ {0, 0, 0, 1, 3, 1, 3},
+ };
+
+ int[][] expected = {
+ {0, 0, 2, 2, 0, 0, 0},
+ {2, 2, 3, 3, 3, 0, 0},
+ {2, 3, 2, 2, 5, 0, 0},
+ {0, 3, 2, 2, 5, 5, 3},
+ {0, 3, 5, 5, 2, 2, 3},
+ {0, 0, 0, 5, 2, 2, 3},
+ {0, 0, 0, 2, 3, 2, 3},
+ };
+
+ IterativeFloodFill.floodFill(image, 2, 2, 2, 1);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForImageThree() {
+ int[][] image = {
+ {1, 1, 2, 3, 1, 1, 1},
+ {1, 0, 0, 1, 0, 0, 1},
+ {1, 1, 1, 0, 3, 1, 2},
+ };
+
+ int[][] expected = {
+ {4, 4, 2, 3, 4, 4, 4},
+ {4, 0, 0, 4, 0, 0, 4},
+ {4, 4, 4, 0, 3, 4, 2},
+ };
+
+ IterativeFloodFill.floodFill(image, 0, 1, 4, 1);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForSameNewAndOldColor() {
+ int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ IterativeFloodFill.floodFill(image, 0, 1, 1, 1);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForBigImage() {
+ int[][] image = new int[100][100];
+
+ assertDoesNotThrow(() -> IterativeFloodFill.floodFill(image, 0, 0, 1, 0));
+ }
+
+ @Test
+ void testForBelowZeroX() {
+ int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ IterativeFloodFill.floodFill(image, -1, 1, 1, 0);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForBelowZeroY() {
+ int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ IterativeFloodFill.floodFill(image, 1, -1, 1, 0);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForAboveBoundaryX() {
+ int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ IterativeFloodFill.floodFill(image, 100, 1, 1, 0);
+ assertArrayEquals(expected, image);
+ }
+
+ @Test
+ void testForAboveBoundaryY() {
+ int[][] image = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ int[][] expected = {{1, 1, 2}, {1, 0, 0}, {1, 1, 1}};
+
+ IterativeFloodFill.floodFill(image, 1, 100, 1, 0);
+ assertArrayEquals(expected, image);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java b/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java
index a56f79670cf3..8fc538be2cf0 100644
--- a/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java
+++ b/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java
@@ -1,25 +1,25 @@
-package com.thealgorithms.searches;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-
-import org.junit.jupiter.api.Test;
-
-public class TestSearchInARowAndColWiseSortedMatrix {
- @Test
- public void searchItem() {
- int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}};
- var test = new SearchInARowAndColWiseSortedMatrix();
- int[] res = test.search(matrix, 16);
- int[] expectedResult = {2, 2};
- assertArrayEquals(expectedResult, res);
- }
-
- @Test
- public void notFound() {
- int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}};
- var test = new SearchInARowAndColWiseSortedMatrix();
- int[] res = test.search(matrix, 96);
- int[] expectedResult = {-1, -1};
- assertArrayEquals(expectedResult, res);
- }
-}
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class TestSearchInARowAndColWiseSortedMatrix {
+ @Test
+ public void searchItem() {
+ int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}};
+ var test = new SearchInARowAndColWiseSortedMatrix();
+ int[] res = test.search(matrix, 16);
+ int[] expectedResult = {2, 2};
+ assertArrayEquals(expectedResult, res);
+ }
+
+ @Test
+ public void notFound() {
+ int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}};
+ var test = new SearchInARowAndColWiseSortedMatrix();
+ int[] res = test.search(matrix, 96);
+ int[] expectedResult = {-1, -1};
+ assertArrayEquals(expectedResult, res);
+ }
+}