diff --git a/DIRECTORY.md b/DIRECTORY.md
index deaf59636fa4..6d945ac16c3d 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -43,7 +43,6 @@
- π [FirstDifferentBit](src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java)
- π [GenerateSubsets](src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java)
- π [GrayCodeConversion](src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java)
- - π [HammingDistance](src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java)
- π [HigherLowerPowerOfTwo](src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java)
- π [HighestSetBit](src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
- π [IndexOfRightMostSetBit](src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
@@ -346,7 +345,6 @@
- π [LongestIncreasingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequence.java)
- π [LongestIncreasingSubsequenceNLogN](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java)
- π [LongestPalindromicSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubsequence.java)
- - π [LongestPalindromicSubstring](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java)
- π [LongestValidParentheses](src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java)
- π [MatrixChainMultiplication](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java)
- π [MatrixChainRecursiveTopDownMemoisation](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java)
@@ -406,7 +404,7 @@
- π [ActivitySelection](src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java)
- π [BandwidthAllocation](src/main/java/com/thealgorithms/greedyalgorithms/BandwidthAllocation.java)
- π [BinaryAddition](src/main/java/com/thealgorithms/greedyalgorithms/BinaryAddition.java)
- - π [CoinChange](src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java)
+ - π [GreedyCoinChange](src/main/java/com/thealgorithms/greedyalgorithms/GreedyCoinChange.java)
- π [DigitSeparation](src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java)
- π [EgyptianFraction](src/main/java/com/thealgorithms/greedyalgorithms/EgyptianFraction.java)
- π [FractionalKnapsack](src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java)
@@ -595,7 +593,7 @@
- π [ArrayRightRotation](src/main/java/com/thealgorithms/others/ArrayRightRotation.java)
- π [BFPRT](src/main/java/com/thealgorithms/others/BFPRT.java)
- π [BankersAlgorithm](src/main/java/com/thealgorithms/others/BankersAlgorithm.java)
- - π [BoyerMoore](src/main/java/com/thealgorithms/others/BoyerMoore.java)
+ - π [BoyerMooreMajorityVote](src/main/java/com/thealgorithms/others/BoyerMooreMajorityVote.java)
- π [BrianKernighanAlgorithm](src/main/java/com/thealgorithms/others/BrianKernighanAlgorithm.java)
- π [CRC16](src/main/java/com/thealgorithms/others/CRC16.java)
- π [CRC32](src/main/java/com/thealgorithms/others/CRC32.java)
@@ -627,7 +625,6 @@
- π [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java)
- π [Verhoeff](src/main/java/com/thealgorithms/others/Verhoeff.java)
- π **cn**
- - π [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java)
- π **physics**
- π [CoulombsLaw](src/main/java/com/thealgorithms/physics/CoulombsLaw.java)
- π [DampedOscillator](src/main/java/com/thealgorithms/physics/DampedOscillator.java)
@@ -834,7 +831,6 @@
- π [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java)
- π [SuffixArray](src/main/java/com/thealgorithms/strings/SuffixArray.java)
- π [Upper](src/main/java/com/thealgorithms/strings/Upper.java)
- - π [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java)
- π [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java)
- π [ZAlgorithm](src/main/java/com/thealgorithms/strings/ZAlgorithm.java)
- π **zigZagPattern**
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
deleted file mode 100644
index 4c24909ef234..000000000000
--- a/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.thealgorithms.bitmanipulation;
-
-/**
- * The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
- * Given two integers x and y, calculate the Hamming distance.
- * Example:
- * Input: x = 1, y = 4
- * Output: 2
- * Explanation: 1 (0001) and 4 (0100) have 2 differing bits.
- *
- * @author Hardvan
- */
-public final class HammingDistance {
- private HammingDistance() {
- }
-
- /**
- * Calculates the Hamming distance between two integers.
- * The Hamming distance is the number of differing bits between the two integers.
- *
- * @param x The first integer.
- * @param y The second integer.
- * @return The Hamming distance (number of differing bits).
- */
- public static int hammingDistance(int x, int y) {
- int xor = x ^ y;
- return Integer.bitCount(xor);
- }
-}
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java
deleted file mode 100644
index 8a4ab2f526a9..000000000000
--- a/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.thealgorithms.dynamicprogramming;
-
-/**
- * Class for finding the longest palindromic substring within a given string.
- *
- * A palindromic substring is a sequence of characters that reads the same backward as forward.
- * This class uses a dynamic programming approach to efficiently find the longest palindromic substring.
- *
- */
-public final class LongestPalindromicSubstring {
- private LongestPalindromicSubstring() {
- }
-
- public static String lps(String input) {
- if (input == null || input.isEmpty()) {
- return input;
- }
- boolean[][] arr = new boolean[input.length()][input.length()];
- int start = 0;
- int end = 0;
- for (int g = 0; g < input.length(); g++) {
- for (int i = 0, j = g; j < input.length(); i++, j++) {
- if (g == 0) {
- arr[i][j] = true;
- } else if (g == 1) {
- arr[i][j] = input.charAt(i) == input.charAt(j);
- } else {
- arr[i][j] = input.charAt(i) == input.charAt(j) && arr[i + 1][j - 1];
- }
-
- if (arr[i][j]) {
- start = i;
- end = j;
- }
- }
- }
- return input.substring(start, end + 1);
- }
-}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java b/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java
deleted file mode 100644
index 8054581d21d7..000000000000
--- a/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.thealgorithms.greedyalgorithms;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-
-// Problem Link : https://en.wikipedia.org/wiki/Change-making_problem
-
-public final class CoinChange {
- private CoinChange() {
- }
- // Function to solve the coin change problem
- public static ArrayList coinChangeProblem(int amount) {
- // Define an array of coin denominations in descending order
- Integer[] coins = {1, 2, 5, 10, 20, 50, 100, 500, 2000};
-
- // Sort the coin denominations in descending order
- Arrays.sort(coins, Comparator.reverseOrder());
-
- ArrayList ans = new ArrayList<>(); // List to store selected coins
-
- // Iterate through the coin denominations
- for (int i = 0; i < coins.length; i++) {
- // Check if the current coin denomination can be used to reduce the remaining amount
- if (coins[i] <= amount) {
- // Repeatedly subtract the coin denomination from the remaining amount
- while (coins[i] <= amount) {
- ans.add(coins[i]); // Add the coin to the list of selected coins
- amount -= coins[i]; // Update the remaining amount
- }
- }
- }
- return ans;
- }
-}
diff --git a/src/main/java/com/thealgorithms/greedyalgorithms/GreedyCoinChange.java b/src/main/java/com/thealgorithms/greedyalgorithms/GreedyCoinChange.java
new file mode 100644
index 000000000000..4aa4153fe226
--- /dev/null
+++ b/src/main/java/com/thealgorithms/greedyalgorithms/GreedyCoinChange.java
@@ -0,0 +1,43 @@
+package com.thealgorithms.greedyalgorithms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Greedy coin change (renamed for clarity).
+ *
+ * Resolves naming conflict: "CoinChange" exists in both dynamicprogramming (DP: count combinations,
+ * minimum coins) and greedyalgorithms. This class is the greedy approach using fixed denominations.
+ *
+ *
Returns a list of coins that sum to the given amount using a greedy strategy with
+ * standard denominations (1, 2, 5, 10, 20, 50, 100, 500, 2000).
+ *
+ * @see Change-making problem
+ */
+public final class GreedyCoinChange {
+ private GreedyCoinChange() {
+ }
+
+ /**
+ * Returns a list of coins (in descending order of use) that sum to the given amount.
+ * Uses greedy selection with fixed denominations.
+ *
+ * @param amount the target amount
+ * @return list of coin values that sum to amount (may be empty if amount is 0)
+ */
+ public static ArrayList coinChangeProblem(int amount) {
+ Integer[] coins = {1, 2, 5, 10, 20, 50, 100, 500, 2000};
+ Arrays.sort(coins, Comparator.reverseOrder());
+
+ ArrayList ans = new ArrayList<>();
+
+ for (Integer coin : coins) {
+ while (coin <= amount) {
+ ans.add(coin);
+ amount -= coin;
+ }
+ }
+ return ans;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/others/BoyerMoore.java b/src/main/java/com/thealgorithms/others/BoyerMooreMajorityVote.java
similarity index 53%
rename from src/main/java/com/thealgorithms/others/BoyerMoore.java
rename to src/main/java/com/thealgorithms/others/BoyerMooreMajorityVote.java
index 3fb97724b5ac..7ad6889fd8ba 100644
--- a/src/main/java/com/thealgorithms/others/BoyerMoore.java
+++ b/src/main/java/com/thealgorithms/others/BoyerMooreMajorityVote.java
@@ -1,16 +1,19 @@
package com.thealgorithms.others;
+
import java.util.Optional;
/**
- * Utility class implementing Boyer-Moore's Voting Algorithm to find the majority element
- * in an array. The majority element is defined as the element that appears more than n/2 times
- * in the array, where n is the length of the array.
+ * Boyer-Moore Majority Vote Algorithm (renamed for clarity).
+ *
+ * Resolves naming conflict: "BoyerMoore" in others referred to the majority vote algorithm,
+ * while searches.BoyerMoore is the string-search algorithm. This class is the majority-vote implementation.
*
- * For more information on the algorithm, refer to:
- * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm
+ *
Finds the majority element in an array (element that appears more than n/2 times).
+ *
+ * @see BoyerβMoore majority vote algorithm
*/
-public final class BoyerMoore {
- private BoyerMoore() {
+public final class BoyerMooreMajorityVote {
+ private BoyerMooreMajorityVote() {
}
/**
@@ -33,12 +36,6 @@ public static Optional findMajorityElement(int[] array) {
return Optional.empty();
}
- /**
- * Identifies the potential majority candidate using Boyer-Moore's Voting Algorithm.
- *
- * @param array the input array
- * @return the candidate for the majority element
- */
private static int findCandidate(final int[] array) {
int count = 0;
int candidate = -1;
@@ -51,13 +48,6 @@ private static int findCandidate(final int[] array) {
return candidate;
}
- /**
- * Counts the occurrences of the candidate element in the array.
- *
- * @param candidate the candidate element
- * @param array the input array
- * @return the number of times the candidate appears in the array
- */
private static int countOccurrences(final int candidate, final int[] array) {
int count = 0;
for (int value : array) {
@@ -68,13 +58,6 @@ private static int countOccurrences(final int candidate, final int[] array) {
return count;
}
- /**
- * Determines if the count of the candidate element is more than n/2, where n is the length of the array.
- *
- * @param count the number of occurrences of the candidate
- * @param totalCount the total number of elements in the array
- * @return true if the candidate is the majority element, false otherwise
- */
private static boolean isMajority(int count, int totalCount) {
return 2 * count > totalCount;
}
diff --git a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java b/src/main/java/com/thealgorithms/others/cn/HammingDistance.java
deleted file mode 100644
index c8239d53d606..000000000000
--- a/src/main/java/com/thealgorithms/others/cn/HammingDistance.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.thealgorithms.others.cn;
-
-public final class HammingDistance {
- private HammingDistance() {
- }
-
- private static void checkChar(char inChar) {
- if (inChar != '0' && inChar != '1') {
- throw new IllegalArgumentException("Input must be a binary string.");
- }
- }
-
- public static int compute(char charA, char charB) {
- checkChar(charA);
- checkChar(charB);
- return charA == charB ? 0 : 1;
- }
-
- public static int compute(String bitsStrA, String bitsStrB) {
- if (bitsStrA.length() != bitsStrB.length()) {
- throw new IllegalArgumentException("Input strings must have the same length.");
- }
-
- int totalErrorBitCount = 0;
-
- for (int i = 0; i < bitsStrA.length(); i++) {
- totalErrorBitCount += compute(bitsStrA.charAt(i), bitsStrB.charAt(i));
- }
-
- return totalErrorBitCount;
- }
-}
diff --git a/src/main/java/com/thealgorithms/stacks/ValidParentheses.java b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java
index 2cc616a38826..306852991a39 100644
--- a/src/main/java/com/thealgorithms/stacks/ValidParentheses.java
+++ b/src/main/java/com/thealgorithms/stacks/ValidParentheses.java
@@ -1,32 +1,26 @@
package com.thealgorithms.stacks;
-import java.util.HashMap;
+import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.Map;
-import java.util.Stack;
/**
- * Valid Parentheses Problem
+ * Valid Parentheses Problem (consolidated implementation).
*
- * Given a string containing just the characters '(', ')', '{', '}', '[' and ']',
- * determine if the input string is valid.
- *
- * An input string is valid if:
- * 1. Open brackets must be closed by the same type of brackets.
- * 2. Open brackets must be closed in the correct order.
- * 3. Every close bracket has a corresponding open bracket of the same type.
- *
- * Examples:
- * Input: "()"
- * Output: true
+ * Resolves duplicate implementations: single stack-based solution for validating
+ * matching parentheses. Previously duplicated in strings and stacks packages.
*
- * Input: "()[]{}"
- * Output: true
+ *
Given a string containing just the characters '(', ')', '{', '}', '[' and ']',
+ * determine if the input string is valid.
*
- * Input: "(]"
- * Output: false
+ *
An input string is valid if:
+ *
+ * - Open brackets are closed by the same type of brackets.
+ * - Open brackets are closed in the correct order.
+ * - Every closing bracket has a corresponding open bracket of the same type.
+ *
*
- * Input: "([)]"
- * Output: false
+ * Examples: "()" β true, "()[]{}" β true, "(]" β false, "([)]" β false.
*
* @author Gokul45-45
*/
@@ -34,41 +28,37 @@ public final class ValidParentheses {
private ValidParentheses() {
}
+ // Map closing bracket to opening bracket for stack matching
+ private static final Map CLOSE_TO_OPEN = Map.of(')', '(', '}', '{', ']', '[');
+ private static final Map OPEN_TO_CLOSE = Map.of('(', ')', '{', '}', '[', ']');
+
/**
- * Checks if the given string has valid parentheses
+ * Checks if the given string has valid matching parentheses using a stack.
+ * Only the six bracket characters are allowed; any other character makes the string invalid.
*
- * @param s the input string containing parentheses
- * @return true if valid, false otherwise
+ * @param s the input string (only bracket characters allowed)
+ * @return true if valid, false if null, odd length, contains non-bracket chars, or mismatched
*/
public static boolean isValid(String s) {
if (s == null || s.length() % 2 != 0) {
return false;
}
- Map parenthesesMap = new HashMap<>();
- parenthesesMap.put('(', ')');
- parenthesesMap.put('{', '}');
- parenthesesMap.put('[', ']');
-
- Stack stack = new Stack<>();
+ Deque stack = new ArrayDeque<>();
for (char c : s.toCharArray()) {
- if (parenthesesMap.containsKey(c)) {
- // Opening bracket - push to stack
+ if (OPEN_TO_CLOSE.containsKey(c)) {
stack.push(c);
- } else {
- // Closing bracket - check if it matches
- if (stack.isEmpty()) {
- return false;
- }
- char openBracket = stack.pop();
- if (parenthesesMap.get(openBracket) != c) {
+ } else if (CLOSE_TO_OPEN.containsKey(c)) {
+ if (stack.isEmpty() || stack.pop() != CLOSE_TO_OPEN.get(c)) {
return false;
}
+ } else {
+ // Non-bracket character
+ return false;
}
}
- // Stack should be empty if all brackets are matched
return stack.isEmpty();
}
}
diff --git a/src/main/java/com/thealgorithms/strings/HammingDistance.java b/src/main/java/com/thealgorithms/strings/HammingDistance.java
index 235e317d94f1..d135b3f72505 100644
--- a/src/main/java/com/thealgorithms/strings/HammingDistance.java
+++ b/src/main/java/com/thealgorithms/strings/HammingDistance.java
@@ -1,11 +1,13 @@
package com.thealgorithms.strings;
/**
- * Class for calculating the Hamming distance between two strings of equal length.
- *
- * The Hamming distance is the number of positions at which the corresponding symbols are different.
- * It is used in information theory, coding theory, and computer science.
- *
+ * Hamming distance (consolidated implementation).
+ *
+ * Resolves duplicate implementations: single class for Hamming distance over strings,
+ * integers, and binary strings. Previously duplicated in strings, bitmanipulation, and others.cn.
+ *
+ *
The Hamming distance is the number of positions at which the corresponding symbols differ.
+ *
* @see Hamming distance - Wikipedia
*/
public final class HammingDistance {
@@ -14,27 +16,20 @@ private HammingDistance() {
/**
* Calculates the Hamming distance between two strings of equal length.
- *
- * The Hamming distance is defined only for strings of equal length. If the strings are not
- * of equal length, this method throws an {@code IllegalArgumentException}.
- *
*
* @param s1 the first string
* @param s2 the second string
- * @return the Hamming distance between the two strings
- * @throws IllegalArgumentException if the lengths of {@code s1} and {@code s2} are not equal
+ * @return the number of positions where the characters differ
+ * @throws IllegalArgumentException if either string is null or lengths differ
*/
public static int calculateHammingDistance(String s1, String s2) {
if (s1 == null || s2 == null) {
throw new IllegalArgumentException("Strings must not be null");
}
-
if (s1.length() != s2.length()) {
throw new IllegalArgumentException("String lengths must be equal");
}
-
int distance = 0;
-
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) != s2.charAt(i)) {
distance++;
@@ -42,4 +37,47 @@ public static int calculateHammingDistance(String s1, String s2) {
}
return distance;
}
+
+ /**
+ * Calculates the Hamming distance between two integers (number of differing bits).
+ *
+ * @param x the first integer
+ * @param y the second integer
+ * @return the number of bit positions where the two integers differ
+ */
+ public static int hammingDistance(int x, int y) {
+ return Integer.bitCount(x ^ y);
+ }
+
+ /**
+ * Computes the Hamming distance between two binary strings (only '0' and '1' allowed).
+ *
+ * @param bitsStrA first binary string
+ * @param bitsStrB second binary string (must have same length as bitsStrA)
+ * @return the number of positions where the two binary strings differ
+ * @throws IllegalArgumentException if lengths differ or any character is not '0' or '1'
+ */
+ public static int computeBinary(String bitsStrA, String bitsStrB) {
+ if (bitsStrA == null || bitsStrB == null) {
+ throw new IllegalArgumentException("Input strings must not be null");
+ }
+ if (bitsStrA.length() != bitsStrB.length()) {
+ throw new IllegalArgumentException("Input strings must have the same length.");
+ }
+ int distance = 0;
+ for (int i = 0; i < bitsStrA.length(); i++) {
+ char a = bitsStrA.charAt(i);
+ char b = bitsStrB.charAt(i);
+ if (a != '0' && a != '1') {
+ throw new IllegalArgumentException("Input must be a binary string.");
+ }
+ if (b != '0' && b != '1') {
+ throw new IllegalArgumentException("Input must be a binary string.");
+ }
+ if (a != b) {
+ distance++;
+ }
+ }
+ return distance;
+ }
}
diff --git a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java b/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
index ca500357ba77..14bce4693782 100644
--- a/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
+++ b/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java
@@ -1,14 +1,26 @@
package com.thealgorithms.strings;
-final class LongestPalindromicSubstring {
+/**
+ * Longest Palindromic Substring (consolidated implementation).
+ *
+ * Resolves duplicate implementations: single class providing both a brute-force and a
+ * dynamic-programming solution. Previously duplicated in strings and dynamicprogramming packages.
+ *
+ *
A palindromic substring reads the same backward as forward. This class offers:
+ *
+ * - {@link #longestPalindrome(String)} β brute-force check of all substrings (O(n^2) substrings, O(n) each).
+ * - {@link #lps(String)} β DP table over gap length (O(n^2) time and space).
+ *
+ */
+public final class LongestPalindromicSubstring {
private LongestPalindromicSubstring() {
}
/**
- * Finds the longest palindromic substring in the given string.
+ * Finds the longest palindromic substring using brute force (check every substring).
*
* @param s the input string
- * @return the longest palindromic substring
+ * @return the longest palindromic substring, or "" if null or empty
*/
public static String longestPalindrome(String s) {
if (s == null || s.isEmpty()) {
@@ -17,7 +29,7 @@ public static String longestPalindrome(String s) {
String maxStr = "";
for (int i = 0; i < s.length(); ++i) {
for (int j = i; j < s.length(); ++j) {
- if (isValid(s, i, j) && (j - i + 1 > maxStr.length())) {
+ if (isPalindrome(s, i, j) && (j - i + 1 > maxStr.length())) {
maxStr = s.substring(i, j + 1);
}
}
@@ -25,9 +37,44 @@ public static String longestPalindrome(String s) {
return maxStr;
}
- private static boolean isValid(String s, int lo, int hi) {
- int n = hi - lo + 1;
- for (int i = 0; i < n / 2; ++i) {
+ /**
+ * Finds the longest palindromic substring using dynamic programming.
+ * Fills a table for all substring lengths; returns the longest palindrome found.
+ *
+ * @param input the input string
+ * @return the longest palindromic substring, or the input if null/empty
+ */
+ public static String lps(String input) {
+ if (input == null || input.isEmpty()) {
+ return input;
+ }
+ int n = input.length();
+ boolean[][] dp = new boolean[n][n];
+ int start = 0;
+ int end = 0;
+
+ // g = gap (length of substring - 1); i, j = left and right indices
+ for (int g = 0; g < n; g++) {
+ for (int i = 0, j = g; j < n; i++, j++) {
+ if (g == 0) {
+ dp[i][j] = true;
+ } else if (g == 1) {
+ dp[i][j] = input.charAt(i) == input.charAt(j);
+ } else {
+ dp[i][j] = input.charAt(i) == input.charAt(j) && dp[i + 1][j - 1];
+ }
+ if (dp[i][j]) {
+ start = i;
+ end = j;
+ }
+ }
+ }
+ return input.substring(start, end + 1);
+ }
+
+ private static boolean isPalindrome(String s, int lo, int hi) {
+ int len = hi - lo + 1;
+ for (int i = 0; i < len / 2; i++) {
if (s.charAt(lo + i) != s.charAt(hi - i)) {
return false;
}
diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java
deleted file mode 100644
index 25a72f379dec..000000000000
--- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.thealgorithms.strings;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Map;
-
-/**
- * Validates if a given string has valid matching parentheses.
- *
- * A string is considered valid if:
- *
- * - Open brackets are closed by the same type of brackets.
- * - Brackets are closed in the correct order.
- * - Every closing bracket has a corresponding open bracket of the same type.
- *
- *
- * Allowed characters: '(', ')', '{', '}', '[', ']'
- */
-public final class ValidParentheses {
- private ValidParentheses() {
- }
-
- private static final Map BRACKET_PAIRS = Map.of(')', '(', '}', '{', ']', '[');
-
- /**
- * Checks if the input string has valid parentheses.
- *
- * @param s the string containing only bracket characters
- * @return true if valid, false otherwise
- * @throws IllegalArgumentException if the string contains invalid characters or is null
- */
- public static boolean isValid(String s) {
- if (s == null) {
- throw new IllegalArgumentException("Input string cannot be null");
- }
-
- Deque stack = new ArrayDeque<>();
-
- for (char c : s.toCharArray()) {
- if (BRACKET_PAIRS.containsValue(c)) {
- stack.push(c); // opening bracket
- } else if (BRACKET_PAIRS.containsKey(c)) {
- if (stack.isEmpty() || stack.pop() != BRACKET_PAIRS.get(c)) {
- return false;
- }
- } else {
- throw new IllegalArgumentException("Unexpected character: " + c);
- }
- }
-
- return stack.isEmpty();
- }
-}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java b/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
index bde39a69f190..393397c26fdc 100644
--- a/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
+++ b/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
+import com.thealgorithms.strings.HammingDistance;
import org.junit.jupiter.api.Test;
public class HammingDistanceTest {
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java
index 278de7e10e0a..230f468ac279 100644
--- a/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java
@@ -2,6 +2,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
+import com.thealgorithms.strings.LongestPalindromicSubstring;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
diff --git a/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java b/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java
index b9745be63088..465e76aef02c 100644
--- a/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java
+++ b/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java
@@ -12,49 +12,49 @@ public class CoinChangeTest {
@Test
public void testCoinChangeProblemWithValidAmount() {
ArrayList expected = new ArrayList<>(Arrays.asList(500, 50, 20, 20, 1));
- ArrayList coins = CoinChange.coinChangeProblem(591);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(591);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithLargeAmount() {
List expected = singletonList(2000);
- ArrayList coins = CoinChange.coinChangeProblem(2000);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(2000);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithPartialCoins2() {
ArrayList expected = new ArrayList<>(Arrays.asList(500, 50, 20));
- ArrayList coins = CoinChange.coinChangeProblem(570);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(570);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithSmallAmount() {
ArrayList expected = new ArrayList<>(Arrays.asList(2, 1));
- ArrayList coins = CoinChange.coinChangeProblem(3);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(3);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithLargeAmountAndMultipleDenominations() {
ArrayList expected = new ArrayList<>(Arrays.asList(2000, 2000, 2000, 2000, 500, 500, 500, 100, 100, 100, 100, 50, 20, 20, 5, 2, 2));
- ArrayList coins = CoinChange.coinChangeProblem(9999);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(9999);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithAllDenominations() {
ArrayList expected = new ArrayList<>(Arrays.asList(2000, 500, 100, 100, 100, 50, 20, 10, 5, 2, 1));
- ArrayList coins = CoinChange.coinChangeProblem(2888);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(2888);
assertEquals(expected, coins);
}
@Test
public void testCoinChangeProblemWithZeroAmount() {
ArrayList expected = new ArrayList<>();
- ArrayList coins = CoinChange.coinChangeProblem(0);
+ ArrayList coins = GreedyCoinChange.coinChangeProblem(0);
assertEquals(expected, coins);
}
}
diff --git a/src/test/java/com/thealgorithms/others/BoyerMooreTest.java b/src/test/java/com/thealgorithms/others/BoyerMooreTest.java
index 8416535b2111..cef206259f03 100644
--- a/src/test/java/com/thealgorithms/others/BoyerMooreTest.java
+++ b/src/test/java/com/thealgorithms/others/BoyerMooreTest.java
@@ -11,7 +11,7 @@ public class BoyerMooreTest {
@ParameterizedTest
@MethodSource("inputStreamWithExistingMajority")
void checkWhenMajorityExists(int expected, int[] input) {
- Assertions.assertEquals(expected, BoyerMoore.findMajorityElement(input).get());
+ Assertions.assertEquals(expected, BoyerMooreMajorityVote.findMajorityElement(input).get());
}
private static Stream inputStreamWithExistingMajority() {
@@ -21,7 +21,7 @@ private static Stream inputStreamWithExistingMajority() {
@ParameterizedTest
@MethodSource("inputStreamWithoutMajority")
void checkWhenMajorityExists(int[] input) {
- Assertions.assertFalse(BoyerMoore.findMajorityElement(input).isPresent());
+ Assertions.assertFalse(BoyerMooreMajorityVote.findMajorityElement(input).isPresent());
}
private static Stream inputStreamWithoutMajority() {
diff --git a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java b/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
index 669f928cd247..f32b77447d98 100644
--- a/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
+++ b/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java
@@ -1,12 +1,13 @@
package com.thealgorithms.others.cn;
+import com.thealgorithms.strings.HammingDistance;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
public class HammingDistanceTest {
@Test
public void checkForDifferentBits() {
- int answer = HammingDistance.compute("000", "011");
+ int answer = HammingDistance.computeBinary("000", "011");
Assertions.assertThat(answer).isEqualTo(2);
}
@@ -21,33 +22,33 @@ public void checkForDifferentBits() {
*/
@Test
public void checkForDifferentBitsLength() {
- int answer = HammingDistance.compute("10101", "11110");
+ int answer = HammingDistance.computeBinary("10101", "11110");
Assertions.assertThat(answer).isEqualTo(3);
}
@Test
public void checkForSameBits() {
String someBits = "111";
- int answer = HammingDistance.compute(someBits, someBits);
+ int answer = HammingDistance.computeBinary(someBits, someBits);
Assertions.assertThat(answer).isEqualTo(0);
}
@Test
public void checkForLongDataBits() {
- int answer = HammingDistance.compute("10010101101010000100110100", "00110100001011001100110101");
+ int answer = HammingDistance.computeBinary("10010101101010000100110100", "00110100001011001100110101");
Assertions.assertThat(answer).isEqualTo(7);
}
@Test
public void mismatchDataBits() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("100010", "00011"); });
+ Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.computeBinary("100010", "00011"); });
Assertions.assertThat(ex.getMessage()).contains("must have the same length");
}
@Test
public void mismatchDataBits2() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1", "11"); });
+ Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.computeBinary("1", "11"); });
Assertions.assertThat(ex.getMessage()).contains("must have the same length");
}
@@ -55,27 +56,27 @@ public void mismatchDataBits2() {
@Test
public void checkForLongDataBitsSame() {
String someBits = "10010101101010000100110100";
- int answer = HammingDistance.compute(someBits, someBits);
+ int answer = HammingDistance.computeBinary(someBits, someBits);
Assertions.assertThat(answer).isEqualTo(0);
}
@Test
public void checkForEmptyInput() {
String someBits = "";
- int answer = HammingDistance.compute(someBits, someBits);
+ int answer = HammingDistance.computeBinary(someBits, someBits);
Assertions.assertThat(answer).isEqualTo(0);
}
@Test
public void checkForInputOfLength1() {
String someBits = "0";
- int answer = HammingDistance.compute(someBits, someBits);
+ int answer = HammingDistance.computeBinary(someBits, someBits);
Assertions.assertThat(answer).isEqualTo(0);
}
@Test
public void computeThrowsExceptionWhenInputsAreNotBitStrs() {
- Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.compute("1A", "11"); });
+ Exception ex = org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> { HammingDistance.computeBinary("1A", "11"); });
Assertions.assertThat(ex.getMessage()).contains("must be a binary string");
}
diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
index 411b11e743b8..916a96f4326b 100644
--- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
+++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
@@ -1,33 +1,52 @@
package com.thealgorithms.strings;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import com.thealgorithms.stacks.ValidParentheses;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
+/**
+ * Tests for ValidParentheses (consolidated implementation in stacks package).
+ */
public class ValidParenthesesTest {
@ParameterizedTest(name = "Input: \"{0}\" β Expected: {1}")
- @CsvSource({"'()', true", "'()[]{}', true", "'(]', false", "'{[]}', true", "'([{}])', true", "'([)]', false", "'', true", "'(', false", "')', false", "'{{{{}}}}', true", "'[({})]', true", "'[(])', false", "'[', false", "']', false", "'()()()()', true", "'(()', false", "'())', false",
- "'{[()()]()}', true"})
- void
- testIsValid(String input, boolean expected) {
+ @CsvSource({
+ "'()', true",
+ "'()[]{}', true",
+ "'(]', false",
+ "'{[]}', true",
+ "'([{}])', true",
+ "'([)]', false",
+ "'', true",
+ "'(', false",
+ "')', false",
+ "'{{{{}}}}', true",
+ "'[({})]', true",
+ "'[(])', false",
+ "'[', false",
+ "']', false",
+ "'()()()()', true",
+ "'(()', false",
+ "'())', false",
+ "'{[()()]()}', true"
+ })
+ void testIsValid(String input, boolean expected) {
assertEquals(expected, ValidParentheses.isValid(input));
}
@Test
- void testNullInputThrows() {
- IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(null));
- assertEquals("Input string cannot be null", ex.getMessage());
+ void testNullInputReturnsFalse() {
+ assertFalse(ValidParentheses.isValid(null));
}
- @ParameterizedTest(name = "Input: \"{0}\" β throws IllegalArgumentException")
+ @ParameterizedTest(name = "Input: \"{0}\" β invalid characters return false")
@CsvSource({"'a'", "'()a'", "'[123]'", "'{hello}'", "'( )'", "'\t'", "'\n'", "'@#$%'"})
- void testInvalidCharactersThrow(String input) {
- IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(input));
- assertTrue(ex.getMessage().startsWith("Unexpected character"));
+ void testInvalidCharactersReturnFalse(String input) {
+ assertFalse(ValidParentheses.isValid(input));
}
}