+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a + * new entry is added, the youngest entry in the cache is selected and evicted to make space. + *
+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will + * automatically expire and be removed upon access or insertion attempts. + *
+ * Features: + *
This constructor initializes the cache with the specified capacity and default TTL,
+ * sets up internal data structures (a {@code HashMap} for cache entries,
+ * {an @code ArrayDeque}, for key storage, and configures eviction.
+ *
+ * @param builder the {@code Builder} object containing configuration parameters
+ */
+ private LIFOCache(Builder If the key is not present or the corresponding entry has expired, this method
+ * returns {@code null}. If an expired entry is found, it will be removed and the
+ * eviction listener (if any) will be notified. Cache hit-and-miss statistics are
+ * also updated accordingly.
+ *
+ * @param key the key whose associated value is to be returned; must not be {@code null}
+ * @return the cached value associated with the key, or {@code null} if not present or expired
+ * @throws IllegalArgumentException if {@code key} is {@code null}
+ */
+ public V get(K key) {
+ if (key == null) {
+ throw new IllegalArgumentException("Key must not be null");
+ }
+
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ final CacheEntry The key may overwrite an existing entry. The actual insertion is delegated
+ * to the overloaded {@link #put(K, V, long)} method.
+ *
+ * @param key the key to cache the value under
+ * @param value the value to be cached
+ */
+ public void put(K key, V value) {
+ put(key, value, defaultTTL);
+ }
+
+ /**
+ * Adds a key-value pair to the cache with a specified time-to-live (TTL).
+ *
+ * If the key already exists, its value is removed, re-inserted at tail and its TTL is reset.
+ * If the key does not exist and the cache is full, the youngest entry is evicted to make space.
+ * Expired entries are also cleaned up prior to any eviction. The eviction listener
+ * is notified when an entry gets evicted.
+ *
+ * @param key the key to associate with the cached value; must not be {@code null}
+ * @param value the value to be cached; must not be {@code null}
+ * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0
+ * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative
+ */
+ public void put(K key, V value, long ttlMillis) {
+ if (key == null || value == null) {
+ throw new IllegalArgumentException("Key and value must not be null");
+ }
+ if (ttlMillis < 0) {
+ throw new IllegalArgumentException("TTL must be >= 0");
+ }
+
+ lock.lock();
+ try {
+ // If key already exists, remove it. It will later be re-inserted at top of stack
+ keys.remove(key);
+ final CacheEntry This method iterates through the list of cached keys and checks each associated
+ * entry for expiration. Expired entries are removed the cache map. For each eviction,
+ * the eviction listener is notified.
+ */
+ private int evictExpired() {
+ int count = 0;
+ final Iterator If the {@code evictionListener} is not {@code null}, it is invoked with the provided key
+ * and value. Any exceptions thrown by the listener are caught and logged to standard error,
+ * preventing them from disrupting cache operations.
+ *
+ * @param key the key that was evicted
+ * @param value the value that was associated with the evicted key
+ */
+ private void notifyEviction(K key, V value) {
+ if (evictionListener != null) {
+ try {
+ evictionListener.accept(key, value);
+ } catch (Exception e) {
+ System.err.println("Eviction listener failed: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns the number of successful cache lookups (hits).
+ *
+ * @return the number of cache hits
+ */
+ public long getHits() {
+ lock.lock();
+ try {
+ return hits;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the number of failed cache lookups (misses), including expired entries.
+ *
+ * @return the number of cache misses
+ */
+ public long getMisses() {
+ lock.lock();
+ try {
+ return misses;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the current number of entries in the cache, excluding expired ones.
+ *
+ * @return the current cache size
+ */
+ public int size() {
+ lock.lock();
+ try {
+ evictionStrategy.onAccess(this);
+
+ int count = 0;
+ for (CacheEntry This method clears the internal cache map entirely, resets the hit-and-miss counters,
+ * and notifies the eviction listener (if any) for each removed entry.
+ * Note that expired entries are treated the same as active ones for the purpose of clearing.
+ *
+ * This operation acquires the internal lock to ensure thread safety.
+ */
+ public void clear() {
+ lock.lock();
+ try {
+ for (Map.Entry This method iterates through the cache and collects the keys of all non-expired entries.
+ * Expired entries are ignored but not removed. If you want to ensure expired entries are cleaned up,
+ * consider invoking {@link EvictionStrategy#onAccess(LIFOCache)} or calling {@link #evictExpired()} manually.
+ *
+ * This operation acquires the internal lock to ensure thread safety.
+ *
+ * @return a set containing all non-expired keys currently in the cache
+ */
+ public Set The returned string includes the cache's capacity, current size (excluding expired entries),
+ * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock
+ * to ensure thread-safe access.
+ *
+ * @return a string summarizing the state of the cache
+ */
+ @Override
+ public String toString() {
+ lock.lock();
+ try {
+ final Map Implementations decide whether and when to trigger {@link LIFOCache#evictExpired()} based
+ * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup,
+ * or no automatic cleanup.
+ *
+ * @param This deterministic strategy ensures cleanup occurs at predictable intervals,
+ * ideal for moderately active caches where memory usage is a concern.
+ *
+ * @param Allows configuring capacity, default TTL, eviction listener, and a pluggable eviction
+ * strategy. Call {@link #build()} to create the configured cache instance.
+ *
+ * @param
- * This class utilizes a HashMap to efficiently count occurrences of elements in the first array,
- * allowing for an efficient lookup of common elements in the second array.
+ * This intersection includes duplicate values — meaning elements are included in the result
+ * as many times as they appear in both arrays (i.e., multiset intersection).
*
- * Example:
- *
+ * Example usage:
+ *
- * Note: The order of the returned list may vary since it depends on the order of elements
- * in the input arrays.
+ * Note: The order of elements in the returned list depends on the order in the second input array.
* This algorithm determines whether any subset of a given array sums up to a specific target value. Time Complexity: O(n * sum) Space Complexity: O(sum)
+ * The mode of an array is the integer value(s) that occur most frequently.
+ * If multiple values have the same highest frequency, all such values are returned.
+ *
+ * If the input array is empty, this method returns {@code null}.
+ * If multiple numbers share the highest frequency, all are returned in the result array.
+ * Matrix multiplication takes two 2D arrays (matrices) as input and
+ * produces their product, following the mathematical definition of
+ * matrix multiplication.
+ *
+ * For more details:
+ * https://www.geeksforgeeks.org/java/java-program-to-multiply-two-matrices-of-any-size/
+ * https://en.wikipedia.org/wiki/Matrix_multiplication
+ *
+ * Time Complexity: O(n^3) – where n is the dimension of the matrices
+ * (assuming square matrices for simplicity).
+ *
+ * Space Complexity: O(n^2) – for storing the result matrix.
+ *
+ *
+ * @author Nishitha Wihala Pitigala
+ *
+ */
+
+public final class MatrixMultiplication {
+ private MatrixMultiplication() {
+ }
+
+ /**
+ * Multiplies two matrices.
+ *
+ * @param matrixA the first matrix rowsA x colsA
+ * @param matrixB the second matrix rowsB x colsB
+ * @return the product of the two matrices rowsA x colsB
+ * @throws IllegalArgumentException if the matrices cannot be multiplied
+ */
+ public static double[][] multiply(double[][] matrixA, double[][] matrixB) {
+ // Check the input matrices are not null
+ if (matrixA == null || matrixB == null) {
+ throw new IllegalArgumentException("Input matrices cannot be null");
+ }
+
+ // Check for empty matrices
+ if (matrixA.length == 0 || matrixB.length == 0 || matrixA[0].length == 0 || matrixB[0].length == 0) {
+ throw new IllegalArgumentException("Input matrices must not be empty");
+ }
+
+ // Validate the matrix dimensions
+ if (matrixA[0].length != matrixB.length) {
+ throw new IllegalArgumentException("Matrices cannot be multiplied: incompatible dimensions.");
+ }
+
+ int rowsA = matrixA.length;
+ int colsA = matrixA[0].length;
+ int colsB = matrixB[0].length;
+
+ // Initialize the result matrix with zeros
+ double[][] result = new double[rowsA][colsB];
+
+ // Perform matrix multiplication
+ for (int i = 0; i < rowsA; i++) {
+ for (int j = 0; j < colsB; j++) {
+ for (int k = 0; k < colsA; k++) {
+ result[i][j] += matrixA[i][k] * matrixB[k][j];
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java b/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java
index c710c60a2d2a..1ec977af07c6 100644
--- a/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java
+++ b/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java
@@ -14,19 +14,19 @@ private MedianOfMatrix() {
}
public static int median(Iterable This class uses a stack-based approach to reverse the digits obtained from
+ * successive divisions by the target radix.
+ *
+ * This class cannot be instantiated.
+ *
+ *
+ * @see Disjoint Set Union (Wikipedia)
*/
public class DisjointSetUnion
+ * The algorithm uses a {@link java.util.HashMap} to count occurrences of elements in the first array,
+ * then iterates through the second array to collect common elements based on these counts.
+ *
{@code
* int[] array1 = {1, 2, 2, 1};
* int[] array2 = {2, 2};
- * List
+ * List> matrix) {
- // Flatten the matrix into a 1D list
- List
> bag = new Bag<>();
+ List
> filter = new BloomFilter<>(4, 200);
+ List