From 62144f61af289cc94cec380d680b8865726c459a Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Mon, 7 Oct 2024 21:55:48 +0530
Subject: [PATCH 001/348] Add tests for `AStar.java`, enhance documentation
(#5603)
---
DIRECTORY.md | 1 +
.../datastructures/graphs/AStar.java | 144 ++++++------------
.../datastructures/graphs/AStarTest.java | 46 ++++++
3 files changed, 92 insertions(+), 99 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 7e5d0d3de9ba..87922528abda 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -694,6 +694,7 @@
* dynamicarray
* [DynamicArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java)
* graphs
+ * [AStarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java)
* [BipartiteGraphDFSTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java)
* [BoruvkaAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java)
* [DijkstraAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/AStar.java b/src/main/java/com/thealgorithms/datastructures/graphs/AStar.java
index 54fb5fba5c1b..460c05e04403 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/AStar.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/AStar.java
@@ -1,25 +1,26 @@
-/*
- Time Complexity = O(E), where E is equal to the number of edges
- */
package com.thealgorithms.datastructures.graphs;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
+/**
+ * AStar class implements the A* pathfinding algorithm to find the shortest path in a graph.
+ * The graph is represented using an adjacency list, and the algorithm uses a heuristic to estimate
+ * the cost to reach the destination node.
+ * Time Complexity = O(E), where E is equal to the number of edges
+ */
public final class AStar {
private AStar() {
}
- private static class Graph {
-
- // Graph's structure can be changed only applying changes to this class.
-
+ /**
+ * Represents a graph using an adjacency list.
+ */
+ static class Graph {
private ArrayList> graph;
- // Initialise ArrayLists in Constructor
Graph(int size) {
this.graph = new ArrayList<>();
for (int i = 0; i < size; i++) {
@@ -31,15 +32,17 @@ private ArrayList getNeighbours(int from) {
return this.graph.get(from);
}
- // Graph is bidirectional, for just one direction remove second instruction of this method.
+ // Add a bidirectional edge to the graph
private void addEdge(Edge edge) {
this.graph.get(edge.getFrom()).add(new Edge(edge.getFrom(), edge.getTo(), edge.getWeight()));
this.graph.get(edge.getTo()).add(new Edge(edge.getTo(), edge.getFrom(), edge.getWeight()));
}
}
+ /**
+ * Represents an edge in the graph with a start node, end node, and weight.
+ */
private static class Edge {
-
private int from;
private int to;
private int weight;
@@ -63,12 +66,13 @@ public int getWeight() {
}
}
- // class to iterate during the algorithm execution, and also used to return the solution.
- private static class PathAndDistance {
-
- private int distance; // distance advanced so far.
- private ArrayList path; // list of visited nodes in this path.
- private int estimated; // heuristic value associated to the last node od the path (current node).
+ /**
+ * Contains information about the path and its total distance.
+ */
+ static class PathAndDistance {
+ private int distance; // total distance from the start node
+ private ArrayList path; // list of nodes in the path
+ private int estimated; // heuristic estimate for reaching the destination
PathAndDistance(int distance, ArrayList path, int estimated) {
this.distance = distance;
@@ -87,112 +91,54 @@ public ArrayList getPath() {
public int getEstimated() {
return estimated;
}
-
- private void printSolution() {
- if (this.path != null) {
- System.out.println("Optimal path: " + this.path + ", distance: " + this.distance);
- } else {
- System.out.println("There is no path available to connect the points");
- }
- }
}
- private static void initializeGraph(Graph graph, ArrayList data) {
+ // Initializes the graph with edges defined in the input data
+ static void initializeGraph(Graph graph, ArrayList data) {
for (int i = 0; i < data.size(); i += 4) {
graph.addEdge(new Edge(data.get(i), data.get(i + 1), data.get(i + 2)));
}
- /*
- .x. node
- (y) cost
- - or | or / bidirectional connection
-
- ( 98)- .7. -(86)- .4.
- |
- ( 85)- .17. -(142)- .18. -(92)- .8. -(87)- .11.
- |
- . 1. -------------------- (160)
- | \ |
- (211) \ .6.
- | \ |
- . 5. (101)-.13. -(138) (115)
- | | | /
- ( 99) ( 97) | /
- | | | /
- .12. -(151)- .15. -(80)- .14. | /
- | | | | /
- ( 71) (140) (146)- .2. -(120)
- | | |
- .19. -( 75)- . 0. .10. -(75)- .3.
- | |
- (118) ( 70)
- | |
- .16. -(111)- .9.
- */
- }
-
- public static void main(String[] args) {
- // heuristic function optimistic values
- int[] heuristic = {
- 366,
- 0,
- 160,
- 242,
- 161,
- 178,
- 77,
- 151,
- 226,
- 244,
- 241,
- 234,
- 380,
- 98,
- 193,
- 253,
- 329,
- 80,
- 199,
- 374,
- };
-
- Graph graph = new Graph(20);
- ArrayList graphData = new ArrayList<>(Arrays.asList(0, 19, 75, null, 0, 15, 140, null, 0, 16, 118, null, 19, 12, 71, null, 12, 15, 151, null, 16, 9, 111, null, 9, 10, 70, null, 10, 3, 75, null, 3, 2, 120, null, 2, 14, 146, null, 2, 13, 138, null, 2, 6, 115, null, 15, 14, 80, null,
- 15, 5, 99, null, 14, 13, 97, null, 5, 1, 211, null, 13, 1, 101, null, 6, 1, 160, null, 1, 17, 85, null, 17, 7, 98, null, 7, 4, 86, null, 17, 18, 142, null, 18, 8, 92, null, 8, 11, 87));
- initializeGraph(graph, graphData);
-
- PathAndDistance solution = aStar(3, 1, graph, heuristic);
- solution.printSolution();
}
+ /**
+ * Implements the A* pathfinding algorithm to find the shortest path from a start node to a destination node.
+ *
+ * @param from the starting node
+ * @param to the destination node
+ * @param graph the graph representation of the problem
+ * @param heuristic the heuristic estimates for each node
+ * @return a PathAndDistance object containing the shortest path and its distance
+ */
public static PathAndDistance aStar(int from, int to, Graph graph, int[] heuristic) {
- // nodes are prioritised by the less value of the current distance of their paths, and the
- // estimated value
- // given by the heuristic function to reach the destination point from the current point.
+ // PriorityQueue to explore nodes based on their distance and estimated cost to reach the destination
PriorityQueue queue = new PriorityQueue<>(Comparator.comparingInt(a -> (a.getDistance() + a.getEstimated())));
- // dummy data to start the algorithm from the beginning point
- queue.add(new PathAndDistance(0, new ArrayList<>(List.of(from)), 0));
+ // Start with the initial node
+ queue.add(new PathAndDistance(0, new ArrayList<>(List.of(from)), heuristic[from]));
boolean solutionFound = false;
PathAndDistance currentData = new PathAndDistance(-1, null, -1);
+
while (!queue.isEmpty() && !solutionFound) {
- currentData = queue.poll(); // first in the queue, best node so keep exploring.
- int currentPosition = currentData.getPath().get(currentData.getPath().size() - 1); // current node.
+ currentData = queue.poll(); // get the best node from the queue
+ int currentPosition = currentData.getPath().get(currentData.getPath().size() - 1); // current node
+
+ // Check if the destination has been reached
if (currentPosition == to) {
solutionFound = true;
} else {
for (Edge edge : graph.getNeighbours(currentPosition)) {
- if (!currentData.getPath().contains(edge.getTo())) { // Avoid Cycles
+ // Avoid cycles by checking if the next node is already in the path
+ if (!currentData.getPath().contains(edge.getTo())) {
ArrayList updatedPath = new ArrayList<>(currentData.getPath());
- updatedPath.add(edge.getTo()); // Add the new node to the path, update the distance,
- // and the heuristic function value associated to that path.
+ updatedPath.add(edge.getTo());
+
+ // Update the distance and heuristic for the new path
queue.add(new PathAndDistance(currentData.getDistance() + edge.getWeight(), updatedPath, heuristic[edge.getTo()]));
}
}
}
}
return (solutionFound) ? currentData : new PathAndDistance(-1, null, -1);
- // Out of while loop, if there is a solution, the current Data stores the optimal path, and
- // its distance
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java
new file mode 100644
index 000000000000..dce5a6ed4b69
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class AStarTest {
+
+ private AStar.Graph graph;
+ private int[] heuristic;
+
+ @BeforeEach
+ public void setUp() {
+ // Initialize graph and heuristic values for testing
+ graph = new AStar.Graph(5);
+ ArrayList graphData = new ArrayList<>(Arrays.asList(0, 1, 1, null, 0, 2, 2, null, 1, 3, 1, null, 2, 3, 1, null, 3, 4, 1, null));
+ AStar.initializeGraph(graph, graphData);
+
+ heuristic = new int[] {5, 4, 3, 2, 0}; // Heuristic values for each node
+ }
+
+ @Test
+ public void testAStarFindsPath() {
+ AStar.PathAndDistance result = AStar.aStar(0, 4, graph, heuristic);
+ assertEquals(3, result.getDistance(), "Expected distance from 0 to 4 is 3");
+ assertEquals(Arrays.asList(0, 1, 3, 4), result.getPath(), "Expected path from 0 to 4");
+ }
+
+ @Test
+ public void testAStarPathNotFound() {
+ AStar.PathAndDistance result = AStar.aStar(0, 5, graph, heuristic); // Node 5 does not exist
+ assertEquals(-1, result.getDistance(), "Expected distance when path not found is -1");
+ assertNull(result.getPath(), "Expected path should be null when no path exists");
+ }
+
+ @Test
+ public void testAStarSameNode() {
+ AStar.PathAndDistance result = AStar.aStar(0, 0, graph, heuristic);
+ assertEquals(0, result.getDistance(), "Expected distance from 0 to 0 is 0");
+ assertEquals(Arrays.asList(0), result.getPath(), "Expected path should only contain the start node");
+ }
+}
From 676d451aa605a9442cdda85badbd0877816d6cf7 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Mon, 7 Oct 2024 22:17:29 +0530
Subject: [PATCH 002/348] Add class documentation, improve comments in
`MazeRecursion.java` (#5576)
---
.../backtracking/MazeRecursion.java | 205 ++++++++----------
.../backtracking/MazeRecursionTest.java | 34 ++-
2 files changed, 103 insertions(+), 136 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
index f7eae01e449a..8247172e7ee0 100644
--- a/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
+++ b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
@@ -1,152 +1,125 @@
package com.thealgorithms.backtracking;
+/**
+ * This class contains methods to solve a maze using recursive backtracking.
+ * The maze is represented as a 2D array where walls, paths, and visited/dead
+ * ends are marked with different integers.
+ *
+ * The goal is to find a path from a starting position to the target position
+ * (map[6][5]) while navigating through the maze.
+ */
public final class MazeRecursion {
+
private MazeRecursion() {
}
- public static void mazeRecursion() {
- // First create a 2 dimensions array to mimic a maze map
- int[][] map = new int[8][7];
- int[][] map2 = new int[8][7];
-
- // We use 1 to indicate wall
- // Set the ceiling and floor to 1
- for (int i = 0; i < 7; i++) {
- map[0][i] = 1;
- map[7][i] = 1;
- }
-
- // Then we set the left and right wall to 1
- for (int i = 0; i < 8; i++) {
- map[i][0] = 1;
- map[i][6] = 1;
- }
-
- // Now we have created a maze with its wall initialized
-
- // Here we set the obstacle
- map[3][1] = 1;
- map[3][2] = 1;
-
- // Print the current map
- System.out.println("The condition of the map: ");
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 7; j++) {
- System.out.print(map[i][j] + " ");
- }
- System.out.println();
- }
-
- // clone another map for setWay2 method
- for (int i = 0; i < map.length; i++) {
- System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
- }
-
- // By using recursive backtracking to let your ball(target) find its way in the
- // maze
- // The first parameter is the map
- // Second parameter is x coordinate of your target
- // Third parameter is the y coordinate of your target
- setWay(map, 1, 1);
- setWay2(map2, 1, 1);
-
- // Print out the new map1, with the ball footprint
- System.out.println("After the ball goes through the map1,show the current map1 condition");
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 7; j++) {
- System.out.print(map[i][j] + " ");
- }
- System.out.println();
+ /**
+ * This method solves the maze using the "down -> right -> up -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingFirstStrategy(int[][] map) {
+ if (setWay(map, 1, 1)) {
+ return map;
}
+ return null;
+ }
- // Print out the new map2, with the ball footprint
- System.out.println("After the ball goes through the map2,show the current map2 condition");
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < 7; j++) {
- System.out.print(map2[i][j] + " ");
- }
- System.out.println();
+ /**
+ * This method solves the maze using the "up -> right -> down -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingSecondStrategy(int[][] map) {
+ if (setWay2(map, 1, 1)) {
+ return map;
}
+ return null;
}
/**
- * Using recursive path finding to help the ball find its way in the maze
- * Description:
- * 1. map (means the maze)
- * 2. i, j (means the initial coordinate of the ball in the maze)
- * 3. if the ball can reach the end of maze, that is position of map[6][5],
- * means the we have found a path for the ball
- * 4. Additional Information: 0 in the map[i][j] means the ball has not gone
- * through this position, 1 means the wall, 2 means the path is feasible, 3
- * means the ball has gone through the path but this path is dead end
- * 5. We will need strategy for the ball to pass through the maze for example:
- * Down -> Right -> Up -> Left, if the path doesn't work, then backtrack
+ * Attempts to find a path through the maze using a "down -> right -> up -> left"
+ * movement strategy. The path is marked with '2' for valid paths and '3' for dead ends.
*
- * @author OngLipWei
- * @version Jun 23, 2021 11:36:14 AM
- * @param map The maze
- * @param i x coordinate of your ball(target)
- * @param j y coordinate of your ball(target)
- * @return If we did find a path for the ball,return true,else false
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
*/
- public static boolean setWay(int[][] map, int i, int j) {
- if (map[6][5] == 2) { // means the ball find its path, ending condition
+ private static boolean setWay(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
return true;
}
- if (map[i][j] == 0) { // if the ball haven't gone through this point
- // then the ball follows the move strategy : down -> right -> up -> left
- map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
- // first。
- if (setWay(map, i + 1, j)) { // go down
+
+ // If the current position is unvisited (0), explore it
+ if (map[i][j] == 0) {
+ // Mark the current position as '2'
+ map[i][j] = 2;
+
+ // Move down
+ if (setWay(map, i + 1, j)) {
return true;
- } else if (setWay(map, i, j + 1)) { // go right
+ }
+ // Move right
+ else if (setWay(map, i, j + 1)) {
return true;
- } else if (setWay(map, i - 1, j)) { // go up
+ }
+ // Move up
+ else if (setWay(map, i - 1, j)) {
return true;
- } else if (setWay(map, i, j - 1)) { // go left
+ }
+ // Move left
+ else if (setWay(map, i, j - 1)) {
return true;
- } else {
- // means that the current point is the dead end, the ball cannot proceed, set
- // the current point to 3 and return false, the backtracking will start, it will
- // go to the previous step and check for feasible path again
- map[i][j] = 3;
- return false;
}
- } else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
- // ball cannot hit the wall, cannot go to the path that has gone though before,
- // and cannot head to deadened.
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false;
}
+ return false;
}
- // Here is another move strategy for the ball: up->right->down->left
- public static boolean setWay2(int[][] map, int i, int j) {
- if (map[6][5] == 2) { // means the ball find its path, ending condition
+ /**
+ * Attempts to find a path through the maze using an alternative movement
+ * strategy "up -> right -> down -> left".
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
+ */
+ private static boolean setWay2(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
return true;
}
- if (map[i][j] == 0) { // if the ball haven't gone through this point
- // then the ball follows the move strategy : up->right->down->left
- map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
- // first。
- if (setWay2(map, i - 1, j)) { // go up
+
+ if (map[i][j] == 0) {
+ map[i][j] = 2;
+
+ // Move up
+ if (setWay2(map, i - 1, j)) {
return true;
- } else if (setWay2(map, i, j + 1)) { // go right
+ }
+ // Move right
+ else if (setWay2(map, i, j + 1)) {
return true;
- } else if (setWay2(map, i + 1, j)) { // go down
+ }
+ // Move down
+ else if (setWay2(map, i + 1, j)) {
return true;
- } else if (setWay2(map, i, j - 1)) { // go left
+ }
+ // Move left
+ else if (setWay2(map, i, j - 1)) {
return true;
- } else {
- // means that the current point is the dead end, the ball cannot proceed, set
- // the current point to 3 and return false, the backtracking will start, it will
- // go to the previous step and check for feasible path again
- map[i][j] = 3;
- return false;
}
- } else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
- // ball cannot hit the wall, cannot go to the path that has gone through before,
- // and cannot head to deadend.
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
return false;
}
+ return false;
}
}
diff --git a/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java b/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java
index edaca14af067..b8e77fb38bad 100644
--- a/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java
+++ b/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java
@@ -11,41 +11,35 @@
public class MazeRecursionTest {
@Test
- public void testMaze() {
- // First create a 2 dimensions array to mimic a maze map
+ public void testSolveMazeUsingFirstAndSecondStrategy() {
int[][] map = new int[8][7];
int[][] map2 = new int[8][7];
- // We use 1 to indicate wall
+ // We use 1 to indicate walls
// Set the ceiling and floor to 1
for (int i = 0; i < 7; i++) {
map[0][i] = 1;
map[7][i] = 1;
}
-
- // Then we set the left and right wall to 1
+ // Set the left and right wall to 1
for (int i = 0; i < 8; i++) {
map[i][0] = 1;
map[i][6] = 1;
}
-
- // Now we have created a maze with its wall initialized
-
- // Here we set the obstacle
+ // Set obstacles
map[3][1] = 1;
map[3][2] = 1;
- // clone another map for setWay2 method
+ // Clone the original map for the second pathfinding strategy
for (int i = 0; i < map.length; i++) {
- for (int j = 0; j < map[i].length; j++) {
- map2[i][j] = map[i][j];
- }
+ System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
}
- MazeRecursion.setWay(map, 1, 1);
- MazeRecursion.setWay2(map2, 1, 1);
-
- int[][] expectedMap = new int[][] {
+ // Solve the maze using the first strategy
+ int[][] solvedMap1 = MazeRecursion.solveMazeUsingFirstStrategy(map);
+ // Solve the maze using the second strategy
+ int[][] solvedMap2 = MazeRecursion.solveMazeUsingSecondStrategy(map2);
+ int[][] expectedMap1 = new int[][] {
{1, 1, 1, 1, 1, 1, 1},
{1, 2, 0, 0, 0, 0, 1},
{1, 2, 2, 2, 0, 0, 1},
@@ -55,7 +49,6 @@ public void testMaze() {
{1, 0, 0, 2, 2, 2, 1},
{1, 1, 1, 1, 1, 1, 1},
};
-
int[][] expectedMap2 = new int[][] {
{1, 1, 1, 1, 1, 1, 1},
{1, 2, 2, 2, 2, 2, 1},
@@ -67,7 +60,8 @@ public void testMaze() {
{1, 1, 1, 1, 1, 1, 1},
};
- assertArrayEquals(map, expectedMap);
- assertArrayEquals(map2, expectedMap2);
+ // Assert the results
+ assertArrayEquals(expectedMap1, solvedMap1);
+ assertArrayEquals(expectedMap2, solvedMap2);
}
}
From 732f7c8458669fca84f9800c0d0864a5634eca6a Mon Sep 17 00:00:00 2001
From: Prayas Kumar <71717433+prayas7102@users.noreply.github.com>
Date: Mon, 7 Oct 2024 23:00:46 +0530
Subject: [PATCH 003/348] Add BM25 Inverted Index Search Algorithm (#5615)
---
.../searches/BM25InvertedIndex.java | 220 ++++++++++++++++++
.../searches/BM25InvertedIndexTest.java | 93 ++++++++
2 files changed, 313 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
create mode 100644 src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
diff --git a/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java b/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
new file mode 100644
index 000000000000..1cfd2bbad8e4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
@@ -0,0 +1,220 @@
+package com.thealgorithms.searches;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Inverted Index implementation with BM25 Scoring for movie search.
+ * This class supports adding movie documents and searching for terms
+ * within those documents using the BM25 algorithm.
+ * @author Prayas Kumar (https://github.com/prayas7102)
+ */
+
+class Movie {
+ int docId; // Unique identifier for the movie
+ String name; // Movie name
+ double imdbRating; // IMDb rating of the movie
+ int releaseYear; // Year the movie was released
+ String content; // Full text content (could be the description or script)
+
+ /**
+ * Constructor for the Movie class.
+ * @param docId Unique identifier for the movie.
+ * @param name Name of the movie.
+ * @param imdbRating IMDb rating of the movie.
+ * @param releaseYear Release year of the movie.
+ * @param content Content or description of the movie.
+ */
+ Movie(int docId, String name, double imdbRating, int releaseYear, String content) {
+ this.docId = docId;
+ this.name = name;
+ this.imdbRating = imdbRating;
+ this.releaseYear = releaseYear;
+ this.content = content;
+ }
+
+ /**
+ * Get all the words from the movie's name and content.
+ * Converts the name and content to lowercase and splits on non-word characters.
+ * @return Array of words from the movie name and content.
+ */
+ public String[] getWords() {
+ return (name + " " + content).toLowerCase().split("\\W+");
+ }
+
+ @Override
+ public String toString() {
+ return "Movie{"
+ + "docId=" + docId + ", name='" + name + '\'' + ", imdbRating=" + imdbRating + ", releaseYear=" + releaseYear + '}';
+ }
+}
+
+class SearchResult {
+ int docId; // Unique identifier of the movie document
+ double relevanceScore; // Relevance score based on the BM25 algorithm
+
+ /**
+ * Constructor for SearchResult class.
+ * @param docId Document ID (movie) for this search result.
+ * @param relevanceScore The relevance score based on BM25 scoring.
+ */
+ SearchResult(int docId, double relevanceScore) {
+ this.docId = docId;
+ this.relevanceScore = relevanceScore;
+ }
+
+ public int getDocId() {
+ return docId;
+ }
+
+ @Override
+ public String toString() {
+ return "SearchResult{"
+ + "docId=" + docId + ", relevanceScore=" + relevanceScore + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SearchResult that = (SearchResult) o;
+ return docId == that.docId && Double.compare(that.relevanceScore, relevanceScore) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(docId, relevanceScore);
+ }
+
+ public double getRelevanceScore() {
+ return this.relevanceScore;
+ }
+}
+
+public final class BM25InvertedIndex {
+ private Map> index; // Inverted index mapping terms to document id and frequency
+ private Map movies; // Mapping of movie document IDs to Movie objects
+ private int totalDocuments; // Total number of movies/documents
+ private double avgDocumentLength; // Average length of documents (number of words)
+ private static final double K = 1.5; // BM25 tuning parameter, controls term frequency saturation
+ private static final double B = 0.75; // BM25 tuning parameter, controls length normalization
+
+ /**
+ * Constructor for BM25InvertedIndex.
+ * Initializes the inverted index and movie storage.
+ */
+ BM25InvertedIndex() {
+ index = new HashMap<>();
+ movies = new HashMap<>();
+ totalDocuments = 0;
+ avgDocumentLength = 0.0;
+ }
+
+ /**
+ * Add a movie to the index.
+ * @param docId Unique identifier for the movie.
+ * @param name Name of the movie.
+ * @param imdbRating IMDb rating of the movie.
+ * @param releaseYear Release year of the movie.
+ * @param content Content or description of the movie.
+ */
+ public void addMovie(int docId, String name, double imdbRating, int releaseYear, String content) {
+ Movie movie = new Movie(docId, name, imdbRating, releaseYear, content);
+ movies.put(docId, movie);
+ totalDocuments++;
+
+ // Get words (terms) from the movie's name and content
+ String[] terms = movie.getWords();
+ int docLength = terms.length;
+
+ // Update the average document length
+ avgDocumentLength = (avgDocumentLength * (totalDocuments - 1) + docLength) / totalDocuments;
+
+ // Update the inverted index
+ for (String term : terms) {
+ // Create a new entry if the term is not yet in the index
+ index.putIfAbsent(term, new HashMap<>());
+
+ // Get the list of documents containing the term
+ Map docList = index.get(term);
+ if (docList == null) {
+ docList = new HashMap<>();
+ index.put(term, docList); // Ensure docList is added to the index
+ }
+ // Increment the term frequency in this document
+ docList.put(docId, docList.getOrDefault(docId, 0) + 1);
+ }
+ }
+
+ public int getMoviesLength() {
+ return movies.size();
+ }
+
+ /**
+ * Search for documents containing a term using BM25 scoring.
+ * @param term The search term.
+ * @return A list of search results sorted by relevance score.
+ */
+ public List search(String term) {
+ term = term.toLowerCase(); // Normalize search term
+ if (!index.containsKey(term)) {
+ return new ArrayList<>(); // Return empty list if term not found
+ }
+
+ Map termDocs = index.get(term); // Documents containing the term
+ List results = new ArrayList<>();
+
+ // Compute IDF for the search term
+ double idf = computeIDF(termDocs.size());
+
+ // Calculate relevance scores for all documents containing the term
+ for (Map.Entry entry : termDocs.entrySet()) {
+ int docId = entry.getKey();
+ int termFrequency = entry.getValue();
+ Movie movie = movies.get(docId);
+ if (movie == null) {
+ continue; // Skip this document if movie doesn't exist
+ }
+ double docLength = movie.getWords().length;
+
+ // Compute BM25 relevance score
+ double score = computeBM25Score(termFrequency, docLength, idf);
+ results.add(new SearchResult(docId, score));
+ }
+
+ // Sort the results by relevance score in descending order
+ results.sort((r1, r2) -> Double.compare(r2.relevanceScore, r1.relevanceScore));
+ return results;
+ }
+
+ /**
+ * Compute the BM25 score for a given term and document.
+ * @param termFrequency The frequency of the term in the document.
+ * @param docLength The length of the document.
+ * @param idf The inverse document frequency of the term.
+ * @return The BM25 relevance score for the term in the document.
+ */
+ private double computeBM25Score(int termFrequency, double docLength, double idf) {
+ double numerator = termFrequency * (K + 1);
+ double denominator = termFrequency + K * (1 - B + B * (docLength / avgDocumentLength));
+ return idf * (numerator / denominator);
+ }
+
+ /**
+ * Compute the inverse document frequency (IDF) of a term.
+ * The IDF measures the importance of a term across the entire document set.
+ * @param docFrequency The number of documents that contain the term.
+ * @return The inverse document frequency (IDF) value.
+ */
+ private double computeIDF(int docFrequency) {
+ // Total number of documents in the index
+ return Math.log((totalDocuments - docFrequency + 0.5) / (docFrequency + 0.5));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java b/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
new file mode 100644
index 000000000000..8595e0a00683
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
@@ -0,0 +1,93 @@
+package com.thealgorithms.searches;
+
+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.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test Cases for Inverted Index with BM25
+ * @author Prayas Kumar (https://github.com/prayas7102)
+ */
+
+class BM25InvertedIndexTest {
+
+ private static BM25InvertedIndex index;
+
+ @BeforeAll
+ static void setUp() {
+ index = new BM25InvertedIndex();
+ index.addMovie(1, "The Shawshank Redemption", 9.3, 1994, "Hope is a good thing. Maybe the best of things. And no good thing ever dies.");
+ index.addMovie(2, "The Godfather", 9.2, 1972, "I'm gonna make him an offer he can't refuse.");
+ index.addMovie(3, "The Dark Knight", 9.0, 2008, "You either die a hero or live long enough to see yourself become the villain.");
+ index.addMovie(4, "Pulp Fiction", 8.9, 1994, "You know what they call a Quarter Pounder with Cheese in Paris? They call it a Royale with Cheese.");
+ index.addMovie(5, "Good Will Hunting", 8.3, 1997, "Will Hunting is a genius and he has a good heart. The best of his abilities is yet to be explored.");
+ index.addMovie(6, "It's a Wonderful Life", 8.6, 1946, "Each man's life touches so many other lives. If he wasn't around, it would leave an awfully good hole.");
+ index.addMovie(7, "The Pursuit of Happyness", 8.0, 2006, "It was the pursuit of a better life, and a good opportunity to change things for the better.");
+ index.addMovie(8, "A Few Good Men", 7.7, 1992, "You can't handle the truth! This movie has a lot of good moments and intense drama.");
+ }
+
+ @Test
+ void testAddMovie() {
+ // Check that the index contains the correct number of movies
+ int moviesLength = index.getMoviesLength();
+ assertEquals(8, moviesLength);
+ }
+
+ @Test
+ void testSearchForTermFound() {
+ int expected = 1;
+ List result = index.search("hope");
+ int actual = result.getFirst().getDocId();
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ void testSearchRanking() {
+ // Perform search for the term "good"
+ List results = index.search("good");
+ assertFalse(results.isEmpty());
+
+ // Validate the ranking based on the provided relevance scores
+ assertEquals(6, results.get(0).getDocId()); // It's a Wonderful Life should be ranked 1st
+ assertEquals(7, results.get(1).getDocId()); // The Pursuit of Happyness should be ranked 2nd
+ assertEquals(5, results.get(2).getDocId()); // Good Will Hunting should be ranked 3rd
+ assertEquals(8, results.get(3).getDocId()); // A Few Good Men should be ranked 4th
+ assertEquals(1, results.get(4).getDocId()); // The Shawshank Redemption should be ranked 5th
+
+ // Ensure the relevance scores are in descending order
+ for (int i = 0; i < results.size() - 1; i++) {
+ assertTrue(results.get(i).getRelevanceScore() > results.get(i + 1).getRelevanceScore());
+ }
+ }
+
+ @Test
+ void testSearchForTermNotFound() {
+ List results = index.search("nonexistent");
+ assertTrue(results.isEmpty());
+ }
+
+ @Test
+ void testSearchForCommonTerm() {
+ List results = index.search("the");
+ assertFalse(results.isEmpty());
+ assertTrue(results.size() > 1);
+ }
+
+ @Test
+ void testBM25ScoreCalculation() {
+ List results = index.search("cheese");
+ assertEquals(1, results.size());
+ assertEquals(4, results.getFirst().docId); // Pulp Fiction should have the highest score
+ }
+
+ @Test
+ void testCaseInsensitivity() {
+ List resultsLowerCase = index.search("hope");
+ List resultsUpperCase = index.search("HOPE");
+ assertEquals(resultsLowerCase, resultsUpperCase);
+ }
+}
From 4a5bf39f8e196efd9772d3708217dd5554d14a1d Mon Sep 17 00:00:00 2001
From: Taranjeet Singh Kalsi
Date: Tue, 8 Oct 2024 00:18:02 +0530
Subject: [PATCH 004/348] Add another method to check valid parentheses in
ValidParentheses.java (#5616)
---
.../strings/ValidParentheses.java | 18 ++++++++++++++++++
.../strings/ValidParenthesesTest.java | 3 +++
2 files changed, 21 insertions(+)
diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java
index f4f3761b0495..629fee495d84 100644
--- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java
+++ b/src/main/java/com/thealgorithms/strings/ValidParentheses.java
@@ -38,4 +38,22 @@ public static boolean isValid(String s) {
}
return head == 0;
}
+ public static boolean isValidParentheses(String s) {
+ int i = -1;
+ char[] stack = new char[s.length()];
+ String openBrackets = "({[";
+ String closeBrackets = ")}]";
+ for (char ch : s.toCharArray()) {
+ if (openBrackets.indexOf(ch) != -1) {
+ stack[++i] = ch;
+ } else {
+ if (i >= 0 && openBrackets.indexOf(stack[i]) == closeBrackets.indexOf(ch)) {
+ i--;
+ } else {
+ return false;
+ }
+ }
+ }
+ return i == -1;
+ }
}
diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
index 22deb4b14d3c..2b6884c91c8f 100644
--- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
+++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java
@@ -10,15 +10,18 @@ public class ValidParenthesesTest {
@Test
void testOne() {
assertTrue(ValidParentheses.isValid("()"));
+ assertTrue(ValidParentheses.isValidParentheses("()"));
}
@Test
void testTwo() {
assertTrue(ValidParentheses.isValid("()[]{}"));
+ assertTrue(ValidParentheses.isValidParentheses("()[]{}"));
}
@Test
void testThree() {
assertFalse(ValidParentheses.isValid("(]"));
+ assertFalse(ValidParentheses.isValidParentheses("(]"));
}
}
From 6868bf8ba01041a50fdb37b953ff462d68526879 Mon Sep 17 00:00:00 2001
From: Nandini Pandey <120239212+Nandini-Pandey@users.noreply.github.com>
Date: Tue, 8 Oct 2024 00:28:17 +0530
Subject: [PATCH 005/348] Add palindrome singly linkedlist optimised approach
(#5617)
---
.../misc/PalindromeSinglyLinkedList.java | 43 +++++++++++
.../misc/PalindromeSinglyLinkedListTest.java | 72 +++++++++++++++++++
2 files changed, 115 insertions(+)
diff --git a/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java b/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java
index 07286b39f2e4..8af8a9b030e1 100644
--- a/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java
+++ b/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java
@@ -30,4 +30,47 @@ public static boolean isPalindrome(final SinglyLinkedList linkedList) {
return true;
}
+
+ // Optimised approach with O(n) time complexity and O(1) space complexity
+
+ public static boolean isPalindromeOptimised(Node head) {
+ if (head == null || head.next == null) {
+ return true;
+ }
+ Node slow = head;
+ Node fast = head;
+ while (fast != null && fast.next != null) {
+ slow = slow.next;
+ fast = fast.next.next;
+ }
+ Node midNode = slow;
+
+ Node prevNode = null;
+ Node currNode = midNode;
+ Node nextNode;
+ while (currNode != null) {
+ nextNode = currNode.next;
+ currNode.next = prevNode;
+ prevNode = currNode;
+ currNode = nextNode;
+ }
+ Node left = head;
+ Node right = prevNode;
+ while (left != null && right != null) {
+ if (left.val != right.val) {
+ return false;
+ }
+ right = right.next;
+ left = left.next;
+ }
+ return true;
+ }
+ static class Node {
+ int val;
+ Node next;
+ Node(int val) {
+ this.val = val;
+ this.next = null;
+ }
+ }
}
diff --git a/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java b/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java
index ae0d6ae0674d..0f0577d39094 100644
--- a/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java
+++ b/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java
@@ -7,6 +7,8 @@
import org.junit.jupiter.api.Test;
public class PalindromeSinglyLinkedListTest {
+
+ // Stack-based tests
@Test
public void testWithEmptyList() {
assertTrue(PalindromeSinglyLinkedList.isPalindrome(new SinglyLinkedList()));
@@ -67,4 +69,74 @@ public void testWithListWithEvenLengthNegative() {
exampleList.insert(20);
assertFalse(PalindromeSinglyLinkedList.isPalindrome(exampleList));
}
+
+ // Optimized approach tests
+ @Test
+ public void testOptimisedWithEmptyList() {
+ assertTrue(PalindromeSinglyLinkedList.isPalindromeOptimised(null));
+ }
+
+ @Test
+ public void testOptimisedWithSingleElement() {
+ PalindromeSinglyLinkedList.Node node = new PalindromeSinglyLinkedList.Node(100);
+ assertTrue(PalindromeSinglyLinkedList.isPalindromeOptimised(node));
+ }
+
+ @Test
+ public void testOptimisedWithOddLengthPositive() {
+ PalindromeSinglyLinkedList.Node node1 = new PalindromeSinglyLinkedList.Node(1);
+ PalindromeSinglyLinkedList.Node node2 = new PalindromeSinglyLinkedList.Node(2);
+ PalindromeSinglyLinkedList.Node node3 = new PalindromeSinglyLinkedList.Node(1);
+ node1.next = node2;
+ node2.next = node3;
+ assertTrue(PalindromeSinglyLinkedList.isPalindromeOptimised(node1));
+ }
+
+ @Test
+ public void testOptimisedWithOddLengthPositive2() {
+ PalindromeSinglyLinkedList.Node node1 = new PalindromeSinglyLinkedList.Node(3);
+ PalindromeSinglyLinkedList.Node node2 = new PalindromeSinglyLinkedList.Node(2);
+ PalindromeSinglyLinkedList.Node node3 = new PalindromeSinglyLinkedList.Node(1);
+ PalindromeSinglyLinkedList.Node node4 = new PalindromeSinglyLinkedList.Node(2);
+ PalindromeSinglyLinkedList.Node node5 = new PalindromeSinglyLinkedList.Node(3);
+ node1.next = node2;
+ node2.next = node3;
+ node3.next = node4;
+ node4.next = node5;
+ assertTrue(PalindromeSinglyLinkedList.isPalindromeOptimised(node1));
+ }
+
+ @Test
+ public void testOptimisedWithEvenLengthPositive() {
+ PalindromeSinglyLinkedList.Node node1 = new PalindromeSinglyLinkedList.Node(10);
+ PalindromeSinglyLinkedList.Node node2 = new PalindromeSinglyLinkedList.Node(20);
+ PalindromeSinglyLinkedList.Node node3 = new PalindromeSinglyLinkedList.Node(20);
+ PalindromeSinglyLinkedList.Node node4 = new PalindromeSinglyLinkedList.Node(10);
+ node1.next = node2;
+ node2.next = node3;
+ node3.next = node4;
+ assertTrue(PalindromeSinglyLinkedList.isPalindromeOptimised(node1));
+ }
+
+ @Test
+ public void testOptimisedWithOddLengthNegative() {
+ PalindromeSinglyLinkedList.Node node1 = new PalindromeSinglyLinkedList.Node(1);
+ PalindromeSinglyLinkedList.Node node2 = new PalindromeSinglyLinkedList.Node(2);
+ PalindromeSinglyLinkedList.Node node3 = new PalindromeSinglyLinkedList.Node(2);
+ node1.next = node2;
+ node2.next = node3;
+ assertFalse(PalindromeSinglyLinkedList.isPalindromeOptimised(node1));
+ }
+
+ @Test
+ public void testOptimisedWithEvenLengthNegative() {
+ PalindromeSinglyLinkedList.Node node1 = new PalindromeSinglyLinkedList.Node(10);
+ PalindromeSinglyLinkedList.Node node2 = new PalindromeSinglyLinkedList.Node(20);
+ PalindromeSinglyLinkedList.Node node3 = new PalindromeSinglyLinkedList.Node(20);
+ PalindromeSinglyLinkedList.Node node4 = new PalindromeSinglyLinkedList.Node(20);
+ node1.next = node2;
+ node2.next = node3;
+ node3.next = node4;
+ assertFalse(PalindromeSinglyLinkedList.isPalindromeOptimised(node1));
+ }
}
From 5dcf6c0f29d6c850709fd27672efc27f337bf8b5 Mon Sep 17 00:00:00 2001
From: Sailok Chinta
Date: Tue, 8 Oct 2024 02:41:55 +0530
Subject: [PATCH 006/348] Enhance Trie data structure with added methods and
tests (#5538)
---
DIRECTORY.md | 2 +-
.../trees/{TrieImp.java => Trie.java} | 141 +++++++++++++-----
.../trees/{TrieImpTest.java => TrieTest.java} | 37 +++--
3 files changed, 129 insertions(+), 51 deletions(-)
rename src/main/java/com/thealgorithms/datastructures/trees/{TrieImp.java => Trie.java} (50%)
rename src/test/java/com/thealgorithms/datastructures/trees/{TrieImpTest.java => TrieTest.java} (69%)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 87922528abda..ad337f35fc8f 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -207,7 +207,7 @@
* [SplayTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java)
* [Treap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/Treap.java)
* [TreeRandomNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/TreeRandomNode.java)
- * [TrieImp](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java)
+ * [Trie](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/Trie.java)
* [VerticalOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversal.java)
* [ZigzagTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/ZigzagTraversal.java)
* devutils
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java b/src/main/java/com/thealgorithms/datastructures/trees/Trie.java
similarity index 50%
rename from src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java
rename to src/main/java/com/thealgorithms/datastructures/trees/Trie.java
index a43a454146cb..02f28d4d83ad 100644
--- a/src/main/java/com/thealgorithms/datastructures/trees/TrieImp.java
+++ b/src/main/java/com/thealgorithms/datastructures/trees/Trie.java
@@ -1,5 +1,28 @@
package com.thealgorithms.datastructures.trees;
+import java.util.HashMap;
+
+/**
+ * Represents a Trie Node that stores a character and pointers to its children.
+ * Each node has a hashmap which can point to all possible characters.
+ * Each node also has a boolean value to indicate if it is the end of a word.
+ */
+class TrieNode {
+ char value;
+ HashMap child;
+ boolean end;
+
+ /**
+ * Constructor to initialize a TrieNode with an empty hashmap
+ * and set end to false.
+ */
+ TrieNode(char value) {
+ this.value = value;
+ this.child = new HashMap<>();
+ this.end = false;
+ }
+}
+
/**
* Trie Data structure implementation without any libraries.
*
@@ -14,27 +37,11 @@
* possible character.
*
* @author Dheeraj Kumar Barnwal
+ * @author Sailok Chinta
*/
-public class TrieImp {
- /**
- * Represents a Trie Node that stores a character and pointers to its children.
- * Each node has an array of 26 children (one for each letter from 'a' to 'z').
- */
- public class TrieNode {
-
- TrieNode[] child;
- boolean end;
-
- /**
- * Constructor to initialize a TrieNode with an empty child array
- * and set end to false.
- */
- public TrieNode() {
- child = new TrieNode[26];
- end = false;
- }
- }
+public class Trie {
+ private static final char ROOT_NODE_VALUE = '*';
private final TrieNode root;
@@ -42,8 +49,8 @@ public TrieNode() {
* Constructor to initialize the Trie.
* The root node is created but doesn't represent any character.
*/
- public TrieImp() {
- root = new TrieNode();
+ public Trie() {
+ root = new TrieNode(ROOT_NODE_VALUE);
}
/**
@@ -57,13 +64,15 @@ public TrieImp() {
public void insert(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
- TrieNode node = currentNode.child[word.charAt(i) - 'a'];
+ TrieNode node = currentNode.child.getOrDefault(word.charAt(i), null);
+
if (node == null) {
- node = new TrieNode();
- currentNode.child[word.charAt(i) - 'a'] = node;
+ node = new TrieNode(word.charAt(i));
+ currentNode.child.put(word.charAt(i), node);
}
currentNode = node;
}
+
currentNode.end = true;
}
@@ -80,13 +89,14 @@ public void insert(String word) {
public boolean search(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
- char ch = word.charAt(i);
- TrieNode node = currentNode.child[ch - 'a'];
+ TrieNode node = currentNode.child.getOrDefault(word.charAt(i), null);
+
if (node == null) {
return false;
}
currentNode = node;
}
+
return currentNode.end;
}
@@ -104,40 +114,89 @@ public boolean search(String word) {
public boolean delete(String word) {
TrieNode currentNode = root;
for (int i = 0; i < word.length(); i++) {
- char ch = word.charAt(i);
- TrieNode node = currentNode.child[ch - 'a'];
+ TrieNode node = currentNode.child.getOrDefault(word.charAt(i), null);
if (node == null) {
return false;
}
+
currentNode = node;
}
+
if (currentNode.end) {
currentNode.end = false;
return true;
}
+
return false;
}
/**
- * Helper method to print a string to the console.
+ * Counts the number of words in the trie
+ *
+ * The method traverses the Trie and counts the number of words.
*
- * @param print The string to be printed.
+ * @return count of words
*/
- public static void sop(String print) {
- System.out.println(print);
+ public int countWords() {
+ return countWords(root);
+ }
+
+ private int countWords(TrieNode node) {
+ if (node == null) {
+ return 0;
+ }
+
+ int count = 0;
+ if (node.end) {
+ count++;
+ }
+
+ for (TrieNode child : node.child.values()) {
+ count += countWords(child);
+ }
+
+ return count;
}
/**
- * Validates if a given word contains only lowercase alphabetic characters
- * (a-z).
- *
- * The method uses a regular expression to check if the word matches the pattern
- * of only lowercase letters.
+ * Check if the prefix exists in the trie
*
- * @param word The word to be validated.
- * @return true if the word is valid (only a-z), false otherwise.
+ * @param prefix the prefix to be checked in the Trie
+ * @return true / false depending on the prefix if exists in the Trie
*/
- public static boolean isValid(String word) {
- return word.matches("^[a-z]+$");
+ public boolean startsWithPrefix(String prefix) {
+ TrieNode currentNode = root;
+
+ for (int i = 0; i < prefix.length(); i++) {
+ TrieNode node = currentNode.child.getOrDefault(prefix.charAt(i), null);
+ if (node == null) {
+ return false;
+ }
+
+ currentNode = node;
+ }
+
+ return true;
+ }
+
+ /**
+ * Count the number of words starting with the given prefix in the trie
+ *
+ * @param prefix the prefix to be checked in the Trie
+ * @return count of words
+ */
+ public int countWordsWithPrefix(String prefix) {
+ TrieNode currentNode = root;
+
+ for (int i = 0; i < prefix.length(); i++) {
+ TrieNode node = currentNode.child.getOrDefault(prefix.charAt(i), null);
+ if (node == null) {
+ return 0;
+ }
+
+ currentNode = node;
+ }
+
+ return countWords(currentNode);
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java b/src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java
similarity index 69%
rename from src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java
rename to src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java
index 600fdef0a718..9348118bb343 100644
--- a/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java
+++ b/src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java
@@ -1,17 +1,21 @@
package com.thealgorithms.datastructures.trees;
+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.BeforeEach;
import org.junit.jupiter.api.Test;
-public class TrieImpTest {
- private TrieImp trie;
+public class TrieTest {
+ private static final List WORDS = List.of("Apple", "App", "app", "APPLE");
+
+ private Trie trie;
@BeforeEach
public void setUp() {
- trie = new TrieImp();
+ trie = new Trie();
}
@Test
@@ -66,11 +70,26 @@ public void testInsertAndSearchPrefix() {
}
@Test
- public void testIsValidWord() {
- assertTrue(TrieImp.isValid("validword"), "Word should be valid (only lowercase letters).");
- assertFalse(TrieImp.isValid("InvalidWord"), "Word should be invalid (contains uppercase letters).");
- assertFalse(TrieImp.isValid("123abc"), "Word should be invalid (contains numbers).");
- assertFalse(TrieImp.isValid("hello!"), "Word should be invalid (contains special characters).");
- assertFalse(TrieImp.isValid(""), "Empty string should be invalid.");
+ public void testCountWords() {
+ Trie trie = createTrie();
+ assertEquals(WORDS.size(), trie.countWords(), "Count words should return the correct number of words.");
+ }
+
+ @Test
+ public void testStartsWithPrefix() {
+ Trie trie = createTrie();
+ assertTrue(trie.startsWithPrefix("App"), "Starts with prefix should return true.");
+ }
+
+ @Test
+ public void testCountWordsWithPrefix() {
+ Trie trie = createTrie();
+ assertEquals(2, trie.countWordsWithPrefix("App"), "Count words with prefix should return 2.");
+ }
+
+ private Trie createTrie() {
+ Trie trie = new Trie();
+ WORDS.forEach(trie::insert);
+ return trie;
}
}
From bd9e324e8c522032cabc0b7c267df7d53ad77b91 Mon Sep 17 00:00:00 2001
From: Sailok Chinta
Date: Tue, 8 Oct 2024 02:47:45 +0530
Subject: [PATCH 007/348] Add QuadraticEquationSolver and test cases (#5619)
---
DIRECTORY.md | 1 +
.../maths/QuadraticEquationSolver.java | 60 +++++++++++++++++++
.../maths/QuadraticEquationSolverTest.java | 50 ++++++++++++++++
3 files changed, 111 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java
create mode 100644 src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index ad337f35fc8f..1cd30a336f24 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -377,6 +377,7 @@
* [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeFactorization.java)
* [PronicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PronicNumber.java)
* [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java)
+ * [QuadraticEquationSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java)
* [ReverseNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ReverseNumber.java)
* [RomanNumeralUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/RomanNumeralUtil.java)
* [SecondMinMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SecondMinMax.java)
diff --git a/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java b/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java
new file mode 100644
index 000000000000..cd654c5dc023
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java
@@ -0,0 +1,60 @@
+package com.thealgorithms.maths;
+
+/**
+ * This class represents a complex number which has real and imaginary part
+ */
+class ComplexNumber {
+ Double real;
+ Double imaginary;
+
+ ComplexNumber(double real, double imaginary) {
+ this.real = real;
+ this.imaginary = imaginary;
+ }
+
+ ComplexNumber(double real) {
+ this.real = real;
+ this.imaginary = null;
+ }
+}
+
+/**
+ * Quadratic Equation Formula is used to find
+ * the roots of a quadratic equation of the form ax^2 + bx + c = 0
+ *
+ * @see Quadratic Equation
+ */
+public class QuadraticEquationSolver {
+ /**
+ * Function takes in the coefficients of the quadratic equation
+ *
+ * @param a is the coefficient of x^2
+ * @param b is the coefficient of x
+ * @param c is the constant
+ * @return roots of the equation which are ComplexNumber type
+ */
+ public ComplexNumber[] solveEquation(double a, double b, double c) {
+ double discriminant = b * b - 4 * a * c;
+
+ // if discriminant is positive, roots will be different
+ if (discriminant > 0) {
+ return new ComplexNumber[] {new ComplexNumber((-b + Math.sqrt(discriminant)) / (2 * a)), new ComplexNumber((-b - Math.sqrt(discriminant)) / (2 * a))};
+ }
+
+ // if discriminant is zero, roots will be same
+ if (discriminant == 0) {
+ return new ComplexNumber[] {new ComplexNumber((-b) / (2 * a))};
+ }
+
+ // if discriminant is negative, roots will have imaginary parts
+ if (discriminant < 0) {
+ double realPart = -b / (2 * a);
+ double imaginaryPart = Math.sqrt(-discriminant) / (2 * a);
+
+ return new ComplexNumber[] {new ComplexNumber(realPart, imaginaryPart), new ComplexNumber(realPart, -imaginaryPart)};
+ }
+
+ // return no roots
+ return new ComplexNumber[] {};
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
new file mode 100644
index 000000000000..a2046511ddf5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java
@@ -0,0 +1,50 @@
+package com.thealgorithms.maths;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class QuadraticEquationSolverTest {
+ private final QuadraticEquationSolver quadraticEquationSolver = new QuadraticEquationSolver();
+
+ @Test
+ public void testSolveEquationRealRoots() {
+ // 4.2x^2 + 8x + 1.9 = 0
+ double a = 4.2;
+ double b = 8;
+ double c = 1.9;
+
+ ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
+ Assertions.assertEquals(roots.length, 2);
+ Assertions.assertEquals(roots[0].real, -0.27810465435684306);
+ Assertions.assertNull(roots[0].imaginary);
+ Assertions.assertEquals(roots[1].real, -1.6266572504050616);
+ Assertions.assertNull(roots[1].imaginary);
+ }
+
+ @Test
+ public void testSolveEquationEqualRoots() {
+ // x^2 + 2x + 1 = 0
+ double a = 1;
+ double b = 2;
+ double c = 1;
+
+ ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
+ Assertions.assertEquals(roots.length, 1);
+ Assertions.assertEquals(roots[0].real, -1);
+ }
+
+ @Test
+ public void testSolveEquationComplexRoots() {
+ // 2.3x^2 + 4x + 5.6 = 0
+ double a = 2.3;
+ double b = 4;
+ double c = 5.6;
+
+ ComplexNumber[] roots = quadraticEquationSolver.solveEquation(a, b, c);
+ Assertions.assertEquals(roots.length, 2);
+ Assertions.assertEquals(roots[0].real, -0.8695652173913044);
+ Assertions.assertEquals(roots[0].imaginary, 1.2956229935435948);
+ Assertions.assertEquals(roots[1].real, -0.8695652173913044);
+ Assertions.assertEquals(roots[1].imaginary, -1.2956229935435948);
+ }
+}
From 9fb819235643b8a6afa392b65e72a46036c4c210 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 02:54:57 +0530
Subject: [PATCH 008/348] Add QueueByTwoStacks algorithm (#5623)
---
DIRECTORY.md | 7 +-
.../queues/QueueByTwoStacks.java | 87 +++++++++++++++++++
.../queues/QueueByTwoStacksTest.java | 69 +++++++++++++++
3 files changed, 162 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 1cd30a336f24..228735aa8ea9 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -170,6 +170,7 @@
* [LinkedQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/LinkedQueue.java)
* [PriorityQueues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java)
* [Queue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/Queue.java)
+ * [QueueByTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java)
* stacks
* [NodeStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java)
* [ReverseStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/ReverseStack.java)
@@ -477,6 +478,7 @@
* searches
* [BinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BinarySearch.java)
* [BinarySearch2dArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java)
+ * [BM25InvertedIndex](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java)
* [BreadthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java)
* [DepthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/DepthFirstSearch.java)
* [ExponentalSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/ExponentalSearch.java)
@@ -731,6 +733,7 @@
* [GenericArrayListQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/GenericArrayListQueueTest.java)
* [LinkedQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/LinkedQueueTest.java)
* [PriorityQueuesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java)
+ * [QueueByTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java)
* [QueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java)
* stacks
* [LinkedListStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/LinkedListStackTest.java)
@@ -756,7 +759,7 @@
* [SplayTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java)
* [TreapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java)
* [TreeTestUtils](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java)
- * [TrieImpTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TrieImpTest.java)
+ * [TrieTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java)
* [VerticalOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java)
* [ZigzagTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java)
* divideandconquer
@@ -887,6 +890,7 @@
* [PrimeFactorizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java)
* [PronicNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PronicNumberTest.java)
* [PythagoreanTripleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java)
+ * [QuadraticEquationSolverTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java)
* [ReverseNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ReverseNumberTest.java)
* [SecondMinMaxTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java)
* [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java)
@@ -952,6 +956,7 @@
* [SRTFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SRTFSchedulingTest.java)
* searches
* [BinarySearch2dArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java)
+ * [BM25InvertedIndexTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java)
* [BreadthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java)
* [DepthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java)
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java b/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java
new file mode 100644
index 000000000000..11e5e9b83892
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java
@@ -0,0 +1,87 @@
+package com.thealgorithms.datastructures.queues;
+
+import java.util.NoSuchElementException;
+import java.util.Stack;
+
+/**
+ * A queue implementation using two stacks. This class provides methods to
+ * enqueue (add) elements to the end of the queue and dequeue (remove)
+ * elements from the front, while utilizing two internal stacks to manage
+ * the order of elements.
+ *
+ * @param The type of elements held in this queue.
+ */
+public class QueueByTwoStacks {
+
+ private final Stack enqueueStk;
+ private final Stack dequeueStk;
+
+ /**
+ * Constructor that initializes two empty stacks for the queue.
+ * The `enqueueStk` is used to push elements when enqueuing, and
+ * the `dequeueStk` is used to pop elements when dequeuing.
+ */
+ public QueueByTwoStacks() {
+ enqueueStk = new Stack<>();
+ dequeueStk = new Stack<>();
+ }
+
+ /**
+ * Adds an element to the end of the queue. This method pushes the element
+ * onto the `enqueueStk`.
+ *
+ * @param item The element to be added to the queue.
+ */
+ public void put(T item) {
+ enqueueStk.push(item);
+ }
+
+ /**
+ * Removes and returns the element at the front of the queue.
+ * If `dequeueStk` is empty, it transfers all elements from
+ * `enqueueStk` to `dequeueStk` to maintain the correct FIFO
+ * (First-In-First-Out) order before popping.
+ *
+ * @return The element at the front of the queue.
+ * @throws NoSuchElementException If the queue is empty.
+ */
+ public T get() {
+ if (dequeueStk.isEmpty()) {
+ while (!enqueueStk.isEmpty()) {
+ dequeueStk.push(enqueueStk.pop());
+ }
+ }
+ if (dequeueStk.isEmpty()) {
+ throw new NoSuchElementException("Queue is empty");
+ }
+ return dequeueStk.pop();
+ }
+
+ /**
+ * Returns the total number of elements currently in the queue.
+ * This is the sum of the sizes of both stacks.
+ *
+ * @return The number of elements in the queue.
+ */
+ public int size() {
+ return enqueueStk.size() + dequeueStk.size();
+ }
+
+ /**
+ * Returns a string representation of the queue, showing the elements
+ * in the correct order (from front to back).
+ * The `dequeueStk` is first cloned, and then all elements from the
+ * `enqueueStk` are added to the cloned stack in reverse order to
+ * represent the queue accurately.
+ *
+ * @return A string representation of the queue.
+ */
+ @Override
+ public String toString() {
+ Stack tempStack = (Stack) dequeueStk.clone();
+ while (!enqueueStk.isEmpty()) {
+ tempStack.push(enqueueStk.pop());
+ }
+ return "Queue(" + tempStack + ")";
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java b/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java
new file mode 100644
index 000000000000..87f136a84631
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.datastructures.queues;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.NoSuchElementException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class QueueByTwoStacksTest {
+
+ private QueueByTwoStacks queue;
+
+ @BeforeEach
+ public void setUp() {
+ queue = new QueueByTwoStacks<>();
+ }
+
+ @Test
+ public void testEmptyQueue() {
+ assertEquals(0, queue.size());
+ }
+
+ @Test
+ public void testEnqueue() {
+ queue.put(10);
+ queue.put(20);
+ assertEquals(2, queue.size());
+ }
+
+ @Test
+ public void testDequeue() {
+ queue.put(10);
+ queue.put(20);
+ queue.put(30);
+ assertEquals(10, queue.get()); // First item out
+ assertEquals(20, queue.get()); // Second item out
+ assertEquals(30, queue.get()); // Third item out
+ }
+
+ @Test
+ public void testInterleavedOperations() {
+ queue.put(10);
+ queue.put(20);
+ assertEquals(10, queue.get()); // Dequeue first item
+ queue.put(30);
+ assertEquals(20, queue.get()); // Dequeue second item
+ assertEquals(30, queue.get()); // Dequeue third item
+ }
+
+ @Test
+ public void testQueueSize() {
+ assertEquals(0, queue.size());
+ queue.put(1);
+ assertEquals(1, queue.size());
+ queue.put(2);
+ queue.put(3);
+ assertEquals(3, queue.size());
+ queue.get();
+ assertEquals(2, queue.size());
+ }
+
+ @Test
+ public void testEmptyQueueException() {
+ assertThrows(NoSuchElementException.class, () -> {
+ queue.get(); // Attempting to dequeue from empty queue
+ });
+ }
+}
From 0b86774991740bc7f0a1071a342279b861683560 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 8 Oct 2024 09:14:21 +0200
Subject: [PATCH 009/348] Chore(deps): bump
org.apache.maven.plugins:maven-surefire-plugin from 3.5.0 to 3.5.1 (#5632)
Chore(deps): bump org.apache.maven.plugins:maven-surefire-plugin
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.0...surefire-3.5.1)
---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index ab12e8ec4082..673be6cd4e36 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,7 +63,7 @@
maven-surefire-plugin
- 3.5.0
+ 3.5.1
From 0d68b655d21d7f8d6a996f64c2e6f5d33eba95b5 Mon Sep 17 00:00:00 2001
From: Tuhinm2002 <75078694+Tuhinm2002@users.noreply.github.com>
Date: Tue, 8 Oct 2024 13:25:34 +0530
Subject: [PATCH 010/348] feat : new dp algo added
`UniqueSubsequenceCount.java` (#5586)
* feat : new algo uniquesubseqcount
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
---------
Co-authored-by: Alex Klymenko
---
.../UniqueSubsequencesCount.java | 98 +++++++++++++++++++
.../UniqueSubsequencesCountTest.java | 15 +++
2 files changed, 113 insertions(+)
create mode 100755 src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
create mode 100755 src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java b/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
new file mode 100755
index 000000000000..8c7ea6179e3f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java
@@ -0,0 +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];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
new file mode 100755
index 000000000000..049804f58b5a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java
@@ -0,0 +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));
+ }
+}
From 136e0e23a4eac52484034ff878d5ec1db6659bbf Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 21:47:56 +0530
Subject: [PATCH 011/348] Add SortStack algorithm (#5624)
---
DIRECTORY.md | 4 +
.../com/thealgorithms/stacks/SortStack.java | 60 +++++++++++++++
.../thealgorithms/stacks/SortStackTest.java | 77 +++++++++++++++++++
3 files changed, 141 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/stacks/SortStack.java
create mode 100644 src/test/java/com/thealgorithms/stacks/SortStackTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 228735aa8ea9..9fb1112924f3 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -267,6 +267,7 @@
* [SumOfSubset](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java)
* [Tribonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Tribonacci.java)
* [UniquePaths](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java)
+ * [UniqueSubsequencesCount](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java)
* [WildcardMatching](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java)
* [WineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java)
* geometry
@@ -566,6 +567,7 @@
* [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java)
* [PostfixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java)
* [PrefixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java)
+ * [SortStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/SortStack.java)
* [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java)
* strings
* [AhoCorasick](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/AhoCorasick.java)
@@ -794,6 +796,7 @@
* [SumOfSubsetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SumOfSubsetTest.java)
* [TribonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/TribonacciTest.java)
* [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java)
+ * [UniqueSubsequencesCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java)
* [WildcardMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
* geometry
* [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java)
@@ -1027,6 +1030,7 @@
* [NextSmallerElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java)
* [PostfixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java)
* [PrefixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java)
+ * [SortStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/SortStackTest.java)
* [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java)
* strings
* [AhoCorasickTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AhoCorasickTest.java)
diff --git a/src/main/java/com/thealgorithms/stacks/SortStack.java b/src/main/java/com/thealgorithms/stacks/SortStack.java
new file mode 100644
index 000000000000..d07d1a5f1dc3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/SortStack.java
@@ -0,0 +1,60 @@
+package com.thealgorithms.stacks;
+
+import java.util.Stack;
+
+/**
+ * A utility class that provides a method to sort a stack using recursion.
+ * The elements are sorted in ascending order, with the largest element at the top.
+ * This algorithm is implemented using only recursion and the original stack,
+ * without utilizing any additional data structures apart from the stack itself.
+ */
+public final class SortStack {
+ private SortStack() {
+ }
+
+ /**
+ * Sorts the given stack in ascending order using recursion.
+ * The sorting is performed such that the largest element ends up on top of the stack.
+ * This method modifies the original stack and does not return a new stack.
+ *
+ * The algorithm works as follows:
+ * 1. Remove the top element.
+ * 2. Recursively sort the remaining stack.
+ * 3. Insert the removed element back into the sorted stack at the correct position.
+ *
+ * @param stack The stack to be sorted, containing Integer elements.
+ * @throws IllegalArgumentException if the stack contains `null` elements.
+ */
+ public static void sortStack(Stack stack) {
+ if (stack.isEmpty()) {
+ return;
+ }
+
+ int top = stack.pop();
+ sortStack(stack);
+ insertInSortedOrder(stack, top);
+ }
+
+ /**
+ * Helper method to insert an element into the correct position in a sorted stack.
+ * This method is called recursively to place the given element into the stack
+ * such that the stack remains sorted in ascending order.
+ *
+ * The element is inserted in such a way that all elements below it are smaller
+ * (if the stack is non-empty), and elements above it are larger, maintaining
+ * the ascending order.
+ *
+ * @param stack The stack in which the element needs to be inserted.
+ * @param element The element to be inserted into the stack in sorted order.
+ */
+ private static void insertInSortedOrder(Stack stack, int element) {
+ if (stack.isEmpty() || element > stack.peek()) {
+ stack.push(element);
+ return;
+ }
+
+ int top = stack.pop();
+ insertInSortedOrder(stack, element);
+ stack.push(top);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/SortStackTest.java b/src/test/java/com/thealgorithms/stacks/SortStackTest.java
new file mode 100644
index 000000000000..b9f2f1b6f106
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/SortStackTest.java
@@ -0,0 +1,77 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Stack;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class SortStackTest {
+
+ private Stack stack;
+
+ @BeforeEach
+ public void setUp() {
+ stack = new Stack<>();
+ }
+
+ @Test
+ public void testSortEmptyStack() {
+ SortStack.sortStack(stack);
+ assertTrue(stack.isEmpty()); // An empty stack should remain empty
+ }
+
+ @Test
+ public void testSortSingleElementStack() {
+ stack.push(10);
+ SortStack.sortStack(stack);
+ assertEquals(1, stack.size());
+ assertEquals(10, (int) stack.peek()); // Single element should remain unchanged
+ }
+
+ @Test
+ public void testSortAlreadySortedStack() {
+ stack.push(1);
+ stack.push(2);
+ stack.push(3);
+ stack.push(4);
+ SortStack.sortStack(stack);
+
+ assertEquals(4, stack.size());
+ assertEquals(4, (int) stack.pop());
+ assertEquals(3, (int) stack.pop());
+ assertEquals(2, (int) stack.pop());
+ assertEquals(1, (int) stack.pop());
+ }
+
+ @Test
+ public void testSortUnsortedStack() {
+ stack.push(3);
+ stack.push(1);
+ stack.push(4);
+ stack.push(2);
+ SortStack.sortStack(stack);
+
+ assertEquals(4, stack.size());
+ assertEquals(4, (int) stack.pop());
+ assertEquals(3, (int) stack.pop());
+ assertEquals(2, (int) stack.pop());
+ assertEquals(1, (int) stack.pop());
+ }
+
+ @Test
+ public void testSortWithDuplicateElements() {
+ stack.push(3);
+ stack.push(1);
+ stack.push(3);
+ stack.push(2);
+ SortStack.sortStack(stack);
+
+ assertEquals(4, stack.size());
+ assertEquals(3, (int) stack.pop());
+ assertEquals(3, (int) stack.pop());
+ assertEquals(2, (int) stack.pop());
+ assertEquals(1, (int) stack.pop());
+ }
+}
From d3bd2874c83a0cb14c564f01d3e45c9b823f4960 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 23:07:10 +0530
Subject: [PATCH 012/348] Add StackUsingTwoQueues algorithm (#5625)
---
DIRECTORY.md | 2 +
.../stacks/StackUsingTwoQueues.java | 91 +++++++++++++++++++
.../stacks/StackUsingTwoQueuesTest.java | 70 ++++++++++++++
3 files changed, 163 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java
create mode 100644 src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 9fb1112924f3..7a1bb728fac2 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -569,6 +569,7 @@
* [PrefixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java)
* [SortStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/SortStack.java)
* [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java)
+ * [StackUsingTwoQueues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java)
* strings
* [AhoCorasick](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/AhoCorasick.java)
* [Alphabetical](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Alphabetical.java)
@@ -1032,6 +1033,7 @@
* [PrefixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java)
* [SortStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/SortStackTest.java)
* [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java)
+ * [StackUsingTwoQueuesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java)
* strings
* [AhoCorasickTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AhoCorasickTest.java)
* [AlphabeticalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java)
diff --git a/src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java b/src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java
new file mode 100644
index 000000000000..5b1ca5d1d5a5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java
@@ -0,0 +1,91 @@
+package com.thealgorithms.stacks;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+
+/**
+ * A class that implements a stack using two queues.
+ * This approach ensures that the stack's LIFO (Last In, First Out) behavior
+ * is maintained by utilizing two queues for storage.
+ * The mainQueue is used to store the elements of the stack, while the tempQueue
+ * is used to temporarily store elements during the push operation.
+ */
+public class StackUsingTwoQueues {
+
+ private Queue mainQueue;
+ private Queue tempQueue;
+
+ /**
+ * Constructs an empty stack using two queues.
+ */
+ public StackUsingTwoQueues() {
+ mainQueue = new LinkedList<>();
+ tempQueue = new LinkedList<>();
+ }
+
+ /**
+ * Pushes an element onto the top of the stack.
+ * The newly pushed element becomes the top of the stack.
+ *
+ * @param item The element to be pushed onto the stack.
+ */
+ public void push(int item) {
+ tempQueue.add(item);
+
+ // Move all elements from the mainQueue to tempQueue to maintain LIFO order
+ while (!mainQueue.isEmpty()) {
+ tempQueue.add(mainQueue.remove());
+ }
+
+ // Swap the names of the two queues
+ Queue swap = mainQueue;
+ mainQueue = tempQueue;
+ tempQueue = swap; // tempQueue is now empty
+ }
+
+ /**
+ * Removes and returns the element at the top of the stack.
+ * Throws an exception if the stack is empty.
+ *
+ * @return The element at the top of the stack.
+ * @throws NoSuchElementException if the stack is empty.
+ */
+ public int pop() {
+ if (mainQueue.isEmpty()) {
+ throw new NoSuchElementException("Stack is empty");
+ }
+ return mainQueue.remove();
+ }
+
+ /**
+ * Returns the element at the top of the stack without removing it.
+ * Returns null if the stack is empty.
+ *
+ * @return The element at the top of the stack, or null if the stack is empty.
+ */
+ public Integer peek() {
+ if (mainQueue.isEmpty()) {
+ return null;
+ }
+ return mainQueue.peek();
+ }
+
+ /**
+ * Returns true if the stack is empty.
+ *
+ * @return true if the stack is empty; false otherwise.
+ */
+ public boolean isEmpty() {
+ return mainQueue.isEmpty();
+ }
+
+ /**
+ * Returns the number of elements in the stack.
+ *
+ * @return The size of the stack.
+ */
+ public int size() {
+ return mainQueue.size();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java b/src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java
new file mode 100644
index 000000000000..a7e24421e682
--- /dev/null
+++ b/src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java
@@ -0,0 +1,70 @@
+package com.thealgorithms.stacks;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class StackUsingTwoQueuesTest {
+
+ private StackUsingTwoQueues stack;
+
+ @BeforeEach
+ public void setUp() {
+ stack = new StackUsingTwoQueues();
+ }
+
+ @Test
+ public void testPushAndPeek() {
+ stack.push(1);
+ stack.push(2);
+ stack.push(3);
+ assertEquals(3, stack.peek());
+ }
+
+ @Test
+ public void testPop() {
+ stack.push(1);
+ stack.push(2);
+ stack.push(3);
+ assertEquals(3, stack.pop());
+ assertEquals(2, stack.pop());
+ assertEquals(1, stack.pop());
+ }
+
+ @Test
+ public void testPeek() {
+ stack.push(10);
+ stack.push(20);
+ assertEquals(20, stack.peek());
+ stack.pop();
+ assertEquals(10, stack.peek());
+ }
+
+ @Test
+ public void testIsEmpty() {
+ assertTrue(stack.isEmpty());
+ stack.push(1);
+ assertFalse(stack.isEmpty());
+ stack.pop();
+ assertTrue(stack.isEmpty());
+ }
+
+ @Test
+ public void testSize() {
+ assertEquals(0, stack.size());
+ stack.push(1);
+ stack.push(2);
+ assertEquals(2, stack.size());
+ stack.pop();
+ assertEquals(1, stack.size());
+ }
+
+ @Test
+ public void testPeekEmptyStack() {
+ assertNull(stack.peek());
+ }
+}
From 435532fb7bd20e7077403ef2fe64b31ce9fc7ae1 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 23:15:17 +0530
Subject: [PATCH 013/348] Add WordPatternMatcher algorithm (#5627)
---
DIRECTORY.md | 2 +
.../backtracking/WordPatternMatcher.java | 86 +++++++++++++++++++
.../backtracking/WordPatternMatcherTest.java | 40 +++++++++
3 files changed, 128 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
create mode 100644 src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 7a1bb728fac2..1b69d17e347d 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -19,6 +19,7 @@
* [Permutation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/Permutation.java)
* [PowerSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/PowerSum.java)
* [SubsequenceFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java)
+ * [WordPatternMatcher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java)
* [WordSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordSearch.java)
* bitmanipulation
* [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
@@ -624,6 +625,7 @@
* [PermutationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/PermutationTest.java)
* [PowerSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/PowerSumTest.java)
* [SubsequenceFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java)
+ * [WordPatternMatcherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java)
* [WordSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordSearchTest.java)
* bitmanipulation
* [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
diff --git a/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
new file mode 100644
index 000000000000..1854cab20a7f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
@@ -0,0 +1,86 @@
+package com.thealgorithms.backtracking;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class to determine if a pattern matches a string using backtracking.
+ *
+ * Example:
+ * Pattern: "abab"
+ * Input String: "JavaPythonJavaPython"
+ * Output: true
+ *
+ * Pattern: "aaaa"
+ * Input String: "JavaJavaJavaJava"
+ * Output: true
+ *
+ * Pattern: "aabb"
+ * Input String: "JavaPythonPythonJava"
+ * Output: false
+ */
+public final class WordPatternMatcher {
+ private WordPatternMatcher() {
+ }
+
+ /**
+ * Determines if the given pattern matches the input string using backtracking.
+ *
+ * @param pattern The pattern to match.
+ * @param inputString The string to match against the pattern.
+ * @return True if the pattern matches the string, False otherwise.
+ */
+ public static boolean matchWordPattern(String pattern, String inputString) {
+ Map patternMap = new HashMap<>();
+ Map strMap = new HashMap<>();
+ return backtrack(pattern, inputString, 0, 0, patternMap, strMap);
+ }
+
+ /**
+ * Backtracking helper function to check if the pattern matches the string.
+ *
+ * @param pattern The pattern string.
+ * @param inputString The string to match against the pattern.
+ * @param patternIndex Current index in the pattern.
+ * @param strIndex Current index in the input string.
+ * @param patternMap Map to store pattern characters to string mappings.
+ * @param strMap Map to store string to pattern character mappings.
+ * @return True if the pattern matches, False otherwise.
+ */
+ private static boolean backtrack(String pattern, String inputString, int patternIndex, int strIndex, Map patternMap, Map strMap) {
+ if (patternIndex == pattern.length() && strIndex == inputString.length()) {
+ return true;
+ }
+ if (patternIndex == pattern.length() || strIndex == inputString.length()) {
+ return false;
+ }
+
+ char currentChar = pattern.charAt(patternIndex);
+ if (patternMap.containsKey(currentChar)) {
+ String mappedStr = patternMap.get(currentChar);
+ if (inputString.startsWith(mappedStr, strIndex)) {
+ return backtrack(pattern, inputString, patternIndex + 1, strIndex + mappedStr.length(), patternMap, strMap);
+ } else {
+ return false;
+ }
+ }
+
+ for (int end = strIndex + 1; end <= inputString.length(); end++) {
+ String substring = inputString.substring(strIndex, end);
+ if (strMap.containsKey(substring)) {
+ continue;
+ }
+
+ patternMap.put(currentChar, substring);
+ strMap.put(substring, currentChar);
+ if (backtrack(pattern, inputString, patternIndex + 1, end, patternMap, strMap)) {
+ return true;
+ }
+
+ patternMap.remove(currentChar);
+ strMap.remove(substring);
+ }
+
+ return false;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java b/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java
new file mode 100644
index 000000000000..4d56be566035
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java
@@ -0,0 +1,40 @@
+package com.thealgorithms.backtracking;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class WordPatternMatcherTest {
+
+ @Test
+ public void testPatternMatchingSuccess() {
+ assertTrue(WordPatternMatcher.matchWordPattern("aba", "GraphTreesGraph"));
+ assertTrue(WordPatternMatcher.matchWordPattern("xyx", "PythonRubyPython"));
+ }
+
+ @Test
+ public void testPatternMatchingFailure() {
+ assertFalse(WordPatternMatcher.matchWordPattern("GG", "PythonJavaPython"));
+ }
+
+ @Test
+ public void testEmptyPatternAndString() {
+ assertTrue(WordPatternMatcher.matchWordPattern("", ""));
+ }
+
+ @Test
+ public void testEmptyPattern() {
+ assertFalse(WordPatternMatcher.matchWordPattern("", "nonempty"));
+ }
+
+ @Test
+ public void testEmptyString() {
+ assertFalse(WordPatternMatcher.matchWordPattern("abc", ""));
+ }
+
+ @Test
+ public void testLongerPatternThanString() {
+ assertFalse(WordPatternMatcher.matchWordPattern("abcd", "abc"));
+ }
+}
From ecd75c0c2eb962b12eb1b03098ed246b521d1ac7 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 23:30:02 +0530
Subject: [PATCH 014/348] Add CrosswordSolver algorithm (#5626)
---
DIRECTORY.md | 2 +
.../backtracking/CrosswordSolver.java | 124 ++++++++++++++++++
.../backtracking/CrosswordSolverTest.java | 66 ++++++++++
3 files changed, 192 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
create mode 100644 src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 1b69d17e347d..7c6f284c9e43 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -10,6 +10,7 @@
* [AllPathsFromSourceToTarget](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java)
* [ArrayCombination](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java)
* [Combination](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/Combination.java)
+ * [CrosswordSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java)
* [FloodFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/FloodFill.java)
* [KnightsTour](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/KnightsTour.java)
* [MazeRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java)
@@ -616,6 +617,7 @@
* [AllPathsFromSourceToTargetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java)
* [ArrayCombinationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java)
* [CombinationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/CombinationTest.java)
+ * [CrosswordSolverTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java)
* [FloodFillTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/FloodFillTest.java)
* [KnightsTourTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/KnightsTourTest.java)
* [MazeRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java)
diff --git a/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
new file mode 100644
index 000000000000..cbd9f70f74f4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
@@ -0,0 +1,124 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class to solve a crossword puzzle using backtracking.
+ * Example:
+ * Input:
+ * puzzle = {
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '}
+ * }
+ * words = List.of("cat", "dog")
+ *
+ * Output:
+ * {
+ * {'c', 'a', 't'},
+ * {' ', ' ', ' '},
+ * {'d', 'o', 'g'}
+ * }
+ */
+public final class CrosswordSolver {
+ private CrosswordSolver() {
+ }
+
+ /**
+ * Checks if a word can be placed at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word might be placed.
+ * @param col The column index where the word might be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ * @return true if the word can be placed, false otherwise.
+ */
+ public static boolean isValid(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ if (row + i >= puzzle.length || puzzle[row + i][col] != ' ') {
+ return false;
+ }
+ } else {
+ if (col + i >= puzzle[0].length || puzzle[row][col + i] != ' ') {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Places a word at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word will be placed.
+ * @param col The column index where the word will be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ */
+ public static void placeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = word.charAt(i);
+ } else {
+ puzzle[row][col + i] = word.charAt(i);
+ }
+ }
+ }
+
+ /**
+ * Removes a word from the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be removed.
+ * @param row The row index where the word is placed.
+ * @param col The column index where the word is placed.
+ * @param vertical If true, the word was placed vertically; otherwise, horizontally.
+ */
+ public static void removeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = ' ';
+ } else {
+ puzzle[row][col + i] = ' ';
+ }
+ }
+ }
+
+ /**
+ * Solves the crossword puzzle using backtracking.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param words The list of words to be placed.
+ * @return true if the crossword is solved, false otherwise.
+ */
+ public static boolean solveCrossword(char[][] puzzle, List words) {
+ // Create a mutable copy of the words list
+ List remainingWords = new ArrayList<>(words);
+
+ for (int row = 0; row < puzzle.length; row++) {
+ for (int col = 0; col < puzzle[0].length; col++) {
+ if (puzzle[row][col] == ' ') {
+ for (String word : new ArrayList<>(remainingWords)) {
+ for (boolean vertical : new boolean[] {true, false}) {
+ if (isValid(puzzle, word, row, col, vertical)) {
+ placeWord(puzzle, word, row, col, vertical);
+ remainingWords.remove(word);
+ if (solveCrossword(puzzle, remainingWords)) {
+ return true;
+ }
+ remainingWords.add(word);
+ removeWord(puzzle, word, row, col, vertical);
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java b/src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java
new file mode 100644
index 000000000000..542fd53fe5ed
--- /dev/null
+++ b/src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java
@@ -0,0 +1,66 @@
+package com.thealgorithms.backtracking;
+
+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.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+public class CrosswordSolverTest {
+
+ @Test
+ public void testValidPlacement() {
+ char[][] puzzle = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};
+ assertTrue(CrosswordSolver.isValid(puzzle, "cat", 0, 0, true));
+ assertTrue(CrosswordSolver.isValid(puzzle, "dog", 0, 0, false));
+ assertFalse(CrosswordSolver.isValid(puzzle, "cat", 1, 2, false));
+ }
+
+ @Test
+ public void testPlaceAndRemoveWord() {
+ char[][] puzzle = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};
+ CrosswordSolver.placeWord(puzzle, "cat", 0, 0, true);
+ assertEquals('c', puzzle[0][0]);
+ assertEquals('a', puzzle[1][0]);
+ assertEquals('t', puzzle[2][0]);
+
+ CrosswordSolver.removeWord(puzzle, "cat", 0, 0, true);
+ assertEquals(' ', puzzle[0][0]);
+ assertEquals(' ', puzzle[1][0]);
+ assertEquals(' ', puzzle[2][0]);
+ }
+
+ @Test
+ public void testSolveCrossword() {
+ char[][] puzzle = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};
+ List words = Arrays.asList("cat", "dog", "car");
+ assertTrue(CrosswordSolver.solveCrossword(puzzle, words));
+
+ /* Solved crossword:
+ * c d c
+ * a o a
+ * t g r
+ */
+
+ assertEquals('c', puzzle[0][0]);
+ assertEquals('a', puzzle[1][0]);
+ assertEquals('t', puzzle[2][0]);
+
+ assertEquals('d', puzzle[0][1]);
+ assertEquals('o', puzzle[1][1]);
+ assertEquals('g', puzzle[2][1]);
+
+ assertEquals('c', puzzle[0][2]);
+ assertEquals('a', puzzle[1][2]);
+ assertEquals('r', puzzle[2][2]);
+ }
+
+ @Test
+ public void testNoSolution() {
+ char[][] puzzle = {{' ', ' ', ' '}, {' ', ' ', ' '}, {' ', ' ', ' '}};
+ List words = Arrays.asList("cat", "dog", "elephant"); // 'elephant' is too long for the grid
+ assertFalse(CrosswordSolver.solveCrossword(puzzle, words));
+ }
+}
From d437d581f4d280f632e663fc528e0a9c2605cbf4 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Tue, 8 Oct 2024 23:37:46 +0530
Subject: [PATCH 015/348] Remove `print` & `main` methods (#5584)
---
DIRECTORY.md | 1 +
.../datastructures/graphs/FloydWarshall.java | 79 +++++++++++--------
.../graphs/FloydWarshallTest.java | 33 ++++++++
3 files changed, 81 insertions(+), 32 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 7c6f284c9e43..6042dd1b5e0d 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -709,6 +709,7 @@
* [BoruvkaAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java)
* [DijkstraAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java)
* [EdmondsBlossomAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java)
+ * [FloydWarshallTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java)
* [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java)
* [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java)
* [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java b/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java
index d47ffe3aa27d..66dc6782a8be 100644
--- a/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java
@@ -1,21 +1,46 @@
package com.thealgorithms.datastructures.graphs;
-import java.util.Scanner;
-
+/**
+ * The {@code FloydWarshall} class provides an implementation of the Floyd-Warshall algorithm
+ * to compute the shortest paths between all pairs of vertices in a weighted graph.
+ * It handles both positive and negative edge weights but does not support negative cycles.
+ * The algorithm is based on dynamic programming and runs in O(V^3) time complexity,
+ * where V is the number of vertices in the graph.
+ *
+ *
+ * The distance matrix is updated iteratively to find the shortest distance between any two vertices
+ * by considering each vertex as an intermediate step.
+ *
+ *
+ * Reference: Floyd-Warshall Algorithm
+ */
public class FloydWarshall {
private int[][] distanceMatrix;
- private int numberofvertices; // number of vertices in the graph
+ private int numberofvertices;
public static final int INFINITY = 999;
+ /**
+ * Constructs a Floyd-Warshall instance for a graph with the given number of vertices.
+ * Initializes the distance matrix for the graph.
+ *
+ * @param numberofvertices The number of vertices in the graph.
+ */
public FloydWarshall(int numberofvertices) {
- distanceMatrix = new int[numberofvertices + 1][numberofvertices + 1]; // stores the value of distance from all the possible path form the source
- // vertex to destination vertex
+ distanceMatrix = new int[numberofvertices + 1][numberofvertices + 1];
// The matrix is initialized with 0's by default
this.numberofvertices = numberofvertices;
}
- public void floydwarshall(int[][] adjacencyMatrix) { // calculates all the distances from source to destination vertex
+ /**
+ * Executes the Floyd-Warshall algorithm to compute the shortest path between all pairs of vertices.
+ * It uses an adjacency matrix to calculate the distance matrix by considering each vertex as an intermediate point.
+ *
+ * @param adjacencyMatrix The weighted adjacency matrix representing the graph.
+ * A value of 0 means no direct edge between the vertices, except for diagonal elements which are 0 (distance to self).
+ */
+ public void floydwarshall(int[][] adjacencyMatrix) {
+ // Initialize the distance matrix with the adjacency matrix.
for (int source = 1; source <= numberofvertices; source++) {
for (int destination = 1; destination <= numberofvertices; destination++) {
distanceMatrix[source][destination] = adjacencyMatrix[source][destination];
@@ -24,19 +49,29 @@ public void floydwarshall(int[][] adjacencyMatrix) { // calculates all the dista
for (int intermediate = 1; intermediate <= numberofvertices; intermediate++) {
for (int source = 1; source <= numberofvertices; source++) {
for (int destination = 1; destination <= numberofvertices; destination++) {
- if (distanceMatrix[source][intermediate] + distanceMatrix[intermediate][destination] < distanceMatrix[source][destination]) { // calculated distance it get replaced as
- // new shortest distance // if the new
- // distance calculated is less then the
- // earlier shortest
+ // Update distance if a shorter path through the intermediate vertex exists.
+ if (distanceMatrix[source][intermediate] + distanceMatrix[intermediate][destination] < distanceMatrix[source][destination]) {
distanceMatrix[source][destination] = distanceMatrix[source][intermediate] + distanceMatrix[intermediate][destination];
}
}
}
}
+
+ printDistanceMatrix();
+ }
+
+ /**
+ * Prints the distance matrix representing the shortest paths between all pairs of vertices.
+ * The rows and columns correspond to the source and destination vertices.
+ */
+ private void printDistanceMatrix() {
+ // Print header for vertices
for (int source = 1; source <= numberofvertices; source++) {
System.out.print("\t" + source);
}
System.out.println();
+
+ // Print the distance matrix
for (int source = 1; source <= numberofvertices; source++) {
System.out.print(source + "\t");
for (int destination = 1; destination <= numberofvertices; destination++) {
@@ -46,27 +81,7 @@ public void floydwarshall(int[][] adjacencyMatrix) { // calculates all the dista
}
}
- public static void main(String... arg) {
- Scanner scan = new Scanner(System.in);
- System.out.println("Enter the number of vertices");
- int numberOfVertices = scan.nextInt();
- int[][] adjacencyMatrix = new int[numberOfVertices + 1][numberOfVertices + 1];
- System.out.println("Enter the Weighted Matrix for the graph");
- for (int source = 1; source <= numberOfVertices; source++) {
- for (int destination = 1; destination <= numberOfVertices; destination++) {
- adjacencyMatrix[source][destination] = scan.nextInt();
- if (source == destination) {
- adjacencyMatrix[source][destination] = 0;
- continue;
- }
- if (adjacencyMatrix[source][destination] == 0) {
- adjacencyMatrix[source][destination] = INFINITY;
- }
- }
- }
- System.out.println("The Transitive Closure of the Graph");
- FloydWarshall floydwarshall = new FloydWarshall(numberOfVertices);
- floydwarshall.floydwarshall(adjacencyMatrix);
- scan.close();
+ public Object[] getDistanceMatrix() {
+ return distanceMatrix;
}
}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java
new file mode 100644
index 000000000000..7d6a2b239f4b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+class FloydWarshallTest {
+
+ @Test
+ void testSmallGraph() {
+ int[][] adjacencyMatrix = {{0, 0, 0, 0}, // Ignored row (0 index)
+ {0, 0, 3, FloydWarshall.INFINITY}, {0, FloydWarshall.INFINITY, 0, 1}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0}};
+
+ FloydWarshall fw = new FloydWarshall(3);
+ fw.floydwarshall(adjacencyMatrix);
+
+ int[][] expectedDistanceMatrix = {{0, 0, 0, 0}, {0, 0, 3, 4}, {0, FloydWarshall.INFINITY, 0, 1}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0}};
+
+ assertArrayEquals(expectedDistanceMatrix, fw.getDistanceMatrix());
+ }
+
+ @Test
+ void testLargerGraph() {
+ int[][] adjacencyMatrix = {{0, 0, 0, 0, 0}, {0, 0, 1, FloydWarshall.INFINITY, 2}, {0, FloydWarshall.INFINITY, 0, 4, FloydWarshall.INFINITY}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0, 3}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0}};
+
+ FloydWarshall fw = new FloydWarshall(4);
+ fw.floydwarshall(adjacencyMatrix);
+
+ int[][] expectedDistanceMatrix = {{0, 0, 0, 0, 0}, {0, 0, 1, 5, 2}, {0, FloydWarshall.INFINITY, 0, 4, 7}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0, 3}, {0, FloydWarshall.INFINITY, FloydWarshall.INFINITY, FloydWarshall.INFINITY, 0}};
+
+ assertArrayEquals(expectedDistanceMatrix, fw.getDistanceMatrix());
+ }
+}
From f3b2a94e74ab00fa32f2fc64a01955e49fddc405 Mon Sep 17 00:00:00 2001
From: Manish Raj <2200032955@kluniversity.in>
Date: Tue, 8 Oct 2024 23:59:29 +0530
Subject: [PATCH 016/348] Improve power sum algorithm (#5652)
* Update directory
* Improve PowerSum algorithm implementation and documentation
This commit enhances the PowerSum class in the backtracking package. The changes focus on improving code quality, readability, and documentation. Key improvements include:
1. Enhanced code structure and efficiency:
- Removed class-level variables for better thread safety
- Optimized the recursive approach to avoid unnecessary calculations
- Simplified the overall logic for easier understanding
2. Improved readability:
- Used more descriptive variable names (e.g., 'targetSum' instead of 'n', 'power' instead of 'x')
- Enhanced method structure with a private recursive helper method
3. Better documentation:
- Added comprehensive JavaDoc comments explaining the algorithm's purpose and implementation
- Clarified the meaning of parameters, especially relating them to the original problem statement (N and X)
- Improved inline comments for better code understanding
4. Adhered to Java best practices:
- Improved encapsulation by making the recursive method private
- Used Math.pow() directly instead of a custom power method
5. Maintained core functionality:
- The algorithm still solves the same problem as before, but with improved code quality
* updated PowerSum
* Refactor PowerSum algorithm implementation and documentation
* Refactor PowerSum algorithm implementation and documentation
* Refactor code formatting and remove unnecessary line in PowerSum.java
* Refactor code formatting and add newline at end of file in .clang-format
---------
Co-authored-by: manishraj27
Co-authored-by: Bama Charan Chhandogi
---
.../thealgorithms/backtracking/PowerSum.java | 72 ++++++++++---------
1 file changed, 39 insertions(+), 33 deletions(-)
diff --git a/src/main/java/com/thealgorithms/backtracking/PowerSum.java b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
index 6617ea326a1c..b34ba660ebd7 100644
--- a/src/main/java/com/thealgorithms/backtracking/PowerSum.java
+++ b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
@@ -1,45 +1,51 @@
package com.thealgorithms.backtracking;
-/*
- * Problem Statement :
- * Find the number of ways that a given integer, N , can be expressed as the sum of the Xth powers
- * of unique, natural numbers. For example, if N=100 and X=3, we have to find all combinations of
- * unique cubes adding up to 100. The only solution is 1^3+2^3+3^3+4^3. Therefore output will be 1.
+/**
+ * Problem Statement:
+ * Find the number of ways that a given integer, N, can be expressed as the sum of the Xth powers
+ * of unique, natural numbers.
+ * For example, if N=100 and X=3, we have to find all combinations of unique cubes adding up to 100.
+ * The only solution is 1^3 + 2^3 + 3^3 + 4^3. Therefore, the output will be 1.
+ *
+ * N is represented by the parameter 'targetSum' in the code.
+ * X is represented by the parameter 'power' in the code.
*/
public class PowerSum {
- private int count = 0;
- private int sum = 0;
-
- public int powSum(int n, int x) {
- sum(n, x, 1);
- return count;
+ /**
+ * Calculates the number of ways to express the target sum as a sum of Xth powers of unique natural numbers.
+ *
+ * @param targetSum The target sum to achieve (N in the problem statement)
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @return The number of ways to express the target sum
+ */
+ public int powSum(int targetSum, int power) {
+ // Special case: when both targetSum and power are zero
+ if (targetSum == 0 && power == 0) {
+ return 1; // by convention, one way to sum to zero: use nothing
+ }
+ return sumRecursive(targetSum, power, 1, 0);
}
- // here i is the natural number which will be raised by X and added in sum.
- public void sum(int n, int x, int i) {
- // if sum is equal to N that is one of our answer and count is increased.
- if (sum == n) {
- count++;
- return;
- } // we will be adding next natural number raised to X only if on adding it in sum the
- // result is less than N.
- else if (sum + power(i, x) <= n) {
- sum += power(i, x);
- sum(n, x, i + 1);
- // backtracking and removing the number added last since no possible combination is
- // there with it.
- sum -= power(i, x);
+ /**
+ * Recursively calculates the number of ways to express the remaining sum as a sum of Xth powers.
+ *
+ * @param remainingSum The remaining sum to achieve
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @param currentNumber The current natural number being considered
+ * @param currentSum The current sum of powered numbers
+ * @return The number of valid combinations
+ */
+ private int sumRecursive(int remainingSum, int power, int currentNumber, int currentSum) {
+ int newSum = currentSum + (int) Math.pow(currentNumber, power);
+
+ if (newSum == remainingSum) {
+ return 1;
}
- if (power(i, x) < n) {
- // calling the sum function with next natural number after backtracking if when it is
- // raised to X is still less than X.
- sum(n, x, i + 1);
+ if (newSum > remainingSum) {
+ return 0;
}
- }
- // creating a separate power function so that it can be used again and again when required.
- private int power(int a, int b) {
- return (int) Math.pow(a, b);
+ return sumRecursive(remainingSum, power, currentNumber + 1, newSum) + sumRecursive(remainingSum, power, currentNumber + 1, currentSum);
}
}
From b54cc21ade112e20f429964dc86f8543a5605d98 Mon Sep 17 00:00:00 2001
From: Lakshyajeet Singh Goyal
<74810454+DarkMatter-999@users.noreply.github.com>
Date: Wed, 9 Oct 2024 00:12:24 +0530
Subject: [PATCH 017/348] Add NumberAppearingOddTimes algorithm (#5633)
---
.../NumberAppearingOddTimes.java | 21 +++++++++++++++++
.../NumberAppearingOddTimesTest.java | 23 +++++++++++++++++++
2 files changed, 44 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
new file mode 100644
index 000000000000..ce4e1d88da6e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
@@ -0,0 +1,21 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Find the Number Appearing Odd Times in an array
+ * @author Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+
+public final class NumberAppearingOddTimes {
+ private NumberAppearingOddTimes() {
+ }
+ public static int findOddOccurrence(int[] arr) {
+ int result = 0;
+
+ // XOR all elements in the array
+ for (int num : arr) {
+ result ^= num;
+ }
+
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java b/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java
new file mode 100644
index 000000000000..d10b0f67b806
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java
@@ -0,0 +1,23 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class NumberAppearingOddTimesTest {
+
+ @Test
+ void testFindOddOccurrence() {
+ int[] arr1 = {5, 6, 7, 8};
+ assertEquals(12, NumberAppearingOddTimes.findOddOccurrence(arr1));
+
+ int[] arr2 = {2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2};
+ assertEquals(5, NumberAppearingOddTimes.findOddOccurrence(arr2));
+
+ int[] arr3 = {10, 10, 20, 20, 30};
+ assertEquals(30, NumberAppearingOddTimes.findOddOccurrence(arr3));
+
+ int[] arr4 = {-5, -5, -3, -3, -7, -7, -7};
+ assertEquals(-7, NumberAppearingOddTimes.findOddOccurrence(arr4));
+ }
+}
From 403649d40416916db23ad106a3dc90f051ffb547 Mon Sep 17 00:00:00 2001
From: Albin Sabu <126412402+albinsabu2023@users.noreply.github.com>
Date: Wed, 9 Oct 2024 11:17:47 +0530
Subject: [PATCH 018/348] Update CreateAndDetectLoop with tests (#5561)
---
.../lists/CreateAndDetectLoop.java | 115 +++++++-----------
.../lists/CreateAndDetectLoopTest.java | 71 +++++++++++
2 files changed, 115 insertions(+), 71 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java b/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java
index 441c95702050..49115b2d0f3d 100644
--- a/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java
+++ b/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java
@@ -1,63 +1,66 @@
package com.thealgorithms.datastructures.lists;
-import java.util.Scanner;
-
public final class CreateAndDetectLoop {
+
+ // Node class representing a single node in the linked list
private CreateAndDetectLoop() {
+ throw new UnsupportedOperationException("Utility class");
}
+ static final class Node {
+ int data;
+ Node next;
- /**
- * Prints the linked list.
- *
- * @param head head node of the linked list
- */
- static void printList(Node head) {
- Node cur = head;
-
- while (cur != null) {
- System.out.print(cur.value + " ");
- cur = cur.next;
+ Node(int data) {
+ this.data = data;
+ next = null;
}
}
- /**
- * Creates a loop in the linked list.
- *
- * @see
- *
- * GeeksForGeeks: Make a loop at K-th position
- * @param head head node of the linked list
- * @param k position of node where loop is to be created
+ // Method to create a loop between two specific positions in the linked list
+ /*
+ * Test case that shows the Cycle(loop) in a LinkedList
+ * Let's take this linked list:
+ * 1->2->3->4->5->6
+ * \______/
+ * In this linked list we can see there is a cycle.
+ * we can create loop by calling createLoop function in main after creating LL
+ * createLoop(head,2,5);
+ * to detect there is loop or not we can call detectloop function in main
+ * detectloop(head);
*/
- static void createLoop(Node head, int k) {
- if (head == null) {
+
+ static void createLoop(Node head, int position1, int position2) {
+ if (position1 == 0 || position2 == 0) {
return;
}
- Node temp = head;
- int count = 1;
- while (count < k) { // Traverse the list till the kth node
- temp = temp.next;
- count++;
- }
- Node connectedPoint = temp;
+ Node node1 = head;
+ Node node2 = head;
- while (temp.next != null) { // Traverse remaining nodes
- temp = temp.next;
+ int count1 = 1;
+ int count2 = 1;
+ // Traverse to find node at position1
+ while (count1 < position1 && node1 != null) {
+ node1 = node1.next;
+ count1++;
}
- temp.next = connectedPoint; // Connect last node to k-th element
- }
+ // Traverse to find node at position2
+ while (count2 < position2 && node2 != null) {
+ node2 = node2.next;
+ count2++;
+ }
+ // Create a loop by connecting node2's next to node1
+ if (node1 != null && node2 != null) {
+ node2.next = node1;
+ }
+ }
+ // Method to detect a loop in the linked list
/**
* Detects the presence of a loop in the linked list.
*
- * @see
- *
- * Floyd's Cycle Detection Algorithm
- *
- * @param head the head node of the linked list
- *
+ * @see Floyd's Cycle Detection Algorithm
* @return true if loop exists else false
*/
static boolean detectLoop(Node head) {
@@ -67,40 +70,10 @@ static boolean detectLoop(Node head) {
while (fptr != null && fptr.next != null) {
sptr = sptr.next;
fptr = fptr.next.next;
- if (fptr == sptr) {
+ if (sptr == fptr) {
return true;
}
}
-
return false;
}
-
- public static void main(String[] args) {
- SinglyLinkedList singlyLinkedList = new SinglyLinkedList();
- Scanner sc = new Scanner(System.in);
-
- System.out.println("Enter the number of elements to be inserted: ");
- int n = sc.nextInt();
- System.out.printf("Enter the %d elements: %n", n);
- while (n-- > 0) {
- singlyLinkedList.insert(sc.nextInt());
- }
-
- System.out.print("Given list: ");
- printList(singlyLinkedList.getHead());
- System.out.println();
-
- System.out.println("Enter the location to generate loop: ");
- int k = sc.nextInt();
-
- createLoop(singlyLinkedList.getHead(), k);
-
- if (detectLoop(singlyLinkedList.getHead())) {
- System.out.println("Loop found");
- } else {
- System.out.println("No loop found");
- }
-
- sc.close();
- }
}
diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java
new file mode 100644
index 000000000000..5e9d4c3a2913
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java
@@ -0,0 +1,71 @@
+package com.thealgorithms.datastructures.lists;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class CreateAndDetectLoopTest {
+
+ private CreateAndDetectLoop.Node head;
+
+ @BeforeEach
+ void setUp() {
+ // Create a linked list: 1 -> 2 -> 3 -> 4 -> 5 -> 6
+ head = new CreateAndDetectLoop.Node(1);
+ CreateAndDetectLoop.Node second = new CreateAndDetectLoop.Node(2);
+ CreateAndDetectLoop.Node third = new CreateAndDetectLoop.Node(3);
+ CreateAndDetectLoop.Node fourth = new CreateAndDetectLoop.Node(4);
+ CreateAndDetectLoop.Node fifth = new CreateAndDetectLoop.Node(5);
+ CreateAndDetectLoop.Node sixth = new CreateAndDetectLoop.Node(6);
+
+ head.next = second;
+ second.next = third;
+ third.next = fourth;
+ fourth.next = fifth;
+ fifth.next = sixth;
+ }
+
+ @Test
+ void testDetectLoopNoLoop() {
+ // Test when no loop exists
+ assertFalse(CreateAndDetectLoop.detectLoop(head), "There should be no loop.");
+ }
+
+ @Test
+ void testCreateAndDetectLoopLoopExists() {
+ // Create a loop between position 2 (node with value 2) and position 5 (node with value 5)
+ CreateAndDetectLoop.createLoop(head, 2, 5);
+
+ // Now test if the loop is detected
+ assertTrue(CreateAndDetectLoop.detectLoop(head), "A loop should be detected.");
+ }
+
+ @Test
+ void testCreateLoopInvalidPosition() {
+ // Create loop with invalid positions
+ CreateAndDetectLoop.createLoop(head, 0, 0);
+
+ // Ensure no loop was created
+ assertFalse(CreateAndDetectLoop.detectLoop(head), "There should be no loop with invalid positions.");
+ }
+
+ @Test
+ void testCreateLoopSelfLoop() {
+ // Create a self-loop at position 3 (node with value 3)
+ CreateAndDetectLoop.createLoop(head, 3, 3);
+
+ // Test if the self-loop is detected
+ assertTrue(CreateAndDetectLoop.detectLoop(head), "A self-loop should be detected.");
+ }
+
+ @Test
+ void testCreateLoopNoChangeForNonExistentPositions() {
+ // Create a loop with positions that don't exist in the linked list
+ CreateAndDetectLoop.createLoop(head, 10, 20);
+
+ // Ensure no loop was created
+ assertFalse(CreateAndDetectLoop.detectLoop(head), "No loop should be created if positions are out of bounds.");
+ }
+}
From 5c79e5de5d7fc07d089b3e20a75584c5b6cadbe3 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Wed, 9 Oct 2024 11:26:08 +0530
Subject: [PATCH 019/348] Add MedianOfTwoSortedArrays algorithm (#5554)
---
DIRECTORY.md | 5 ++
.../MedianOfTwoSortedArrays.java | 53 +++++++++++++++++++
.../MedianOfTwoSortedArraysTest.java | 41 ++++++++++++++
3 files changed, 99 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java
create mode 100644 src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 6042dd1b5e0d..af1e4f284445 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -31,6 +31,7 @@
* [IsPowerTwo](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java)
* [LowestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java)
* [NonRepeatingNumberFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java)
+ * [NumberAppearingOddTimes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java)
* [NumbersDifferentSigns](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java)
* [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
* [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
@@ -228,6 +229,7 @@
* divideandconquer
* [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java)
* [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java)
+ * [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java)
* [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java)
* [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java)
* dynamicprogramming
@@ -638,6 +640,7 @@
* [IsPowerTwoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsPowerTwoTest.java)
* [LowestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/LowestSetBitTest.java)
* [NonRepeatingNumberFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java)
+ * [NumberAppearingOddTimesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java)
* [NumbersDifferentSignsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java)
* [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
@@ -729,6 +732,7 @@
* [LeftistHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java)
* lists
* [CircleLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java)
+ * [CreateAndDetectLoopTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java)
* [QuickSortLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/QuickSortLinkedListTest.java)
* [ReverseKGroupTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java)
* [RotateSinglyLinkedListsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java)
@@ -773,6 +777,7 @@
* divideandconquer
* [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java)
* [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java)
+ * [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java)
* [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java)
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
* dynamicprogramming
diff --git a/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java b/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java
new file mode 100644
index 000000000000..d9e51442253c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java
@@ -0,0 +1,53 @@
+package com.thealgorithms.divideandconquer;
+
+public final class MedianOfTwoSortedArrays {
+
+ private MedianOfTwoSortedArrays() {
+ }
+
+ /**
+ * Finds the median of two sorted arrays in logarithmic time.
+ *
+ * @param nums1 the first sorted array
+ * @param nums2 the second sorted array
+ * @return the median of the combined sorted array
+ * @throws IllegalArgumentException if the input arrays are not sorted
+ */
+ public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
+ if (nums1.length > nums2.length) {
+ return findMedianSortedArrays(nums2, nums1); // Ensure nums1 is the smaller array
+ }
+
+ int m = nums1.length;
+ int n = nums2.length;
+ int low = 0;
+ int high = m;
+ while (low <= high) {
+ int partition1 = (low + high) / 2; // Partition in the first array
+ int partition2 = (m + n + 1) / 2 - partition1; // Partition in the second array
+
+ int maxLeft1 = (partition1 == 0) ? Integer.MIN_VALUE : nums1[partition1 - 1];
+ int minRight1 = (partition1 == m) ? Integer.MAX_VALUE : nums1[partition1];
+ int maxLeft2 = (partition2 == 0) ? Integer.MIN_VALUE : nums2[partition2 - 1];
+ int minRight2 = (partition2 == n) ? Integer.MAX_VALUE : nums2[partition2];
+
+ // Check if partition is valid
+ if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
+ // If combined array length is odd
+ if (((m + n) & 1) == 1) {
+ return Math.max(maxLeft1, maxLeft2);
+ }
+ // If combined array length is even
+ else {
+ return (Math.max(maxLeft1, maxLeft2) + Math.min(minRight1, minRight2)) / 2.0;
+ }
+ } else if (maxLeft1 > minRight2) {
+ high = partition1 - 1;
+ } else {
+ low = partition1 + 1;
+ }
+ }
+
+ throw new IllegalArgumentException("Input arrays are not sorted");
+ }
+}
diff --git a/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java b/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java
new file mode 100644
index 000000000000..6cfbc2379600
--- /dev/null
+++ b/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.divideandconquer;
+
+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 MedianOfTwoSortedArraysTest {
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testFindMedianSortedArrays(int[] nums1, int[] nums2, double expectedMedian) {
+ assertEquals(expectedMedian, MedianOfTwoSortedArrays.findMedianSortedArrays(nums1, nums2));
+ }
+
+ private static Stream provideTestCases() {
+ return Stream.of(
+ // Test case 1: Arrays of equal length
+ Arguments.of(new int[] {1, 3}, new int[] {2, 4}, 2.5),
+
+ // Test case 2: Arrays of different lengths
+ Arguments.of(new int[] {1, 3}, new int[] {2}, 2.0),
+
+ // Test case 3: Arrays with even total length
+ Arguments.of(new int[] {1, 2, 8}, new int[] {3, 4, 5, 6, 7}, 4.5),
+
+ // Test case 4: Arrays with odd total length
+ Arguments.of(new int[] {1, 2, 8}, new int[] {3, 4, 5}, 3.5),
+
+ // Test case 5: Single element arrays
+ Arguments.of(new int[] {1}, new int[] {3}, 2.0),
+
+ // Test case 6: Empty arrays
+ Arguments.of(new int[] {}, new int[] {0}, 0.0),
+
+ // Test case 7: Same element arrays
+ Arguments.of(new int[] {2, 2, 2}, new int[] {2, 2, 2}, 2.0));
+ }
+}
From 4bcab89f0500e6ae97eb09638635662d6344d963 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Wed, 9 Oct 2024 12:03:39 +0530
Subject: [PATCH 020/348] Add JobSchedulingWithDeadline algorithm (#5608)
---
DIRECTORY.md | 2 +
.../scheduling/JobSchedulingWithDeadline.java | 88 +++++++++++++++++++
.../JobSchedulingWithDeadlineTest.java | 43 +++++++++
3 files changed, 133 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java
create mode 100644 src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index af1e4f284445..a2f65834b498 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -475,6 +475,7 @@
* scheduling
* [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java)
* [HighestResponseRatioNextScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java)
+ * [JobSchedulingWithDeadline](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java)
* [MLFQScheduler](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/MLFQScheduler.java)
* [PreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java)
* [RRScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/RRScheduling.java)
@@ -963,6 +964,7 @@
* scheduling
* [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java)
* [HighestResponseRatioNextSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java)
+ * [JobSchedulingWithDeadlineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java)
* [MLFQSchedulerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/MLFQSchedulerTest.java)
* [PreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java)
* [RRSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/RRSchedulingTest.java)
diff --git a/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java b/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java
new file mode 100644
index 000000000000..49638d39fc2a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java
@@ -0,0 +1,88 @@
+package com.thealgorithms.scheduling;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A class that implements a job scheduling algorithm to maximize profit
+ * while adhering to job deadlines and arrival times.
+ *
+ * This class provides functionality to schedule jobs based on their profit,
+ * arrival time, and deadlines to ensure that the maximum number of jobs is completed
+ * within the given timeframe. It sorts the jobs in decreasing order of profit
+ * and attempts to assign them to the latest possible time slots.
+ */
+public final class JobSchedulingWithDeadline {
+ private JobSchedulingWithDeadline() {
+ }
+
+ /**
+ * Represents a job with an ID, arrival time, deadline, and profit.
+ *
+ * Each job has a unique identifier, an arrival time (when it becomes available for scheduling),
+ * a deadline by which it must be completed, and a profit associated with completing the job.
+ */
+ static class Job {
+ int jobId;
+ int arrivalTime;
+ int deadline;
+ int profit;
+
+ /**
+ * Constructs a Job instance with the specified job ID, arrival time, deadline, and profit.
+ *
+ * @param jobId Unique identifier for the job
+ * @param arrivalTime Time when the job becomes available for scheduling
+ * @param deadline Deadline for completing the job
+ * @param profit Profit earned upon completing the job
+ */
+ Job(int jobId, int arrivalTime, int deadline, int profit) {
+ this.jobId = jobId;
+ this.arrivalTime = arrivalTime;
+ this.deadline = deadline;
+ this.profit = profit;
+ }
+ }
+
+ /**
+ * Schedules jobs to maximize profit while respecting their deadlines and arrival times.
+ *
+ * This method sorts the jobs in descending order of profit and attempts
+ * to allocate them to time slots that are before or on their deadlines,
+ * provided they have arrived. The function returns an array where the first element
+ * is the total number of jobs scheduled and the second element is the total profit earned.
+ *
+ * @param jobs An array of Job objects, each representing a job with an ID, arrival time,
+ * deadline, and profit.
+ * @return An array of two integers: the first element is the count of jobs
+ * that were successfully scheduled, and the second element is the
+ * total profit earned from those jobs.
+ */
+ public static int[] jobSequencingWithDeadlines(Job[] jobs) {
+ Arrays.sort(jobs, Comparator.comparingInt(job -> - job.profit));
+
+ int maxDeadline = Arrays.stream(jobs).mapToInt(job -> job.deadline).max().orElse(0);
+
+ int[] timeSlots = new int[maxDeadline];
+ Arrays.fill(timeSlots, -1);
+
+ int count = 0;
+ int maxProfit = 0;
+
+ // Schedule the jobs
+ for (Job job : jobs) {
+ if (job.arrivalTime <= job.deadline) {
+ for (int i = Math.min(job.deadline - 1, maxDeadline - 1); i >= job.arrivalTime - 1; i--) {
+ if (timeSlots[i] == -1) {
+ timeSlots[i] = job.jobId;
+ count++;
+ maxProfit += job.profit;
+ break;
+ }
+ }
+ }
+ }
+
+ return new int[] {count, maxProfit};
+ }
+}
diff --git a/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java b/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java
new file mode 100644
index 000000000000..538db92a1f26
--- /dev/null
+++ b/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java
@@ -0,0 +1,43 @@
+package com.thealgorithms.scheduling;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+class JobSchedulingWithDeadlineTest {
+
+ @Test
+ void testJobSequencingWithDeadlines1() {
+ JobSchedulingWithDeadline.Job[] jobs = {new JobSchedulingWithDeadline.Job(1, 1, 4, 20), new JobSchedulingWithDeadline.Job(2, 1, 1, 10), new JobSchedulingWithDeadline.Job(3, 1, 1, 40), new JobSchedulingWithDeadline.Job(4, 1, 1, 30)};
+ int[] result = JobSchedulingWithDeadline.jobSequencingWithDeadlines(jobs);
+ assertArrayEquals(new int[] {2, 60}, result); // Expected output: 2 jobs, 60 profit
+ }
+
+ @Test
+ void testJobSequencingWithDeadlines2() {
+ JobSchedulingWithDeadline.Job[] jobs = {new JobSchedulingWithDeadline.Job(1, 1, 2, 100), new JobSchedulingWithDeadline.Job(2, 1, 1, 19), new JobSchedulingWithDeadline.Job(3, 1, 2, 27), new JobSchedulingWithDeadline.Job(4, 1, 1, 25), new JobSchedulingWithDeadline.Job(5, 1, 1, 15)};
+ int[] result = JobSchedulingWithDeadline.jobSequencingWithDeadlines(jobs);
+ assertArrayEquals(new int[] {2, 127}, result); // Expected output: 2 jobs, 127 profit
+ }
+
+ @Test
+ void testJobSequencingWithDeadlinesWithArrivalTimes() {
+ JobSchedulingWithDeadline.Job[] jobs = {new JobSchedulingWithDeadline.Job(1, 2, 5, 50), new JobSchedulingWithDeadline.Job(2, 3, 4, 60), new JobSchedulingWithDeadline.Job(3, 1, 3, 20)};
+ int[] result = JobSchedulingWithDeadline.jobSequencingWithDeadlines(jobs);
+ assertArrayEquals(new int[] {3, 130}, result); // All 3 jobs fit within their deadlines
+ }
+
+ @Test
+ void testJobSequencingWithDeadlinesNoJobs() {
+ JobSchedulingWithDeadline.Job[] jobs = {};
+ int[] result = JobSchedulingWithDeadline.jobSequencingWithDeadlines(jobs);
+ assertArrayEquals(new int[] {0, 0}, result); // No jobs, 0 profit
+ }
+
+ @Test
+ void testJobSequencingWithDeadlinesSingleJob() {
+ JobSchedulingWithDeadline.Job[] jobs = {new JobSchedulingWithDeadline.Job(1, 1, 1, 50)};
+ int[] result = JobSchedulingWithDeadline.jobSequencingWithDeadlines(jobs);
+ assertArrayEquals(new int[] {1, 50}, result); // 1 job scheduled, 50 profit
+ }
+}
From 49a87d3b58142c51e11b669bc5316a9206776202 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Wed, 9 Oct 2024 12:38:16 +0530
Subject: [PATCH 021/348] Add tests for CountFriendsPairing (#5643)
---
DIRECTORY.md | 1 +
.../CountFriendsPairingTest.java | 50 +++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index a2f65834b498..fc52f313c3f1 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -785,6 +785,7 @@
* [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java)
* [CatalanNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java)
* [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
+ * [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java)
* [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
* [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
* [KnapsackMemoizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java
new file mode 100644
index 000000000000..765daba5f69f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java
@@ -0,0 +1,50 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class CountFriendsPairingTest {
+
+ @Test
+ void testSmallCase() {
+ int n = 5;
+ int[] expectedGolombSequence = {1, 2, 2, 3, 3};
+
+ assertTrue(CountFriendsPairing.countFriendsPairing(n, expectedGolombSequence));
+ }
+
+ @Test
+ void testMismatchSequence() {
+ int n = 5;
+ int[] wrongSequence = {1, 2, 2, 2, 3}; // An incorrect sequence
+
+ assertFalse(CountFriendsPairing.countFriendsPairing(n, wrongSequence));
+ }
+
+ @Test
+ void testLargerCase() {
+ int n = 10;
+ int[] expectedGolombSequence = {1, 2, 2, 3, 3, 4, 4, 4, 5, 5};
+
+ assertTrue(CountFriendsPairing.countFriendsPairing(n, expectedGolombSequence));
+ }
+
+ @Test
+ void testEdgeCaseSingleElement() {
+ int n = 1;
+ int[] expectedGolombSequence = {1};
+
+ assertTrue(CountFriendsPairing.countFriendsPairing(n, expectedGolombSequence));
+ }
+
+ @Test
+ void testEmptySequence() {
+ int n = 0;
+ int[] emptySequence = {};
+
+ // Test the case where n is 0 (should handle this gracefully)
+ assertTrue(CountFriendsPairing.countFriendsPairing(n, emptySequence));
+ }
+}
From 0603accfd480cf6ae33daa644ad0b55e9195f578 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Wed, 9 Oct 2024 13:39:36 +0530
Subject: [PATCH 022/348] Add tests, remove `main` method, improve docs in
BruteForceKnapsack (#5641)
---
DIRECTORY.md | 1 +
.../BruteForceKnapsack.java | 76 ++++++++++-----
.../BruteForceKnapsackTest.java | 96 +++++++++++++++++++
3 files changed, 149 insertions(+), 24 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index fc52f313c3f1..70de110e86ea 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -783,6 +783,7 @@
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
* dynamicprogramming
* [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java)
+ * [BruteForceKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java)
* [CatalanNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java)
* [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
* [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java b/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java
index b433c44b9077..3c1851a8c46c 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java
@@ -1,39 +1,67 @@
package com.thealgorithms.dynamicprogramming;
-/* A Naive recursive implementation
-of 0-1 Knapsack problem */
+/**
+ * A naive recursive implementation of the 0-1 Knapsack problem.
+ *
+ *
The 0-1 Knapsack problem is a classic optimization problem where you are
+ * given a set of items, each with a weight and a value, and a knapsack with a
+ * fixed capacity. The goal is to determine the maximum value that can be
+ * obtained by selecting a subset of the items such that the total weight does
+ * not exceed the knapsack's capacity. Each item can either be included (1) or
+ * excluded (0), hence the name "0-1" Knapsack.
+ *
+ *
This class provides a brute-force recursive approach to solving the
+ * problem. It evaluates all possible combinations of items to find the optimal
+ * solution, but this approach has exponential time complexity and is not
+ * suitable for large input sizes.
+ *
+ *
Time Complexity: O(2^n), where n is the number of items.
+ *
+ *
Space Complexity: O(n), due to the recursive function call stack.
+ */
public final class BruteForceKnapsack {
private BruteForceKnapsack() {
}
- // Returns the maximum value that
- // can be put in a knapsack of
- // capacity W
+
+ /**
+ * Solves the 0-1 Knapsack problem using a recursive brute-force approach.
+ *
+ * @param w the total capacity of the knapsack
+ * @param wt an array where wt[i] represents the weight of the i-th item
+ * @param val an array where val[i] represents the value of the i-th item
+ * @param n the number of items available for selection
+ * @return the maximum value that can be obtained with the given capacity
+ *
+ *
The function uses recursion to explore all possible subsets of items.
+ * For each item, it has two choices: either include it in the knapsack
+ * (if it fits) or exclude it. It returns the maximum value obtainable
+ * through these two choices.
+ *
+ *
Base Cases:
+ *
+ *
If no items are left (n == 0), the maximum value is 0.
+ *
If the knapsack's remaining capacity is 0 (w == 0), no more items can
+ * be included, and the value is 0.
+ *
+ *
+ *
Recursive Steps:
+ *
+ *
If the weight of the n-th item exceeds the current capacity, it is
+ * excluded from the solution, and the function proceeds with the remaining
+ * items.
+ *
Otherwise, the function considers two possibilities: include the n-th
+ * item or exclude it, and returns the maximum value of these two scenarios.
+ *
+ */
static int knapSack(int w, int[] wt, int[] val, int n) {
- // Base Case
if (n == 0 || w == 0) {
return 0;
}
- // If weight of the nth item is
- // more than Knapsack capacity W,
- // then this item cannot be included
- // in the optimal solution
if (wt[n - 1] > w) {
return knapSack(w, wt, val, n - 1);
- } // Return the maximum of two cases:
- // (1) nth item included
- // (2) not included
- else {
- return Math.max(val[n - 1] + knapSack(w - wt[n - 1], wt, val, n - 1), knapSack(w, wt, val, n - 1));
+ } else {
+ return Math.max(knapSack(w, wt, val, n - 1), val[n - 1] + knapSack(w - wt[n - 1], wt, val, n - 1));
}
}
-
- // Driver code
- public static void main(String[] args) {
- int[] val = new int[] {60, 100, 120};
- int[] wt = new int[] {10, 20, 30};
- int w = 50;
- int n = val.length;
- System.out.println(knapSack(w, wt, val, n));
- }
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java
new file mode 100644
index 000000000000..ef96f16e04f7
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java
@@ -0,0 +1,96 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class BruteForceKnapsackTest {
+
+ @Test
+ void testKnapSackBasicCase() {
+ int[] val = {60, 100, 120};
+ int[] wt = {10, 20, 30};
+ int w = 50;
+ int n = val.length;
+
+ // The expected result for this case is 220 (items 2 and 3 are included)
+ assertEquals(220, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackNoItems() {
+ int[] val = {};
+ int[] wt = {};
+ int w = 50;
+ int n = val.length;
+
+ // With no items, the maximum value should be 0
+ assertEquals(0, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackZeroCapacity() {
+ int[] val = {60, 100, 120};
+ int[] wt = {10, 20, 30};
+ int w = 0;
+ int n = val.length;
+
+ // With a knapsack of 0 capacity, no items can be included, so the value is 0
+ assertEquals(0, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackSingleItemFits() {
+ int[] val = {100};
+ int[] wt = {20};
+ int w = 30;
+ int n = val.length;
+
+ // Only one item, and it fits in the knapsack, so the result is 100
+ assertEquals(100, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackSingleItemDoesNotFit() {
+ int[] val = {100};
+ int[] wt = {20};
+ int w = 10;
+ int n = val.length;
+
+ // Single item does not fit in the knapsack, so the result is 0
+ assertEquals(0, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackAllItemsFit() {
+ int[] val = {20, 30, 40};
+ int[] wt = {1, 2, 3};
+ int w = 6;
+ int n = val.length;
+
+ // All items fit into the knapsack, so the result is the sum of all values (20 + 30 + 40 = 90)
+ assertEquals(90, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackNoneFit() {
+ int[] val = {100, 200, 300};
+ int[] wt = {100, 200, 300};
+ int w = 50;
+ int n = val.length;
+
+ // None of the items fit into the knapsack, so the result is 0
+ assertEquals(0, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+
+ @Test
+ void testKnapSackSomeItemsFit() {
+ int[] val = {60, 100, 120};
+ int[] wt = {10, 20, 30};
+ int w = 40;
+ int n = val.length;
+
+ // Here, only the 2nd and 1st items should be included for a total value of 160
+ assertEquals(180, BruteForceKnapsack.knapSack(w, wt, val, n));
+ }
+}
From 2d34bc150fe2e3a64bb750ed1174dac9e96bf46b Mon Sep 17 00:00:00 2001
From: Sanketh L Reddy <97825819+sankethl27@users.noreply.github.com>
Date: Wed, 9 Oct 2024 19:27:11 +0530
Subject: [PATCH 023/348] Optimised Space Complexity To O(sum) (#5651)
* Optimised Space Complexity To O(sum)
* Fixes Clang Format
* Optimised Space Complexity To Use a Single DP Array
---
.../dynamicprogramming/SubsetSum.java | 29 +++++++++----------
1 file changed, 13 insertions(+), 16 deletions(-)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java
index 3dd41d2fdc0f..da8667afd0ce 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java
@@ -9,28 +9,25 @@ private SubsetSum() {
*
* @param arr the array containing integers.
* @param sum the target sum of the subset.
- * @return {@code true} if a subset exists that sums to the given value, otherwise {@code false}.
+ * @return {@code true} if a subset exists that sums to the given value,
+ * otherwise {@code false}.
*/
public static boolean subsetSum(int[] arr, int sum) {
int n = arr.length;
- boolean[][] isSum = new boolean[n + 1][sum + 1];
- // Initialize the first column to true since a sum of 0 can always be achieved with an empty subset.
- for (int i = 0; i <= n; i++) {
- isSum[i][0] = true;
- }
+ // Initialize a single array to store the possible sums
+ boolean[] isSum = new boolean[sum + 1];
+
+ // Mark isSum[0] = true since a sum of 0 is always possible with 0 elements
+ isSum[0] = true;
- // Fill the subset sum matrix
- for (int i = 1; i <= n; i++) {
- for (int j = 1; j <= sum; j++) {
- if (arr[i - 1] <= j) {
- isSum[i][j] = isSum[i - 1][j] || isSum[i - 1][j - arr[i - 1]];
- } else {
- isSum[i][j] = isSum[i - 1][j];
- }
+ // Iterate through each Element in the array
+ for (int i = 0; i < n; i++) {
+ // Traverse the isSum array backwards to prevent overwriting values
+ for (int j = sum; j >= arr[i]; j--) {
+ isSum[j] = isSum[j] || isSum[j - arr[i]];
}
}
-
- return isSum[n][sum];
+ return isSum[sum];
}
}
From 6ddb26f48d79b983a3f8f2509fae4c67aef612f7 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 00:34:04 +0530
Subject: [PATCH 024/348] Add tests, remove `main` & `print` methods in
`CoinChange.java` (#5642)
---
DIRECTORY.md | 1 +
.../dynamicprogramming/CoinChange.java | 22 +----
.../dynamicprogramming/CoinChangeTest.java | 80 +++++++++++++++++++
3 files changed, 82 insertions(+), 21 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 70de110e86ea..0c235b792083 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -786,6 +786,7 @@
* [BruteForceKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java)
* [CatalanNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java)
* [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
+ * [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java)
* [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java)
* [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
* [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java b/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java
index 12cc29faa923..7edc9603dc8b 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java
@@ -7,15 +7,6 @@ public final class CoinChange {
private CoinChange() {
}
- // Driver Program
- public static void main(String[] args) {
- int amount = 12;
- int[] coins = {2, 4, 5};
-
- System.out.println("Number of combinations of getting change for " + amount + " is: " + change(coins, amount));
- System.out.println("Minimum number of coins required for amount :" + amount + " is: " + minimumCoins(coins, amount));
- }
-
/**
* This method finds the number of combinations of getting change for a
* given amount and change coins
@@ -32,8 +23,6 @@ public static int change(int[] coins, int amount) {
for (int i = coin; i < amount + 1; i++) {
combinations[i] += combinations[i - coin];
}
- // Uncomment the below line to see the state of combinations for each coin
- // printAmount(combinations);
}
return combinations[amount];
@@ -65,16 +54,7 @@ public static int minimumCoins(int[] coins, int amount) {
}
}
}
- // Uncomment the below line to see the state of combinations for each coin
- // printAmount(minimumCoins);
- return minimumCoins[amount];
- }
- // A basic print method which prints all the contents of the array
- public static void printAmount(int[] arr) {
- for (int i = 0; i < arr.length; i++) {
- System.out.print(arr[i] + " ");
- }
- System.out.println();
+ return minimumCoins[amount];
}
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java
new file mode 100644
index 000000000000..10bc6600ae1e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java
@@ -0,0 +1,80 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class CoinChangeTest {
+
+ @Test
+ void testChangeBasic() {
+ int amount = 12;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(5, CoinChange.change(coins, amount));
+ }
+
+ @Test
+ void testChangeNoCoins() {
+ int amount = 12;
+ int[] coins = {};
+
+ assertEquals(0, CoinChange.change(coins, amount));
+ }
+
+ @Test
+ void testChangeNoAmount() {
+ int amount = 0;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(1, CoinChange.change(coins, amount));
+ }
+
+ @Test
+ void testChangeImpossibleAmount() {
+ int amount = 3;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(0, CoinChange.change(coins, amount));
+ }
+
+ @Test
+ void testMinimumCoinsBasic() {
+ int amount = 12;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(3, CoinChange.minimumCoins(coins, amount));
+ }
+
+ @Test
+ void testMinimumCoinsNoCoins() {
+ int amount = 12;
+ int[] coins = {};
+
+ assertEquals(Integer.MAX_VALUE, CoinChange.minimumCoins(coins, amount));
+ }
+
+ @Test
+ void testMinimumCoinsNoAmount() {
+ int amount = 0;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(0, CoinChange.minimumCoins(coins, amount));
+ }
+
+ @Test
+ void testMinimumCoinsImpossibleAmount() {
+ int amount = 3;
+ int[] coins = {2, 4, 5};
+
+ assertEquals(Integer.MAX_VALUE, CoinChange.minimumCoins(coins, amount));
+ }
+
+ @Test
+ void testMinimumCoinsExactAmount() {
+ int amount = 10;
+ int[] coins = {1, 5, 10};
+
+ assertEquals(1, CoinChange.minimumCoins(coins, amount));
+ }
+}
From 4a0e46dae6ce49eca6f592cb0ea23054eff2bfa1 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 00:46:20 +0530
Subject: [PATCH 025/348] Add tests, remove `main` in `DiceThrow/DP.java`
(#5644)
---
DIRECTORY.md | 1 +
.../dynamicprogramming/DiceThrow.java | 18 +-----
.../dynamicprogramming/DPTest.java | 56 +++++++++++++++++++
3 files changed, 58 insertions(+), 17 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 0c235b792083..520e7b332d3c 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -788,6 +788,7 @@
* [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
* [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java)
* [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java)
+ * [DPTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java)
* [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
* [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
* [KnapsackMemoizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java b/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java
index e1be3ead5895..c3dc3f32ff7c 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java
@@ -9,6 +9,7 @@
/* Hence, storing the results of the solved sub-problems saves time.
And it can be done using Dynamic Programming(DP).
+// Time Complexity: O(m * n * x) where m is number of faces, n is number of dice and x is given sum.
Following is implementation of Dynamic Programming approach. */
// Code ---->
// Java program to find number of ways to get sum 'x' with 'n'
@@ -43,21 +44,4 @@ public static long findWays(int m, int n, int x) {
return table[n][x];
}
-
- public static void main(String[] args) {
- System.out.println(findWays(4, 2, 1));
- System.out.println(findWays(2, 2, 3));
- System.out.println(findWays(6, 3, 8));
- System.out.println(findWays(4, 2, 5));
- System.out.println(findWays(4, 3, 5));
- }
}
-/*
-OUTPUT:
-0
-2
-21
-4
-6
- */
-// Time Complexity: O(m * n * x) where m is number of faces, n is number of dice and x is given sum.
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java
new file mode 100644
index 000000000000..e3bea67fe269
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java
@@ -0,0 +1,56 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class DPTest {
+
+ @Test
+ void testSumLessThanMinimumFaceValue() {
+ // When the sum is less than the minimum possible face value
+ // There are 0 ways to achieve the sum
+ assertEquals(0, DP.findWays(4, 2, 1)); // 4 faces, 2 dice, sum = 1
+ }
+
+ @Test
+ void testTwoDiceWithSumEqualToTwo() {
+ // When there are 2 dice and the sum is equal to the number of dice
+ // The only way is to have both dice showing 1
+ assertEquals(1, DP.findWays(2, 2, 2)); // 2 faces, 2 dice, sum = 2
+ }
+
+ @Test
+ void testTwoDiceWithSumThree() {
+ // When there are 2 dice and the sum is equal to 3
+ // Possible combinations are (1,2) and (2,1)
+ assertEquals(2, DP.findWays(2, 2, 3)); // 2 faces, 2 dice, sum = 3
+ }
+
+ @Test
+ void testThreeDiceWithSumEight() {
+ // Test for 3 dice, each having 6 faces
+ // Possible combinations to make sum of 8
+ assertEquals(21, DP.findWays(6, 3, 8)); // 6 faces, 3 dice, sum = 8
+ }
+
+ @Test
+ void testTwoDiceWithSumFive() {
+ // Test for 2 dice, with 4 faces to make sum of 5
+ // Possible combinations: (1,4), (2,3), (3,2), (4,1)
+ assertEquals(4, DP.findWays(4, 2, 5)); // 4 faces, 2 dice, sum = 5
+ }
+
+ @Test
+ void testThreeDiceWithSumFive() {
+ // Test for 3 dice, with 4 faces to make sum of 5
+ // Possible combinations: (1,1,3), (1,2,2), (1,3,1), (2,1,2), (2,2,1), (3,1,1)
+ assertEquals(6, DP.findWays(4, 3, 5)); // 4 faces, 3 dice, sum = 5
+ }
+
+ @Test
+ void testEdgeCaseZeroSum() {
+ // Test for 0 sum with 0 dice
+ assertEquals(0, DP.findWays(4, 0, 0)); // 4 faces, 0 dice, sum = 0
+ }
+}
From ce9f42081d3997e0ea7b6cc22ff52f3aacaf2db3 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 00:50:45 +0530
Subject: [PATCH 026/348] Add tests, remove `main`, add negativity test in
`Fibonacci.java` (#5645)
---
DIRECTORY.md | 1 +
.../dynamicprogramming/Fibonacci.java | 34 +++----
.../dynamicprogramming/FibonacciTest.java | 89 +++++++++++++++++++
3 files changed, 109 insertions(+), 15 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 520e7b332d3c..94f5890bb157 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -791,6 +791,7 @@
* [DPTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java)
* [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
* [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
+ * [FibonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java)
* [KnapsackMemoizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
* [KnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java)
* [LevenshteinDistanceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java b/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java
index 5855030fc65c..0d6aff2bbef3 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java
@@ -2,7 +2,6 @@
import java.util.HashMap;
import java.util.Map;
-import java.util.Scanner;
/**
* @author Varun Upadhyay (https://github.com/varunu28)
@@ -11,27 +10,19 @@ public final class Fibonacci {
private Fibonacci() {
}
- private static final Map CACHE = new HashMap<>();
-
- public static void main(String[] args) {
- // Methods all returning [0, 1, 1, 2, 3, 5, ...] for n = [0, 1, 2, 3, 4, 5, ...]
- Scanner sc = new Scanner(System.in);
- int n = sc.nextInt();
-
- System.out.println(fibMemo(n));
- System.out.println(fibBotUp(n));
- System.out.println(fibOptimized(n));
- System.out.println(fibBinet(n));
- sc.close();
- }
+ static final Map CACHE = new HashMap<>();
/**
* This method finds the nth fibonacci number using memoization technique
*
* @param n The input n for which we have to determine the fibonacci number
* Outputs the nth fibonacci number
+ * @throws IllegalArgumentException if n is negative
*/
public static int fibMemo(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input n must be non-negative");
+ }
if (CACHE.containsKey(n)) {
return CACHE.get(n);
}
@@ -52,8 +43,12 @@ public static int fibMemo(int n) {
*
* @param n The input n for which we have to determine the fibonacci number
* Outputs the nth fibonacci number
+ * @throws IllegalArgumentException if n is negative
*/
public static int fibBotUp(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input n must be non-negative");
+ }
Map fib = new HashMap<>();
for (int i = 0; i <= n; i++) {
@@ -80,9 +75,13 @@ public static int fibBotUp(int n) {
* Time Complexity will be O(n)
*
* Whereas , the above functions will take O(n) Space.
+ * @throws IllegalArgumentException if n is negative
* @author Shoaib Rayeen (https://github.com/shoaibrayeen)
*/
public static int fibOptimized(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input n must be non-negative");
+ }
if (n == 0) {
return 0;
}
@@ -105,9 +104,14 @@ public static int fibOptimized(int n) {
* = 1.6180339887... Now, let's look at Binet's formula: Sn = Φⁿ–(– Φ⁻ⁿ)/√5 We first calculate
* the squareRootof5 and phi and store them in variables. Later, we apply Binet's formula to get
* the required term. Time Complexity will be O(1)
+ * @param n The input n for which we have to determine the fibonacci number
+ * Outputs the nth fibonacci number
+ * @throws IllegalArgumentException if n is negative
*/
-
public static int fibBinet(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input n must be non-negative");
+ }
double squareRootOf5 = Math.sqrt(5);
double phi = (1 + squareRootOf5) / 2;
return (int) ((Math.pow(phi, n) - Math.pow(-phi, -n)) / squareRootOf5);
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java
new file mode 100644
index 000000000000..166e20c3083f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java
@@ -0,0 +1,89 @@
+package com.thealgorithms.dynamicprogramming;
+
+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 FibonacciTest {
+
+ @BeforeEach
+ void setUp() {
+ // Clear the cache before each test to avoid interference
+ Fibonacci.CACHE.clear();
+ }
+
+ @Test
+ void testFibMemo() {
+ // Test memoization method
+ assertEquals(0, Fibonacci.fibMemo(0));
+ assertEquals(1, Fibonacci.fibMemo(1));
+ assertEquals(1, Fibonacci.fibMemo(2));
+ assertEquals(2, Fibonacci.fibMemo(3));
+ assertEquals(3, Fibonacci.fibMemo(4));
+ assertEquals(5, Fibonacci.fibMemo(5));
+ assertEquals(8, Fibonacci.fibMemo(6));
+ assertEquals(13, Fibonacci.fibMemo(7));
+ assertEquals(21, Fibonacci.fibMemo(8));
+ assertEquals(34, Fibonacci.fibMemo(9));
+ assertEquals(55, Fibonacci.fibMemo(10));
+ }
+
+ @Test
+ void testFibBotUp() {
+ // Test bottom-up method
+ assertEquals(0, Fibonacci.fibBotUp(0));
+ assertEquals(1, Fibonacci.fibBotUp(1));
+ assertEquals(1, Fibonacci.fibBotUp(2));
+ assertEquals(2, Fibonacci.fibBotUp(3));
+ assertEquals(3, Fibonacci.fibBotUp(4));
+ assertEquals(5, Fibonacci.fibBotUp(5));
+ assertEquals(8, Fibonacci.fibBotUp(6));
+ assertEquals(13, Fibonacci.fibBotUp(7));
+ assertEquals(21, Fibonacci.fibBotUp(8));
+ assertEquals(34, Fibonacci.fibBotUp(9));
+ assertEquals(55, Fibonacci.fibBotUp(10));
+ }
+
+ @Test
+ void testFibOptimized() {
+ // Test optimized Fibonacci method
+ assertEquals(0, Fibonacci.fibOptimized(0));
+ assertEquals(1, Fibonacci.fibOptimized(1));
+ assertEquals(1, Fibonacci.fibOptimized(2));
+ assertEquals(2, Fibonacci.fibOptimized(3));
+ assertEquals(3, Fibonacci.fibOptimized(4));
+ assertEquals(5, Fibonacci.fibOptimized(5));
+ assertEquals(8, Fibonacci.fibOptimized(6));
+ assertEquals(13, Fibonacci.fibOptimized(7));
+ assertEquals(21, Fibonacci.fibOptimized(8));
+ assertEquals(34, Fibonacci.fibOptimized(9));
+ assertEquals(55, Fibonacci.fibOptimized(10));
+ }
+
+ @Test
+ void testFibBinet() {
+ // Test Binet's formula method
+ assertEquals(0, Fibonacci.fibBinet(0));
+ assertEquals(1, Fibonacci.fibBinet(1));
+ assertEquals(1, Fibonacci.fibBinet(2));
+ assertEquals(2, Fibonacci.fibBinet(3));
+ assertEquals(3, Fibonacci.fibBinet(4));
+ assertEquals(5, Fibonacci.fibBinet(5));
+ assertEquals(8, Fibonacci.fibBinet(6));
+ assertEquals(13, Fibonacci.fibBinet(7));
+ assertEquals(21, Fibonacci.fibBinet(8));
+ assertEquals(34, Fibonacci.fibBinet(9));
+ assertEquals(55, Fibonacci.fibBinet(10));
+ }
+
+ @Test
+ void testNegativeInput() {
+ // Test negative input; Fibonacci is not defined for negative numbers
+ assertThrows(IllegalArgumentException.class, () -> { Fibonacci.fibMemo(-1); });
+ assertThrows(IllegalArgumentException.class, () -> { Fibonacci.fibBotUp(-1); });
+ assertThrows(IllegalArgumentException.class, () -> { Fibonacci.fibOptimized(-1); });
+ assertThrows(IllegalArgumentException.class, () -> { Fibonacci.fibBinet(-1); });
+ }
+}
From 029dd85646b3ca1d3f827552a56f873221f4a246 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 01:06:00 +0530
Subject: [PATCH 027/348] Add tests, enhance docs in `KadaneAlgorithm.java`
(#5646)
---
DIRECTORY.md | 1 +
.../dynamicprogramming/KadaneAlgorithm.java | 44 ++++++++-----
.../KadaneAlgorithmTest.java | 61 +++++++++++++++++++
3 files changed, 92 insertions(+), 14 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 94f5890bb157..2b595e7a6652 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -792,6 +792,7 @@
* [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java)
* [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java)
* [FibonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java)
+ * [KadaneAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java)
* [KnapsackMemoizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java)
* [KnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java)
* [LevenshteinDistanceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java b/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java
index 905815d10a29..7a0a3da94c1e 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java
@@ -1,36 +1,52 @@
package com.thealgorithms.dynamicprogramming;
/**
- * @author Siddhant Swarup Mallick
- * Program description - To find the maximum subarray sum
+ * This class implements Kadane's Algorithm to find the maximum subarray sum
+ * within a given array of integers. The algorithm efficiently computes the maximum
+ * sum of a contiguous subarray in linear time.
+ *
+ * Author: Siddhant Swarup Mallick
*/
public final class KadaneAlgorithm {
private KadaneAlgorithm() {
}
/**
- * OUTPUT :
- * Input - {89,56,98,123,26,75,12,40,39,68,91}
- * Output: it returns either true or false
- * 1st approach Time Complexity : O(n)
- * Auxiliary Space Complexity : O(1)
+ * Computes the maximum subarray sum using Kadane's Algorithm and checks
+ * if it matches a predicted answer.
+ *
+ * @param a The input array of integers for which the maximum
+ * subarray sum is to be calculated.
+ * @param predictedAnswer The expected maximum subarray sum to be verified
+ * against the computed sum.
+ * @return true if the computed maximum subarray sum equals the predicted
+ * answer, false otherwise.
+ *
+ *
Example:
+ *
+ * Input: {89, 56, 98, 123, 26, 75, 12, 40, 39, 68, 91}
+ * Output: true if the maximum subarray sum is equal to the
+ * predicted answer.
+ *
+ *
+ *
Algorithmic Complexity:
+ *
+ *
Time Complexity: O(n) - the algorithm iterates through the array once.
+ *
Auxiliary Space Complexity: O(1) - only a constant amount of additional space is used.
+ *
*/
public static boolean maxSum(int[] a, int predictedAnswer) {
int sum = a[0];
int runningSum = 0;
+
for (int k : a) {
- runningSum = runningSum + k;
- // running sum of all the indexs are stored
+ runningSum += k;
sum = Math.max(sum, runningSum);
- // the max is stored inorder to the get the maximum sum
if (runningSum < 0) {
runningSum = 0;
}
- // if running sum is negative then it is initialized to zero
}
- // for-each loop is used to iterate over the array and find the maximum subarray sum
+
return sum == predictedAnswer;
- // It returns true if sum and predicted answer matches
- // The predicted answer is the answer itself. So it always return true
}
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java
new file mode 100644
index 000000000000..e26606ef98a9
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java
@@ -0,0 +1,61 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class KadaneAlgorithmTest {
+
+ @Test
+ void testMaxSumWithPositiveValues() {
+ // Test with all positive numbers
+ int[] input = {89, 56, 98, 123, 26, 75, 12, 40, 39, 68, 91};
+ int expectedMaxSum = 89 + 56 + 98 + 123 + 26 + 75 + 12 + 40 + 39 + 68 + 91; // sum of all elements
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+ }
+
+ @Test
+ void testMaxSumWithMixedValues() {
+ // Test with mixed positive and negative numbers
+ int[] input = {1, -2, 3, 4, -1, 2, 1, -5, 4};
+ int expectedMaxSum = 3 + 4 + -1 + 2 + 1; // max subarray is [3, 4, -1, 2, 1]
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+ }
+
+ @Test
+ void testMaxSumWithAllNegativeValues() {
+ // Test with all negative numbers
+ int[] input = {-2, -3, -1, -4};
+ int expectedMaxSum = -1; // max subarray is the least negative number
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+ }
+
+ @Test
+ void testMaxSumWithSingleElement() {
+ // Test with a single positive element
+ int[] input = {10};
+ int expectedMaxSum = 10; // max subarray is the single element
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+
+ // Test with a single negative element
+ input = new int[] {-10};
+ expectedMaxSum = -10; // max subarray is the single element
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+ }
+
+ @Test
+ void testMaxSumWithZero() {
+ // Test with zeros in the array
+ int[] input = {0, -1, 2, -2, 0, 3};
+ int expectedMaxSum = 3; // max subarray is [2, -2, 0, 3]
+ assertTrue(KadaneAlgorithm.maxSum(input, expectedMaxSum));
+ }
+
+ @Test
+ void testMaxSumWithEmptyArray() {
+ // Test with an empty array; should ideally throw an exception or return false
+ int[] input = {};
+ assertThrows(ArrayIndexOutOfBoundsException.class, () -> { KadaneAlgorithm.maxSum(input, 0); });
+ }
+}
From 6e6028e3d0c96d30dc274866bd5398c5cddd0f5f Mon Sep 17 00:00:00 2001
From: SAIVARDHAN15 <127930279+SAIVARDHAN15@users.noreply.github.com>
Date: Thu, 10 Oct 2024 01:11:25 +0530
Subject: [PATCH 028/348] Fix columnarTranspositionCipher and typos in Test
(#5649)
---
.../ciphers/ColumnarTranspositionCipher.java | 29 +++++++++----------
.../ColumnarTranspositionCipherTest.java | 14 ++++-----
2 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java b/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
index d7e64a12ebfd..b6b889b079ca 100644
--- a/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
+++ b/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java
@@ -27,13 +27,13 @@ private ColumnarTranspositionCipher() {
* @return a String with the word encrypted by the Columnar Transposition
* Cipher Rule
*/
- public static String encrpyter(String word, String keyword) {
+ public static String encrypt(final String word, final String keyword) {
ColumnarTranspositionCipher.keyword = keyword;
- abecedariumBuilder(500);
+ abecedariumBuilder();
table = tableBuilder(word);
Object[][] sortedTable = sortTable(table);
StringBuilder wordEncrypted = new StringBuilder();
- for (int i = 0; i < sortedTable[i].length; i++) {
+ for (int i = 0; i < sortedTable[0].length; i++) {
for (int j = 1; j < sortedTable.length; j++) {
wordEncrypted.append(sortedTable[j][i]);
}
@@ -51,11 +51,12 @@ public static String encrpyter(String word, String keyword) {
* @return a String with the word encrypted by the Columnar Transposition
* Cipher Rule
*/
- public static String encrpyter(String word, String keyword, String abecedarium) {
+ public static String encrypt(String word, String keyword, String abecedarium) {
ColumnarTranspositionCipher.keyword = keyword;
ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
table = tableBuilder(word);
Object[][] sortedTable = sortTable(table);
+
StringBuilder wordEncrypted = new StringBuilder();
for (int i = 0; i < sortedTable[0].length; i++) {
for (int j = 1; j < sortedTable.length; j++) {
@@ -72,7 +73,7 @@ public static String encrpyter(String word, String keyword, String abecedarium)
* @return a String decrypted with the word encrypted by the Columnar
* Transposition Cipher Rule
*/
- public static String decrypter() {
+ public static String decrypt() {
StringBuilder wordDecrypted = new StringBuilder();
for (int i = 1; i < table.length; i++) {
for (Object item : table[i]) {
@@ -91,14 +92,14 @@ public static String decrypter() {
*/
private static Object[][] tableBuilder(String word) {
Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()];
- char[] wordInChards = word.toCharArray();
- // Fils in the respective numbers
+ char[] wordInChars = word.toCharArray();
+ // Fills in the respective numbers for the column
table[0] = findElements();
int charElement = 0;
for (int i = 1; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
- if (charElement < wordInChards.length) {
- table[i][j] = wordInChards[charElement];
+ if (charElement < wordInChars.length) {
+ table[i][j] = wordInChars[charElement];
charElement++;
} else {
table[i][j] = ENCRYPTION_FIELD_CHAR;
@@ -116,7 +117,7 @@ private static Object[][] tableBuilder(String word) {
* order to respect the Columnar Transposition Cipher Rule.
*/
private static int numberOfRows(String word) {
- if (word.length() / keyword.length() > word.length() / keyword.length()) {
+ if (word.length() % keyword.length() != 0) {
return (word.length() / keyword.length()) + 1;
} else {
return word.length() / keyword.length();
@@ -173,13 +174,11 @@ private static void switchColumns(Object[][] table, int firstColumnIndex, int se
}
/**
- * Creates an abecedarium with a specified ascii inded
- *
- * @param value Number of characters being used based on the ASCII Table
+ * Creates an abecedarium with all available ascii values.
*/
- private static void abecedariumBuilder(int value) {
+ private static void abecedariumBuilder() {
StringBuilder t = new StringBuilder();
- for (int i = 0; i < value; i++) {
+ for (int i = 0; i < 256; i++) {
t.append((char) i);
}
abecedarium = t.toString();
diff --git a/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java b/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java
index 0d306a6623db..8deae45099d6 100644
--- a/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java
+++ b/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java
@@ -20,7 +20,7 @@ public void setUp() {
@Test
public void testEncryption() {
- String encryptedText = ColumnarTranspositionCipher.encrpyter(plaintext, keyword);
+ String encryptedText = ColumnarTranspositionCipher.encrypt(plaintext, keyword);
assertNotNull(encryptedText, "The encrypted text should not be null.");
assertFalse(encryptedText.isEmpty(), "The encrypted text should not be empty.");
// Check if the encrypted text is different from the plaintext
@@ -29,19 +29,19 @@ public void testEncryption() {
@Test
public void testDecryption() {
- String encryptedText = ColumnarTranspositionCipher.encrpyter(plaintext, keyword);
- String decryptedText = ColumnarTranspositionCipher.decrypter();
+ String encryptedText = ColumnarTranspositionCipher.encrypt(plaintext, keyword);
+ String decryptedText = ColumnarTranspositionCipher.decrypt();
assertEquals(plaintext.replaceAll(" ", ""), decryptedText.replaceAll(" ", ""), "The decrypted text should match the original plaintext, ignoring spaces.");
- assertEquals(encryptedText, ColumnarTranspositionCipher.encrpyter(plaintext, keyword), "The encrypted text should be the same when encrypted again.");
+ assertEquals(encryptedText, ColumnarTranspositionCipher.encrypt(plaintext, keyword), "The encrypted text should be the same when encrypted again.");
}
@Test
public void testLongPlainText() {
String longText = "This is a significantly longer piece of text to test the encryption and decryption capabilities of the Columnar Transposition Cipher. It should handle long strings gracefully.";
- String encryptedText = ColumnarTranspositionCipher.encrpyter(longText, keyword);
- String decryptedText = ColumnarTranspositionCipher.decrypter();
+ String encryptedText = ColumnarTranspositionCipher.encrypt(longText, keyword);
+ String decryptedText = ColumnarTranspositionCipher.decrypt();
assertEquals(longText.replaceAll(" ", ""), decryptedText.replaceAll(" ", ""), "The decrypted text should match the original long plaintext, ignoring spaces.");
- assertEquals(encryptedText, ColumnarTranspositionCipher.encrpyter(longText, keyword), "The encrypted text should be the same when encrypted again.");
+ assertEquals(encryptedText, ColumnarTranspositionCipher.encrypt(longText, keyword), "The encrypted text should be the same when encrypted again.");
}
}
From f170078b8bb1ec346b574b86601040267f2cb2a8 Mon Sep 17 00:00:00 2001
From: Abhinay Verma <53249427+Monk-AbhinayVerma@users.noreply.github.com>
Date: Thu, 10 Oct 2024 01:15:15 +0530
Subject: [PATCH 029/348] Add Ones & Twos Complement in BitManipulation (#5604)
---
.../bitmanipulation/OnesComplement.java | 28 ++++++++++
.../bitmanipulation/TwosComplement.java | 41 ++++++++++++++
.../bitmanipulation/OnesComplementTest.java | 47 ++++++++++++++++
.../bitmanipulation/TwosComplementTest.java | 54 +++++++++++++++++++
4 files changed, 170 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
new file mode 100644
index 000000000000..c5c068422113
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * @author - https://github.com/Monk-AbhinayVerma
+ * @Wikipedia - https://en.wikipedia.org/wiki/Ones%27_complement
+ * The class OnesComplement computes the complement of binary number
+ * and returns
+ * the complemented binary string.
+ * @return the complimented binary string
+ */
+public final class OnesComplement {
+ private OnesComplement() {
+ }
+
+ // Function to get the 1's complement of a binary number
+ public static String onesComplement(String binary) {
+ StringBuilder complement = new StringBuilder();
+ // Invert each bit to get the 1's complement
+ for (int i = 0; i < binary.length(); i++) {
+ if (binary.charAt(i) == '0') {
+ complement.append('1');
+ } else {
+ complement.append('0');
+ }
+ }
+ return complement.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
new file mode 100644
index 000000000000..0bc200722943
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * @wikipedia - https://en.wikipedia.org/wiki/Two%27s_complement
+ * This Algorithm was first suggested by Jon Von Neumann
+ * @author - https://github.com/Monk-AbhinayVerma
+ * @return the two's complement of any binary number
+ */
+public final class TwosComplement {
+ private TwosComplement() {
+ }
+
+ // Function to get the 2's complement of a binary number
+ public static String twosComplement(String binary) {
+ StringBuilder onesComplement = new StringBuilder();
+ // Step 1: Find the 1's complement (invert the bits)
+ for (int i = 0; i < binary.length(); i++) {
+ if (binary.charAt(i) == '0') {
+ onesComplement.append('1');
+ } else {
+ onesComplement.append('0');
+ }
+ }
+ // Step 2: Add 1 to the 1's complement
+ StringBuilder twosComplement = new StringBuilder(onesComplement);
+ boolean carry = true;
+ for (int i = onesComplement.length() - 1; i >= 0; i--) {
+ if (onesComplement.charAt(i) == '1' && carry) {
+ twosComplement.setCharAt(i, '0');
+ } else if (onesComplement.charAt(i) == '0' && carry) {
+ twosComplement.setCharAt(i, '1');
+ carry = false;
+ }
+ }
+ // If there is still a carry, append '1' at the beginning
+ if (carry) {
+ twosComplement.insert(0, '1');
+ }
+ return twosComplement.toString();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java
new file mode 100644
index 000000000000..6be4eb595f79
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java
@@ -0,0 +1,47 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test case for Highest Set Bit
+ * @author Abhinay Verma(https://github.com/Monk-AbhinayVerma)
+ */
+public class OnesComplementTest {
+
+ @Test
+ public void testOnesComplementAllZeroes() {
+
+ // Test cases with all-zero binary strings
+ assertEquals("1111", OnesComplement.onesComplement("0000"));
+ assertEquals("111", OnesComplement.onesComplement("000"));
+ assertEquals("11", OnesComplement.onesComplement("00"));
+ assertEquals("1", OnesComplement.onesComplement("0"));
+ }
+
+ @Test
+ public void testOnesComplementAllOnes() {
+ // Test cases with all-one binary strings
+ assertEquals("0000", OnesComplement.onesComplement("1111"));
+ assertEquals("000", OnesComplement.onesComplement("111"));
+ assertEquals("00", OnesComplement.onesComplement("11"));
+ assertEquals("0", OnesComplement.onesComplement("1"));
+ }
+
+ @Test
+ public void testOnesComplementMixedBits() {
+ // Test more mixed binary patterns
+ assertEquals("1010", OnesComplement.onesComplement("0101"));
+ assertEquals("0101", OnesComplement.onesComplement("1010"));
+ assertEquals("1100", OnesComplement.onesComplement("0011"));
+ assertEquals("0011", OnesComplement.onesComplement("1100"));
+ assertEquals("1001", OnesComplement.onesComplement("0110"));
+ }
+
+ @Test
+ public void testOnesComplementEmptyString() {
+ // Test empty string scenario
+ assertEquals("", OnesComplement.onesComplement(""));
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
new file mode 100644
index 000000000000..512e94b6374e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test case for Highest Set Bit
+ * @author Abhinay Verma(https://github.com/Monk-AbhinayVerma)
+ */
+public class TwosComplementTest {
+
+ @Test
+ public void testTwosComplementAllZeroes() {
+ // Test with a binary number consisting entirely of zeroes
+ assertEquals("10000", TwosComplement.twosComplement("0000"));
+ assertEquals("1000", TwosComplement.twosComplement("000"));
+ assertEquals("100", TwosComplement.twosComplement("00"));
+ assertEquals("10", TwosComplement.twosComplement("0"));
+ }
+
+ @Test
+ public void testTwosComplementAllOnes() {
+ // Test with a binary number consisting entirely of ones
+ assertEquals("00001", TwosComplement.twosComplement("11111"));
+ assertEquals("0001", TwosComplement.twosComplement("1111"));
+ assertEquals("001", TwosComplement.twosComplement("111"));
+ assertEquals("01", TwosComplement.twosComplement("11"));
+ }
+
+ @Test
+ public void testTwosComplementMixedBits() {
+ // Test with binary numbers with mixed bits
+ assertEquals("1111", TwosComplement.twosComplement("0001")); // 1's complement: 1110, then add 1: 1111
+ assertEquals("1001", TwosComplement.twosComplement("0111")); // 1's complement: 1000
+ assertEquals("11001", TwosComplement.twosComplement("00111")); // 1's complement: 11000, add 1: 11001
+ assertEquals("011", TwosComplement.twosComplement("101")); // 1's complement: 010, add 1: 011
+ }
+
+ @Test
+ public void testTwosComplementSingleBit() {
+ // Test with single bit
+ assertEquals("10", TwosComplement.twosComplement("0"));
+ assertEquals("1", TwosComplement.twosComplement("1"));
+ }
+
+ @Test
+ public void testTwosComplementWithLeadingZeroes() {
+ // Test with leading zeroes in the input
+ assertEquals("1111", TwosComplement.twosComplement("0001"));
+ assertEquals("101", TwosComplement.twosComplement("011"));
+ assertEquals("110", TwosComplement.twosComplement("010"));
+ }
+}
From 48c65e4c5e9d5644762b6797f2ab902445f3da54 Mon Sep 17 00:00:00 2001
From: xuyang471 <2621860014@qq.com>
Date: Thu, 10 Oct 2024 03:50:30 +0800
Subject: [PATCH 030/348] Add boundary traversal of binary tree (#5639)
---
.../trees/BoundaryTraversal.java | 168 ++++++++++++++++++
.../trees/BoundaryTraversalTest.java | 108 +++++++++++
2 files changed, 276 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java
new file mode 100644
index 000000000000..9a79902cc598
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java
@@ -0,0 +1,168 @@
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * BoundaryTraversal
+ *
+ * Start with the Root:
+ * Add the root node to the boundary list.
+ * Traverse the Left Boundary (Excluding Leaf Nodes):
+ * Move down the left side of the tree, adding each non-leaf node to the boundary list.
+ * If a node has a left child, go left; otherwise, go right.
+ * Visit All Leaf Nodes:
+ * Traverse the tree and add all leaf nodes to the boundary list, from left to right.
+ * Traverse the Right Boundary (Excluding Leaf Nodes) in Reverse Order:
+ * Move up the right side of the tree, adding each non-leaf node to a temporary list.
+ * If a node has a right child, go right; otherwise, go left.
+ * Reverse the temporary list and add it to the boundary list.
+ * Combine and Output:
+ * The final boundary list contains the root, left boundary, leaf nodes, and reversed right boundary in that order.
+ */
+public final class BoundaryTraversal {
+ private BoundaryTraversal() {
+ }
+
+ // Main function for boundary traversal, returns a list of boundary nodes in order
+ public static List boundaryTraversal(BinaryTree.Node root) {
+ List result = new ArrayList<>();
+ if (root == null) {
+ return result;
+ }
+
+ // Add root node if it's not a leaf node
+ if (!isLeaf(root)) {
+ result.add(root.data);
+ }
+
+ // Add left boundary
+ addLeftBoundary(root, result);
+
+ // Add leaf nodes
+ addLeaves(root, result);
+
+ // Add right boundary
+ addRightBoundary(root, result);
+
+ return result;
+ }
+
+ // Adds the left boundary, including nodes that have no left child but have a right child
+ private static void addLeftBoundary(BinaryTree.Node node, List result) {
+ BinaryTree.Node cur = node.left;
+
+ // If there is no left child but there is a right child, treat the right child as part of the left boundary
+ if (cur == null && node.right != null) {
+ cur = node.right;
+ }
+
+ while (cur != null) {
+ if (!isLeaf(cur)) {
+ result.add(cur.data); // Add non-leaf nodes to result
+ }
+ if (cur.left != null) {
+ cur = cur.left; // Move to the left child
+ } else if (cur.right != null) {
+ cur = cur.right; // If left child is null, move to the right child
+ } else {
+ break; // Stop if there are no children
+ }
+ }
+ }
+
+ // Adds leaf nodes (nodes without children)
+ private static void addLeaves(BinaryTree.Node node, List result) {
+ if (node == null) {
+ return;
+ }
+ if (isLeaf(node)) {
+ result.add(node.data); // Add leaf node
+ } else {
+ addLeaves(node.left, result); // Recur for left subtree
+ addLeaves(node.right, result); // Recur for right subtree
+ }
+ }
+
+ // Adds the right boundary, excluding leaf nodes
+ private static void addRightBoundary(BinaryTree.Node node, List result) {
+ BinaryTree.Node cur = node.right;
+ List temp = new ArrayList<>();
+
+ // If no right boundary is present and there is no left subtree, skip
+ if (cur != null && node.left == null) {
+ return;
+ }
+ while (cur != null) {
+ if (!isLeaf(cur)) {
+ temp.add(cur.data); // Store non-leaf nodes temporarily
+ }
+ if (cur.right != null) {
+ cur = cur.right; // Move to the right child
+ } else if (cur.left != null) {
+ cur = cur.left; // If right child is null, move to the left child
+ } else {
+ break; // Stop if there are no children
+ }
+ }
+
+ // Add the right boundary nodes in reverse order
+ for (int i = temp.size() - 1; i >= 0; i--) {
+ result.add(temp.get(i));
+ }
+ }
+
+ // Checks if a node is a leaf node
+ private static boolean isLeaf(BinaryTree.Node node) {
+ return node.left == null && node.right == null;
+ }
+
+ // Iterative boundary traversal
+ public static List iterativeBoundaryTraversal(BinaryTree.Node root) {
+ List result = new ArrayList<>();
+ if (root == null) {
+ return result;
+ }
+
+ // Add root node if it's not a leaf node
+ if (!isLeaf(root)) {
+ result.add(root.data);
+ }
+
+ // Handle the left boundary
+ BinaryTree.Node cur = root.left;
+ if (cur == null && root.right != null) {
+ cur = root.right;
+ }
+ while (cur != null) {
+ if (!isLeaf(cur)) {
+ result.add(cur.data); // Add non-leaf nodes to result
+ }
+ cur = (cur.left != null) ? cur.left : cur.right; // Prioritize left child, move to right if left is null
+ }
+
+ // Add leaf nodes
+ addLeaves(root, result);
+
+ // Handle the right boundary using a stack (reverse order)
+ cur = root.right;
+ Deque stack = new LinkedList<>();
+ if (cur != null && root.left == null) {
+ return result;
+ }
+ while (cur != null) {
+ if (!isLeaf(cur)) {
+ stack.push(cur.data); // Temporarily store right boundary nodes in a stack
+ }
+ cur = (cur.right != null) ? cur.right : cur.left; // Prioritize right child, move to left if right is null
+ }
+
+ // Add the right boundary nodes from the stack to maintain the correct order
+ while (!stack.isEmpty()) {
+ result.add(stack.pop());
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java
new file mode 100644
index 000000000000..515dac88ce09
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java
@@ -0,0 +1,108 @@
+package com.thealgorithms.datastructures.trees;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ */
+public class BoundaryTraversalTest {
+
+ @Test
+ public void testNullRoot() {
+ assertEquals(Collections.emptyList(), BoundaryTraversal.boundaryTraversal(null));
+ assertEquals(Collections.emptyList(), BoundaryTraversal.iterativeBoundaryTraversal(null));
+ }
+
+ @Test
+ public void testSingleNodeTree() {
+ final BinaryTree.Node root = new BinaryTree.Node(1);
+
+ List expected = List.of(1);
+
+ assertEquals(expected, BoundaryTraversal.boundaryTraversal(root));
+ assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root));
+ }
+
+ /*
+ 1
+ / \
+ 2 3
+ / \ / \
+ 4 5 6 7
+
+ */
+ @Test
+ public void testCompleteBinaryTree() {
+ final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 3, 4, 5, 6, 7});
+
+ List expected = List.of(1, 2, 4, 5, 6, 7, 3);
+
+ assertEquals(expected, BoundaryTraversal.boundaryTraversal(root));
+ assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root));
+ }
+
+ /*
+ 1
+ / \
+ 2 7
+ / \
+ 3 8
+ \ /
+ 4 9
+ / \
+ 5 6
+ / \
+ 10 11
+ */
+ @Test
+ public void testBoundaryTraversal() {
+ final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, 7, 3, null, null, 8, null, 4, 9, null, 5, 6, 10, 11});
+
+ List expected = List.of(1, 2, 3, 4, 5, 6, 10, 11, 9, 8, 7);
+
+ assertEquals(expected, BoundaryTraversal.boundaryTraversal(root));
+ assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root));
+ }
+
+ /*
+ 1
+ /
+ 2
+ /
+ 3
+ /
+ 4
+ */
+ @Test
+ public void testLeftSkewedTree() {
+ final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {1, 2, null, 3, null, 4, null});
+
+ List expected = List.of(1, 2, 3, 4);
+
+ assertEquals(expected, BoundaryTraversal.boundaryTraversal(root));
+ assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root));
+ }
+
+ /*
+ 5
+ \
+ 6
+ \
+ 7
+ \
+ 8
+ */
+ @Test
+ public void testRightSkewedTree() {
+ final BinaryTree.Node root = TreeTestUtils.createTree(new Integer[] {5, null, 6, null, 7, null, 8});
+
+ List expected = List.of(5, 6, 7, 8);
+
+ assertEquals(expected, BoundaryTraversal.boundaryTraversal(root));
+ assertEquals(expected, BoundaryTraversal.iterativeBoundaryTraversal(root));
+ }
+}
From c0f35242a1d3055c345a4164ada5b4fe406f876e Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 01:26:51 +0530
Subject: [PATCH 031/348] Add tests, remove `print` & `main` methods in
`BoundaryFill.java` (#5640)
---
DIRECTORY.md | 7 ++
.../dynamicprogramming/BoundaryFill.java | 44 -------------
.../dynamicprogramming/BoundaryFillTest.java | 66 +++++++++++++++++++
3 files changed, 73 insertions(+), 44 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 2b595e7a6652..a1a53cb2926c 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -33,8 +33,10 @@
* [NonRepeatingNumberFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java)
* [NumberAppearingOddTimes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java)
* [NumbersDifferentSigns](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java)
+ * [OnesComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java)
* [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
* [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
+ * [TwosComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java)
* ciphers
* a5
* [A5Cipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java)
@@ -185,6 +187,7 @@
* [AVLSimple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java)
* [AVLTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java)
* [BinaryTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java)
+ * [BoundaryTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java)
* [BSTFromSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTFromSortedArray.java)
* [BSTIterative](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTIterative.java)
* [BSTRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursive.java)
@@ -643,8 +646,10 @@
* [NonRepeatingNumberFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java)
* [NumberAppearingOddTimesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java)
* [NumbersDifferentSignsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java)
+ * [OnesComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java)
* [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
+ * [TwosComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java)
* ciphers
* a5
* [A5CipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java)
@@ -754,6 +759,7 @@
* [StackArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java)
* trees
* [BinaryTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java)
+ * [BoundaryTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java)
* [BSTFromSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTFromSortedArrayTest.java)
* [BSTIterativeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTIterativeTest.java)
* [BSTRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveTest.java)
@@ -783,6 +789,7 @@
* [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java)
* dynamicprogramming
* [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java)
+ * [BoundaryFillTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java)
* [BruteForceKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java)
* [CatalanNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java)
* [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
index 3fa8728930cb..8494492f293f 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java
@@ -52,48 +52,4 @@ public static void boundaryFill(int[][] image, int xCoordinate, int yCoordinate,
boundaryFill(image, xCoordinate - 1, yCoordinate - 1, newColor, boundaryColor);
}
}
-
- /**
- * This method will print the 2D image matrix
- *
- * @param image The image to be printed on the console
- */
- public static void printImageArray(int[][] image) {
- for (int i = 0; i < image.length; i++) {
- for (int j = 0; j < image[0].length; j++) {
- System.out.print(image[i][j] + " ");
- }
-
- System.out.println();
- }
- }
-
- // Driver Program
- public static void main(String[] args) {
- // Input 2D image matrix
- int[][] image = {
- {0, 0, 0, 0, 0, 0, 0},
- {0, 3, 3, 3, 3, 0, 0},
- {0, 3, 0, 0, 3, 0, 0},
- {0, 3, 0, 0, 3, 3, 3},
- {0, 3, 3, 3, 0, 0, 3},
- {0, 0, 0, 3, 0, 0, 3},
- {0, 0, 0, 3, 3, 3, 3},
- };
-
- boundaryFill(image, 2, 2, 5, 3);
-
- /* Output ==>
- * 0 0 0 0 0 0 0
- 0 3 3 3 3 0 0
- 0 3 5 5 3 0 0
- 0 3 5 5 3 3 3
- 0 3 3 3 5 5 3
- 0 0 0 3 5 5 3
- 0 0 0 3 3 3 3
- * */
-
- // print 2D image matrix
- printImageArray(image);
- }
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java
new file mode 100644
index 000000000000..4aa412731a10
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java
@@ -0,0 +1,66 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class BoundaryFillTest {
+
+ private int[][] image;
+
+ @BeforeEach
+ void setUp() {
+ image = new int[][] {{0, 0, 0, 0, 0, 0, 0}, {0, 3, 3, 3, 3, 0, 0}, {0, 3, 0, 0, 3, 0, 0}, {0, 3, 0, 0, 3, 3, 3}, {0, 3, 3, 3, 0, 0, 3}, {0, 0, 0, 3, 0, 0, 3}, {0, 0, 0, 3, 3, 3, 3}};
+ }
+
+ @Test
+ void testGetPixel() {
+ assertEquals(3, BoundaryFill.getPixel(image, 1, 1));
+ assertEquals(0, BoundaryFill.getPixel(image, 2, 2));
+ assertEquals(3, BoundaryFill.getPixel(image, 4, 3));
+ }
+
+ @Test
+ void testPutPixel() {
+ BoundaryFill.putPixel(image, 2, 2, 5);
+ assertEquals(5, BoundaryFill.getPixel(image, 2, 2));
+
+ BoundaryFill.putPixel(image, 0, 0, 7);
+ assertEquals(7, BoundaryFill.getPixel(image, 0, 0));
+ }
+
+ @Test
+ void testBoundaryFill() {
+ BoundaryFill.boundaryFill(image, 2, 2, 5, 3);
+
+ int[][] expectedImage = {{0, 0, 0, 0, 0, 0, 0}, {0, 3, 3, 3, 3, 0, 0}, {0, 3, 5, 5, 3, 0, 0}, {0, 3, 5, 5, 3, 3, 3}, {0, 3, 3, 3, 5, 5, 3}, {0, 0, 0, 3, 5, 5, 3}, {0, 0, 0, 3, 3, 3, 3}};
+
+ for (int i = 0; i < image.length; i++) {
+ assertArrayEquals(expectedImage[i], image[i]);
+ }
+ }
+
+ @Test
+ void testBoundaryFillEdgeCase() {
+ BoundaryFill.boundaryFill(image, 1, 1, 3, 3);
+
+ int[][] expectedImage = {{0, 0, 0, 0, 0, 0, 0}, {0, 3, 3, 3, 3, 0, 0}, {0, 3, 0, 0, 3, 0, 0}, {0, 3, 0, 0, 3, 3, 3}, {0, 3, 3, 3, 0, 0, 3}, {0, 0, 0, 3, 0, 0, 3}, {0, 0, 0, 3, 3, 3, 3}};
+
+ for (int i = 0; i < image.length; i++) {
+ assertArrayEquals(expectedImage[i], image[i]);
+ }
+ }
+
+ @Test
+ void testBoundaryFillInvalidCoordinates() {
+ BoundaryFill.boundaryFill(image, -1, -1, 5, 3);
+
+ int[][] expectedImage = {{0, 0, 0, 0, 0, 0, 0}, {0, 3, 3, 3, 3, 0, 0}, {0, 3, 0, 0, 3, 0, 0}, {0, 3, 0, 0, 3, 3, 3}, {0, 3, 3, 3, 0, 0, 3}, {0, 0, 0, 3, 0, 0, 3}, {0, 0, 0, 3, 3, 3, 3}};
+
+ for (int i = 0; i < image.length; i++) {
+ assertArrayEquals(expectedImage[i], image[i]);
+ }
+ }
+}
From 6535d4755d8bed3cd410571568d0200f01bd806a Mon Sep 17 00:00:00 2001
From: Lakshyajeet Singh Goyal
<74810454+DarkMatter-999@users.noreply.github.com>
Date: Thu, 10 Oct 2024 01:32:41 +0530
Subject: [PATCH 032/348] Add SwapAdjacentBits algorithm (#5634)
---
.../bitmanipulation/SwapAdjacentBits.java | 26 +++++++++++++++++++
.../bitmanipulation/SwapAdjacentBitsTest.java | 22 ++++++++++++++++
2 files changed, 48 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
new file mode 100644
index 000000000000..933dec5654a0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
@@ -0,0 +1,26 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Swap every pair of adjacent bits of a given number.
+ * @author Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+
+public final class SwapAdjacentBits {
+ private SwapAdjacentBits() {
+ }
+
+ public static int swapAdjacentBits(int num) {
+ // mask the even bits (0xAAAAAAAA => 10101010...)
+ int evenBits = num & 0xAAAAAAAA;
+
+ // mask the odd bits (0x55555555 => 01010101...)
+ int oddBits = num & 0x55555555;
+
+ // right shift even bits and left shift odd bits
+ evenBits >>= 1;
+ oddBits <<= 1;
+
+ // combine shifted bits
+ return evenBits | oddBits;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java b/src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java
new file mode 100644
index 000000000000..67c986136ab0
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java
@@ -0,0 +1,22 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+class SwapAdjacentBitsTest {
+
+ @ParameterizedTest
+ @CsvSource({
+ "2, 1", // 2 (10 in binary) should become 1 (01 in binary)
+ "43, 23", // 43 should become 23
+ "153, 102", // 153 should become 102
+ "15, 15", // 15 (1111) remains 15 (1111)
+ "0, 0" // 0 (0000) remains 0 (0000)
+ })
+ void
+ testSwapAdjacentBits(int input, int expected) {
+ assertEquals(expected, SwapAdjacentBits.swapAdjacentBits(input));
+ }
+}
From d4fff30eaa1d3a4f5ef292c72a3c9bd1591966ef Mon Sep 17 00:00:00 2001
From: Tuhinm2002 <75078694+Tuhinm2002@users.noreply.github.com>
Date: Thu, 10 Oct 2024 13:02:02 +0530
Subject: [PATCH 033/348] feat : new bit manipulation algo `Single element in
an array` (#5689)
* feat : new algo uniquesubseqcount
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* feat : new bitmanipulation algo
---------
Co-authored-by: Alex Klymenko
---
.../bitmanipulation/SingleElement.java | 39 +++++++++++++++++++
.../bitmanipulation/SingleElementTest.java | 33 ++++++++++++++++
2 files changed, 72 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
new file mode 100644
index 000000000000..85ebdf02db25
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class to find the single non-duplicate element from an array
+ * where all other elements appear twice.
+ *
+ * The algorithm runs in O(n) time complexity and O(1) space complexity
+ * using bitwise XOR.
+ *
+ *
+ * @author Tuhin M
+ */
+public final class SingleElement {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ * Throws an UnsupportedOperationException if attempted.
+ */
+ private SingleElement() {
+ throw new UnsupportedOperationException("Utility Class");
+ }
+
+ /**
+ * Finds the single non-duplicate element in an array where every other
+ * element appears exactly twice. Uses bitwise XOR to achieve O(n) time
+ * complexity and O(1) space complexity.
+ *
+ * @param arr the input array containing integers where every element
+ * except one appears exactly twice
+ * @return the single non-duplicate element
+ */
+ public static int findSingleElement(int[] arr) {
+ int ele = 0;
+ for (int i = 0; i < arr.length; i++) {
+ ele ^= arr[i];
+ }
+ return ele;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java
new file mode 100644
index 000000000000..2e2afe99b0da
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.bitmanipulation;
+
+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 final class SingleElementTest {
+
+ /**
+ * Parameterized test to find the single non-duplicate element
+ * in the given arrays.
+ *
+ * @param arr the input array where every element appears twice except one
+ * @param expected the expected single element result
+ */
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testFindSingleElement(int[] arr, int expected) {
+ assertEquals(expected, SingleElement.findSingleElement(arr));
+ }
+
+ /**
+ * Provides test cases for the parameterized test.
+ *
+ * @return Stream of arguments consisting of arrays and expected results
+ */
+ private static Stream provideTestCases() {
+ return Stream.of(Arguments.of(new int[] {1, 1, 2, 2, 4, 4, 3}, 3), Arguments.of(new int[] {1, 2, 2, 3, 3}, 1), Arguments.of(new int[] {10}, 10));
+ }
+}
From 90d20b3a43642548ecc55e425517583080a81e2a Mon Sep 17 00:00:00 2001
From: Prayas Kumar <71717433+prayas7102@users.noreply.github.com>
Date: Thu, 10 Oct 2024 13:09:22 +0530
Subject: [PATCH 034/348] Add smoothing constant to IDF formula in BM25 to
prevent negative scores (#5696)
Co-authored-by: prayas7102
Co-authored-by: Alex Klymenko
---
.../thealgorithms/searches/BM25InvertedIndex.java | 2 +-
.../searches/BM25InvertedIndexTest.java | 12 +++++++-----
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java b/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
index 1cfd2bbad8e4..aeddc591b32b 100644
--- a/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
+++ b/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java
@@ -215,6 +215,6 @@ private double computeBM25Score(int termFrequency, double docLength, double idf)
*/
private double computeIDF(int docFrequency) {
// Total number of documents in the index
- return Math.log((totalDocuments - docFrequency + 0.5) / (docFrequency + 0.5));
+ return Math.log((totalDocuments - docFrequency + 0.5) / (docFrequency + 0.5) + 1);
}
}
diff --git a/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java b/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
index 8595e0a00683..2017c11dfb3c 100644
--- a/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
+++ b/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java
@@ -50,13 +50,15 @@ void testSearchRanking() {
// Perform search for the term "good"
List results = index.search("good");
assertFalse(results.isEmpty());
-
+ for (SearchResult result : results) {
+ System.out.println(result);
+ }
// Validate the ranking based on the provided relevance scores
- assertEquals(6, results.get(0).getDocId()); // It's a Wonderful Life should be ranked 1st
- assertEquals(7, results.get(1).getDocId()); // The Pursuit of Happyness should be ranked 2nd
+ assertEquals(1, results.get(0).getDocId()); // The Shawshank Redemption should be ranked 1st
+ assertEquals(8, results.get(1).getDocId()); // A Few Good Men should be ranked 2nd
assertEquals(5, results.get(2).getDocId()); // Good Will Hunting should be ranked 3rd
- assertEquals(8, results.get(3).getDocId()); // A Few Good Men should be ranked 4th
- assertEquals(1, results.get(4).getDocId()); // The Shawshank Redemption should be ranked 5th
+ assertEquals(7, results.get(3).getDocId()); // The Pursuit of Happyness should be ranked 4th
+ assertEquals(6, results.get(4).getDocId()); // It's a Wonderful Life should be ranked 5th
// Ensure the relevance scores are in descending order
for (int i = 0; i < results.size() - 1; i++) {
From bd3b754eda50b4634c7496b1355bbe57b2964bea Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 22:26:44 +0530
Subject: [PATCH 035/348] Add EDFScheduling algorithm (#5657)
---
DIRECTORY.md | 6 ++
.../scheduling/EDFScheduling.java | 99 +++++++++++++++++++
.../scheduling/EDFSchedulingTest.java | 69 +++++++++++++
3 files changed, 174 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/scheduling/EDFScheduling.java
create mode 100644 src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index a1a53cb2926c..46affca47109 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -36,6 +36,8 @@
* [OnesComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java)
* [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
* [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
+ * [SingleElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java)
+ * [SwapAdjacentBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java)
* [TwosComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java)
* ciphers
* a5
@@ -476,6 +478,7 @@
* Recursion
* [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java)
* scheduling
+ * [EDFScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java)
* [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java)
* [HighestResponseRatioNextScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java)
* [JobSchedulingWithDeadline](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java)
@@ -649,6 +652,8 @@
* [OnesComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java)
* [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
+ * [SingleElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java)
+ * [SwapAdjacentBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java)
* [TwosComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java)
* ciphers
* a5
@@ -975,6 +980,7 @@
* Recursion
* [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java)
* scheduling
+ * [EDFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java)
* [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java)
* [HighestResponseRatioNextSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java)
* [JobSchedulingWithDeadlineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java)
diff --git a/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java b/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java
new file mode 100644
index 000000000000..5ba79cdbb73a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java
@@ -0,0 +1,99 @@
+package com.thealgorithms.scheduling;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The Earliest Deadline First (EDF) Scheduling class implements a dynamic scheduling algorithm.
+ * It assigns the CPU to processes with the earliest deadlines, ensuring that deadlines are met if possible.
+ * This scheduling algorithm is ideal for real-time systems where meeting deadlines is critical.
+ */
+public final class EDFScheduling {
+ private EDFScheduling() {
+ }
+
+ private List processes;
+
+ /**
+ * Constructs an EDFScheduling object with a list of processes.
+ *
+ * @param processes List of processes to be scheduled.
+ */
+ public EDFScheduling(final List processes) {
+ this.processes = processes;
+ }
+
+ /**
+ * Schedules the processes using Earliest Deadline First (EDF) scheduling.
+ * Processes are sorted by their deadlines, and the method simulates their execution.
+ * It calculates the waiting time and turnaround time for each process.
+ *
+ * @return List of processes after they have been executed in order of earliest deadline first.
+ */
+ public List scheduleProcesses() {
+ processes.sort(Comparator.comparingInt(Process::getDeadline));
+
+ int currentTime = 0;
+ List executedProcesses = new ArrayList<>();
+
+ for (Process process : processes) {
+ process.setWaitingTime(currentTime);
+ currentTime += process.getBurstTime();
+ process.setTurnAroundTime(process.getWaitingTime() + process.getBurstTime());
+
+ if (currentTime > process.getDeadline()) {
+ System.out.println("Warning: Process " + process.getProcessId() + " missed its deadline.");
+ }
+
+ executedProcesses.add(process);
+ }
+
+ return executedProcesses;
+ }
+
+ /**
+ * The Process class represents a process with an ID, burst time, deadline, waiting time, and turnaround time.
+ */
+ public static class Process {
+ private String processId;
+ private int burstTime;
+ private int deadline;
+ private int waitingTime;
+ private int turnAroundTime;
+
+ public Process(String processId, int burstTime, int deadline) {
+ this.processId = processId;
+ this.burstTime = burstTime;
+ this.deadline = deadline;
+ }
+
+ public String getProcessId() {
+ return processId;
+ }
+
+ public int getBurstTime() {
+ return burstTime;
+ }
+
+ public int getDeadline() {
+ return deadline;
+ }
+
+ public int getWaitingTime() {
+ return waitingTime;
+ }
+
+ public void setWaitingTime(int waitingTime) {
+ this.waitingTime = waitingTime;
+ }
+
+ public int getTurnAroundTime() {
+ return turnAroundTime;
+ }
+
+ public void setTurnAroundTime(int turnAroundTime) {
+ this.turnAroundTime = turnAroundTime;
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java
new file mode 100644
index 000000000000..8ce290cb246f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java
@@ -0,0 +1,69 @@
+package com.thealgorithms.scheduling;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class EDFSchedulingTest {
+
+ private List processes;
+
+ @BeforeEach
+ public void setup() {
+ processes = createProcesses();
+ }
+
+ @Test
+ public void testEDFScheduling() {
+ EDFScheduling edfScheduling = new EDFScheduling(processes);
+ List executedProcesses = edfScheduling.scheduleProcesses();
+
+ // Assert the correct number of processes
+ assertEquals(3, executedProcesses.size());
+
+ // Assert that processes are executed in order of earliest deadline first
+ EDFScheduling.Process process1 = executedProcesses.get(0);
+ assertEquals("P2", process1.getProcessId());
+ assertEquals(0, process1.getWaitingTime());
+ assertEquals(3, process1.getTurnAroundTime());
+
+ EDFScheduling.Process process2 = executedProcesses.get(1);
+ assertEquals("P1", process2.getProcessId());
+ assertEquals(3, process2.getWaitingTime());
+ assertEquals(10, process2.getTurnAroundTime());
+
+ EDFScheduling.Process process3 = executedProcesses.get(2);
+ assertEquals("P3", process3.getProcessId());
+ assertEquals(10, process3.getWaitingTime());
+ assertEquals(18, process3.getTurnAroundTime());
+ }
+
+ @Test
+ public void testProcessMissedDeadline() {
+ // Modify the deadline of a process to ensure it will miss its deadline
+ processes.get(1).setTurnAroundTime(5); // Set P1's deadline to 5 (which it will miss)
+
+ EDFScheduling edfScheduling = new EDFScheduling(processes);
+ edfScheduling.scheduleProcesses();
+
+ // Check if the process with ID "P1" missed its deadline
+ assertEquals("P1", processes.get(1).getProcessId());
+ }
+
+ private List createProcesses() {
+ // Process ID, Burst Time, Deadline
+ EDFScheduling.Process process1 = new EDFScheduling.Process("P1", 7, 10); // 7 burst time, 10 deadline
+ EDFScheduling.Process process2 = new EDFScheduling.Process("P2", 3, 5); // 3 burst time, 5 deadline
+ EDFScheduling.Process process3 = new EDFScheduling.Process("P3", 8, 18); // 8 burst time, 18 deadline
+
+ List processes = new ArrayList<>();
+ processes.add(process1);
+ processes.add(process2);
+ processes.add(process3);
+
+ return processes;
+ }
+}
From e728aa7d6fc113fddb5cfff3fab337954978229a Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 22:46:04 +0530
Subject: [PATCH 036/348] Add tests, remove `main`, enhance docs in
`MatrixChainMultiplication` (#5658)
---
DIRECTORY.md | 1 +
.../MatrixChainMultiplication.java | 194 ++++++++++--------
.../MatrixChainMultiplicationTest.java | 54 +++++
3 files changed, 163 insertions(+), 86 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 46affca47109..1407ba199756 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -814,6 +814,7 @@
* [LongestIncreasingSubsequenceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceTests.java)
* [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java)
* [LongestValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java)
+ * [MatrixChainMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java)
* [MinimumPathSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java)
* [MinimumSumPartitionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java)
* [OptimalJobSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/OptimalJobSchedulingTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java b/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java
index 45568d21f295..1edb7207dee2 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java
@@ -2,38 +2,32 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Scanner;
+/**
+ * The MatrixChainMultiplication class provides functionality to compute the
+ * optimal way to multiply a sequence of matrices. The optimal multiplication
+ * order is determined using dynamic programming, which minimizes the total
+ * number of scalar multiplications required.
+ */
public final class MatrixChainMultiplication {
private MatrixChainMultiplication() {
}
- private static final Scanner SCANNER = new Scanner(System.in);
- private static final ArrayList MATRICES = new ArrayList<>();
- private static int size;
+ // Matrices to store minimum multiplication costs and split points
private static int[][] m;
private static int[][] s;
private static int[] p;
- public static void main(String[] args) {
- int count = 1;
- while (true) {
- String[] mSize = input("input size of matrix A(" + count + ") ( ex. 10 20 ) : ");
- int col = Integer.parseInt(mSize[0]);
- if (col == 0) {
- break;
- }
- int row = Integer.parseInt(mSize[1]);
-
- Matrix matrix = new Matrix(count, col, row);
- MATRICES.add(matrix);
- count++;
- }
- for (Matrix m : MATRICES) {
- System.out.format("A(%d) = %2d x %2d%n", m.count(), m.col(), m.row());
- }
-
- size = MATRICES.size();
+ /**
+ * Calculates the optimal order for multiplying a given list of matrices.
+ *
+ * @param matrices an ArrayList of Matrix objects representing the matrices
+ * to be multiplied.
+ * @return a Result object containing the matrices of minimum costs and
+ * optimal splits.
+ */
+ public static Result calculateMatrixChainOrder(ArrayList matrices) {
+ int size = matrices.size();
m = new int[size + 1][size + 1];
s = new int[size + 1][size + 1];
p = new int[size + 1];
@@ -44,51 +38,20 @@ public static void main(String[] args) {
}
for (int i = 0; i < p.length; i++) {
- p[i] = i == 0 ? MATRICES.get(i).col() : MATRICES.get(i - 1).row();
+ p[i] = i == 0 ? matrices.get(i).col() : matrices.get(i - 1).row();
}
- matrixChainOrder();
- for (int i = 0; i < size; i++) {
- System.out.print("-------");
- }
- System.out.println();
- printArray(m);
- for (int i = 0; i < size; i++) {
- System.out.print("-------");
- }
- System.out.println();
- printArray(s);
- for (int i = 0; i < size; i++) {
- System.out.print("-------");
- }
- System.out.println();
-
- System.out.println("Optimal solution : " + m[1][size]);
- System.out.print("Optimal parens : ");
- printOptimalParens(1, size);
- }
-
- private static void printOptimalParens(int i, int j) {
- if (i == j) {
- System.out.print("A" + i);
- } else {
- System.out.print("(");
- printOptimalParens(i, s[i][j]);
- printOptimalParens(s[i][j] + 1, j);
- System.out.print(")");
- }
- }
-
- private static void printArray(int[][] array) {
- for (int i = 1; i < size + 1; i++) {
- for (int j = 1; j < size + 1; j++) {
- System.out.printf("%7d", array[i][j]);
- }
- System.out.println();
- }
+ matrixChainOrder(size);
+ return new Result(m, s);
}
- private static void matrixChainOrder() {
+ /**
+ * A helper method that computes the minimum cost of multiplying
+ * the matrices using dynamic programming.
+ *
+ * @param size the number of matrices in the multiplication sequence.
+ */
+ private static void matrixChainOrder(int size) {
for (int i = 1; i < size + 1; i++) {
m[i][i] = 0;
}
@@ -109,33 +72,92 @@ private static void matrixChainOrder() {
}
}
- private static String[] input(String string) {
- System.out.print(string);
- return (SCANNER.nextLine().split(" "));
- }
-}
-
-class Matrix {
+ /**
+ * The Result class holds the results of the matrix chain multiplication
+ * calculation, including the matrix of minimum costs and split points.
+ */
+ public static class Result {
+ private final int[][] m;
+ private final int[][] s;
+
+ /**
+ * Constructs a Result object with the specified matrices of minimum
+ * costs and split points.
+ *
+ * @param m the matrix of minimum multiplication costs.
+ * @param s the matrix of optimal split points.
+ */
+ public Result(int[][] m, int[][] s) {
+ this.m = m;
+ this.s = s;
+ }
- private final int count;
- private final int col;
- private final int row;
+ /**
+ * Returns the matrix of minimum multiplication costs.
+ *
+ * @return the matrix of minimum multiplication costs.
+ */
+ public int[][] getM() {
+ return m;
+ }
- Matrix(int count, int col, int row) {
- this.count = count;
- this.col = col;
- this.row = row;
+ /**
+ * Returns the matrix of optimal split points.
+ *
+ * @return the matrix of optimal split points.
+ */
+ public int[][] getS() {
+ return s;
+ }
}
- int count() {
- return count;
- }
+ /**
+ * The Matrix class represents a matrix with its dimensions and count.
+ */
+ public static class Matrix {
+ private final int count;
+ private final int col;
+ private final int row;
+
+ /**
+ * Constructs a Matrix object with the specified count, number of columns,
+ * and number of rows.
+ *
+ * @param count the identifier for the matrix.
+ * @param col the number of columns in the matrix.
+ * @param row the number of rows in the matrix.
+ */
+ public Matrix(int count, int col, int row) {
+ this.count = count;
+ this.col = col;
+ this.row = row;
+ }
- int col() {
- return col;
- }
+ /**
+ * Returns the identifier of the matrix.
+ *
+ * @return the identifier of the matrix.
+ */
+ public int count() {
+ return count;
+ }
- int row() {
- return row;
+ /**
+ * Returns the number of columns in the matrix.
+ *
+ * @return the number of columns in the matrix.
+ */
+ public int col() {
+ return col;
+ }
+
+ /**
+ * Returns the number of rows in the matrix.
+ *
+ * @return the number of rows in the matrix.
+ */
+ public int row() {
+ return row;
+ }
}
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java
new file mode 100644
index 000000000000..2bee0ca52918
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+import org.junit.jupiter.api.Test;
+
+class MatrixChainMultiplicationTest {
+
+ @Test
+ void testMatrixCreation() {
+ MatrixChainMultiplication.Matrix matrix1 = new MatrixChainMultiplication.Matrix(1, 10, 20);
+ MatrixChainMultiplication.Matrix matrix2 = new MatrixChainMultiplication.Matrix(2, 20, 30);
+
+ assertEquals(1, matrix1.count());
+ assertEquals(10, matrix1.col());
+ assertEquals(20, matrix1.row());
+
+ assertEquals(2, matrix2.count());
+ assertEquals(20, matrix2.col());
+ assertEquals(30, matrix2.row());
+ }
+
+ @Test
+ void testMatrixChainOrder() {
+ // Create a list of matrices to be multiplied
+ ArrayList matrices = new ArrayList<>();
+ matrices.add(new MatrixChainMultiplication.Matrix(1, 10, 20)); // A(1) = 10 x 20
+ matrices.add(new MatrixChainMultiplication.Matrix(2, 20, 30)); // A(2) = 20 x 30
+
+ // Calculate matrix chain order
+ MatrixChainMultiplication.Result result = MatrixChainMultiplication.calculateMatrixChainOrder(matrices);
+
+ // Expected cost of multiplying A(1) and A(2)
+ int expectedCost = 6000; // The expected optimal cost of multiplying A(1)(10x20) and A(2)(20x30)
+ int actualCost = result.getM()[1][2];
+
+ assertEquals(expectedCost, actualCost);
+ }
+
+ @Test
+ void testOptimalParentheses() {
+ // Create a list of matrices to be multiplied
+ ArrayList matrices = new ArrayList<>();
+ matrices.add(new MatrixChainMultiplication.Matrix(1, 10, 20)); // A(1) = 10 x 20
+ matrices.add(new MatrixChainMultiplication.Matrix(2, 20, 30)); // A(2) = 20 x 30
+
+ // Calculate matrix chain order
+ MatrixChainMultiplication.Result result = MatrixChainMultiplication.calculateMatrixChainOrder(matrices);
+
+ // Check the optimal split for parentheses
+ assertEquals(1, result.getS()[1][2]); // s[1][2] should point to the optimal split
+ }
+}
From c152c38d1b3c429db8b8054ab31cc07252fc89fa Mon Sep 17 00:00:00 2001
From: Andrii Siriak
Date: Thu, 10 Oct 2024 21:03:56 +0300
Subject: [PATCH 037/348] Update build.yml (#5709)
---
.github/workflows/build.yml | 2 +-
.github/workflows/codeql.yml | 2 +-
.github/workflows/infer.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 14a4ce5fe0f5..8178509e7258 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -10,7 +10,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: 21
- distribution: 'adopt'
+ distribution: 'temurin'
- name: Build with Maven
run: mvn --batch-mode --update-snapshots verify
- name: Upload coverage to codecov (tokenless)
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index ff76b1af452a..a0908a2b57d9 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -30,7 +30,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: 21
- distribution: 'adopt'
+ distribution: 'temurin'
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
index 121a6c728fbb..a07c6f458083 100644
--- a/.github/workflows/infer.yml
+++ b/.github/workflows/infer.yml
@@ -18,7 +18,7 @@ jobs:
uses: actions/setup-java@v4
with:
java-version: 21
- distribution: 'adopt'
+ distribution: 'temurin'
- name: Set up OCaml
uses: ocaml/setup-ocaml@v3
From 44b0fc9408a7cf5848cb8e822ccea57a79e5dfb4 Mon Sep 17 00:00:00 2001
From: Guhapriya Dharmaraj <76595809+Guhapriya01@users.noreply.github.com>
Date: Thu, 10 Oct 2024 23:37:44 +0530
Subject: [PATCH 038/348] Implement Maximum Sum of Non-Adjacent Elements
(#5544)
---
.../MaximumSumOfNonAdjacentElements.java | 95 +++++++++++++++++++
.../MaximumSumOfNonAdjacentElementsTest.java | 52 ++++++++++
2 files changed, 147 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java b/src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java
new file mode 100644
index 000000000000..49af3ae3db88
--- /dev/null
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java
@@ -0,0 +1,95 @@
+package com.thealgorithms.dynamicprogramming;
+
+/**
+ * Class to find the maximum sum of non-adjacent elements in an array. This
+ * class contains two approaches: one with O(n) space complexity and another
+ * with O(1) space optimization. For more information, refer to
+ * https://takeuforward.org/data-structure/maximum-sum-of-non-adjacent-elements-dp-5/
+ */
+final class MaximumSumOfNonAdjacentElements {
+
+ private MaximumSumOfNonAdjacentElements() {
+ }
+
+ /**
+ * Approach 1: Uses a dynamic programming array to store the maximum sum at
+ * each index. Time Complexity: O(n) - where n is the length of the input
+ * array. Space Complexity: O(n) - due to the additional dp array.
+ * @param arr The input array of integers.
+ * @return The maximum sum of non-adjacent elements.
+ */
+ public static int getMaxSumApproach1(int[] arr) {
+ if (arr.length == 0) {
+ return 0; // Check for empty array
+ }
+
+ int n = arr.length;
+ int[] dp = new int[n];
+
+ // Base case: Maximum sum if only one element is present.
+ dp[0] = arr[0];
+
+ for (int ind = 1; ind < n; ind++) {
+
+ // Case 1: Do not take the current element, carry forward the previous max
+ // sum.
+ int notTake = dp[ind - 1];
+
+ // Case 2: Take the current element, add it to the max sum up to two
+ // indices before.
+ int take = arr[ind];
+ if (ind > 1) {
+ take += dp[ind - 2];
+ }
+
+ // Store the maximum of both choices in the dp array.
+ dp[ind] = Math.max(take, notTake);
+ }
+
+ return dp[n - 1];
+ }
+
+ /**
+ * Approach 2: Optimized space complexity approach using two variables instead
+ * of an array. Time Complexity: O(n) - where n is the length of the input
+ * array. Space Complexity: O(1) - as it only uses constant space for two
+ * variables.
+ * @param arr The input array of integers.
+ * @return The maximum sum of non-adjacent elements.
+ */
+ public static int getMaxSumApproach2(int[] arr) {
+ if (arr.length == 0) {
+ return 0; // Check for empty array
+ }
+
+ int n = arr.length;
+
+ // Two variables to keep track of previous two results:
+ // prev1 = max sum up to the last element (n-1)
+ // prev2 = max sum up to the element before last (n-2)
+
+ int prev1 = arr[0]; // Base case: Maximum sum for the first element.
+ int prev2 = 0;
+
+ for (int ind = 1; ind < n; ind++) {
+ // Case 1: Do not take the current element, keep the last max sum.
+ int notTake = prev1;
+
+ // Case 2: Take the current element and add it to the result from two
+ // steps back.
+ int take = arr[ind];
+ if (ind > 1) {
+ take += prev2;
+ }
+
+ // Calculate the current maximum sum and update previous values.
+ int current = Math.max(take, notTake);
+
+ // Shift prev1 and prev2 for the next iteration.
+ prev2 = prev1;
+ prev1 = current;
+ }
+
+ return prev1;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java
new file mode 100644
index 000000000000..3f312d86462e
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java
@@ -0,0 +1,52 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class MaximumSumOfNonAdjacentElementsTest {
+
+ // Tests for Approach1
+ @Test
+ public void testGetMaxSumApproach1WithEmptyArray() {
+ assertEquals(0, MaximumSumOfNonAdjacentElements.getMaxSumApproach1(new int[] {})); // Empty array
+ }
+
+ @Test
+ public void testGetMaxSumApproach1WithSingleElement() {
+ assertEquals(1, MaximumSumOfNonAdjacentElements.getMaxSumApproach1(new int[] {1})); // Single element
+ }
+
+ @Test
+ public void testGetMaxSumApproach1WithTwoElementsTakeMax() {
+ assertEquals(2, MaximumSumOfNonAdjacentElements.getMaxSumApproach1(new int[] {1, 2})); // Take max of both
+ }
+
+ @Test
+ public void testGetMaxSumApproach1WithMultipleElements() {
+ assertEquals(15, MaximumSumOfNonAdjacentElements.getMaxSumApproach1(new int[] {3, 2, 5, 10, 7})); // 3 + 7 + 5
+ assertEquals(10, MaximumSumOfNonAdjacentElements.getMaxSumApproach1(new int[] {5, 1, 1, 5})); // 5 + 5
+ }
+
+ // Tests for Approach2
+ @Test
+ public void testGetMaxSumApproach2WithEmptyArray() {
+ assertEquals(0, MaximumSumOfNonAdjacentElements.getMaxSumApproach2(new int[] {})); // Empty array
+ }
+
+ @Test
+ public void testGetMaxSumApproach2WithSingleElement() {
+ assertEquals(1, MaximumSumOfNonAdjacentElements.getMaxSumApproach2(new int[] {1})); // Single element
+ }
+
+ @Test
+ public void testGetMaxSumApproach2WithTwoElementsTakeMax() {
+ assertEquals(2, MaximumSumOfNonAdjacentElements.getMaxSumApproach2(new int[] {1, 2})); // Take max of both
+ }
+
+ @Test
+ public void testGetMaxSumApproach2WithMultipleElements() {
+ assertEquals(15, MaximumSumOfNonAdjacentElements.getMaxSumApproach2(new int[] {3, 2, 5, 10, 7})); // 3 + 7 + 5
+ assertEquals(10, MaximumSumOfNonAdjacentElements.getMaxSumApproach2(new int[] {5, 1, 1, 5})); // 5 + 5
+ }
+}
From 41f7e6aa9d0b8a60639681d5668469c705b00590 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 23:41:43 +0530
Subject: [PATCH 039/348] Add tests, improve docs in `NewManShanksPrime`
(#5660)
---
DIRECTORY.md | 3 +
.../dynamicprogramming/NewManShanksPrime.java | 35 ++++++--
.../NewManShanksPrimeTest.java | 80 +++++++++++++++++++
3 files changed, 112 insertions(+), 6 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 1407ba199756..4afe7c78e0eb 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -262,6 +262,7 @@
* [LongestValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java)
* [MatrixChainMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java)
* [MatrixChainRecursiveTopDownMemoisation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java)
+ * [MaximumSumOfNonAdjacentElements](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java)
* [MinimumPathSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumPathSum.java)
* [MinimumSumPartition](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java)
* [NewManShanksPrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java)
@@ -815,8 +816,10 @@
* [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java)
* [LongestValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java)
* [MatrixChainMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java)
+ * [MaximumSumOfNonAdjacentElementsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java)
* [MinimumPathSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java)
* [MinimumSumPartitionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java)
+ * [NewManShanksPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java)
* [OptimalJobSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/OptimalJobSchedulingTest.java)
* [PalindromicPartitioningTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioningTest.java)
* [PartitionProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PartitionProblemTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java b/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java
index d15ea1f78a78..3db40148f1c2 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java
@@ -1,25 +1,48 @@
package com.thealgorithms.dynamicprogramming;
/**
+ * The NewManShanksPrime class provides a method to determine whether the nth
+ * New Man Shanks prime matches an expected answer.
+ *
+ *
This is based on the New Man Shanks prime sequence defined by the recurrence
+ * relation:
For more information on New Man Shanks primes, please refer to the
+ *
+ * Wikipedia article.
+ *
+ *
Note: The class is designed to be non-instantiable.
+ *
* @author Siddhant Swarup Mallick
- * Program description - To find the New Man Shanks Prime.
- * Wikipedia
*/
public final class NewManShanksPrime {
private NewManShanksPrime() {
}
+ /**
+ * Calculates the nth New Man Shanks prime and checks if it equals the
+ * expected answer.
+ *
+ * @param n the index of the New Man Shanks prime to calculate (0-based).
+ * @param expectedAnswer the expected value of the nth New Man Shanks prime.
+ * @return true if the calculated nth New Man Shanks prime matches the
+ * expected answer; false otherwise.
+ */
public static boolean nthManShanksPrime(int n, int expectedAnswer) {
int[] a = new int[n + 1];
- // array of n+1 size is initialized
a[0] = 1;
a[1] = 1;
- // The 0th and 1st index position values are fixed. They are initialized as 1
+
for (int i = 2; i <= n; i++) {
a[i] = 2 * a[i - 1] + a[i - 2];
}
- // The loop is continued till n
+
return a[n] == expectedAnswer;
- // returns true if calculated answer matches with expected answer
}
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java
new file mode 100644
index 000000000000..a16ad67d6470
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java
@@ -0,0 +1,80 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the NewManShanksPrime class.
+ * This test class verifies the correctness of the nthManShanksPrime method
+ * for various input cases.
+ */
+class NewManShanksPrimeTest {
+
+ /**
+ * Test case for the 1st New Man Shanks prime.
+ * The expected answer is 1.
+ */
+ @Test
+ void testNthManShanksPrime1() {
+ int n = 1;
+ int expectedAnswer = 1;
+ assertTrue(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 1st New Man Shanks prime should be 1.");
+ }
+
+ /**
+ * Test case for the 2nd New Man Shanks prime.
+ * The expected answer is 3.
+ */
+ @Test
+ void testNthManShanksPrime2() {
+ int n = 2;
+ int expectedAnswer = 3;
+ assertTrue(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 2nd New Man Shanks prime should be 3.");
+ }
+
+ /**
+ * Test case for the 3rd New Man Shanks prime.
+ * The expected answer is 7.
+ */
+ @Test
+ void testNthManShanksPrime3() {
+ int n = 3;
+ int expectedAnswer = 7;
+ assertTrue(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 3rd New Man Shanks prime should be 7.");
+ }
+
+ /**
+ * Test case for the 4th New Man Shanks prime.
+ * The expected answer is 17.
+ */
+ @Test
+ void testNthManShanksPrime4() {
+ int n = 4;
+ int expectedAnswer = 17;
+ assertTrue(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 4th New Man Shanks prime should be 17.");
+ }
+
+ /**
+ * Test case for the 5th New Man Shanks prime.
+ * The expected answer is 41.
+ */
+ @Test
+ void testNthManShanksPrime5() {
+ int n = 5;
+ int expectedAnswer = 41;
+ assertTrue(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 5th New Man Shanks prime should be 41.");
+ }
+
+ /**
+ * Test case with an incorrect expected answer.
+ * For n = 2, the expected answer is 3.
+ */
+ @Test
+ void testNthManShanksPrimeIncorrectAnswer() {
+ int n = 2;
+ int expectedAnswer = 4; // Incorrect expected value
+ assertFalse(NewManShanksPrime.nthManShanksPrime(n, expectedAnswer), "The 2nd New Man Shanks prime should not be 4.");
+ }
+}
From c18dbc43b536e1c9006dbf0ef13808a6ce1698c8 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 23:45:35 +0530
Subject: [PATCH 040/348] Add tests, add `IllegalArgumentException` in
`RodCutting` (#5661)
---
DIRECTORY.md | 1 +
.../dynamicprogramming/RodCutting.java | 4 +
.../dynamicprogramming/RodCuttingTest.java | 96 +++++++++++++++++++
3 files changed, 101 insertions(+)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 4afe7c78e0eb..fb5ff2fed57b 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -824,6 +824,7 @@
* [PalindromicPartitioningTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioningTest.java)
* [PartitionProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PartitionProblemTest.java)
* [RegexMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/RegexMatchingTest.java)
+ * [RodCuttingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java)
* [ShortestCommonSupersequenceLengthTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLengthTest.java)
* [SubsetCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetCountTest.java)
* [SubsetSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java b/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java
index f56fc4ff5641..76b341e2c823 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java
@@ -15,9 +15,13 @@ private RodCutting() {
* @param price An array representing the prices of different pieces, where price[i-1]
* represents the price of a piece of length i.
* @param n The length of the rod to be cut.
+ * @throws IllegalArgumentException if the price array is null or empty, or if n is less than 0.
* @return The maximum obtainable value.
*/
public static int cutRod(int[] price, int n) {
+ if (price == null || price.length == 0) {
+ throw new IllegalArgumentException("Price array cannot be null or empty.");
+ }
// Create an array to store the maximum obtainable values for each rod length.
int[] val = new int[n + 1];
val[0] = 0;
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java
new file mode 100644
index 000000000000..39497a768397
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java
@@ -0,0 +1,96 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the RodCutting class.
+ * This test class verifies the correctness of the cutRod method for various input cases.
+ */
+class RodCuttingTest {
+
+ /**
+ * Test case for cutting a rod of length 1.
+ * The expected maximum obtainable value is the price of the piece of length 1.
+ */
+ @Test
+ void testCutRodLength1() {
+ int[] prices = {1}; // Price for piece of length 1
+ int length = 1;
+ int expectedValue = 1;
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 1 should be 1.");
+ }
+
+ /**
+ * Test case for cutting a rod of length 2.
+ * The expected maximum obtainable value is the best price combination for length 2.
+ */
+ @Test
+ void testCutRodLength2() {
+ int[] prices = {1, 5}; // Prices for lengths 1 and 2
+ int length = 2;
+ int expectedValue = 5; // Best value is to cut it into a single piece of length 2
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 2 should be 5.");
+ }
+
+ /**
+ * Test case for cutting a rod of length 3.
+ * The expected maximum obtainable value is the best price combination for length 3.
+ */
+ @Test
+ void testCutRodLength3() {
+ int[] prices = {1, 5, 8}; // Prices for lengths 1, 2, and 3
+ int length = 3;
+ int expectedValue = 8; // Best value is to cut it into a single piece of length 3
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 3 should be 8.");
+ }
+
+ /**
+ * Test case for cutting a rod of length 4.
+ * The expected maximum obtainable value is the best price combination for length 4.
+ */
+ @Test
+ void testCutRodLength4() {
+ int[] prices = {1, 5, 8, 9}; // Prices for lengths 1, 2, 3, and 4
+ int length = 4;
+ int expectedValue = 10; // Best value is to cut it into two pieces of length 2
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 4 should be 10.");
+ }
+
+ /**
+ * Test case for cutting a rod of length 5.
+ * The expected maximum obtainable value is the best price combination for length 5.
+ */
+ @Test
+ void testCutRodLength5() {
+ int[] prices = {1, 5, 8, 9, 10}; // Prices for lengths 1, 2, 3, 4, and 5
+ int length = 5;
+ int expectedValue = 13; // Best value is to cut it into pieces of lengths 2 and 3
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 5 should be 13.");
+ }
+
+ /**
+ * Test case for cutting a rod of length 0.
+ * The expected maximum obtainable value should be 0 since the rod has no length.
+ */
+ @Test
+ void testCutRodLength0() {
+ int[] prices = {1, 5, 8, 9, 10}; // Prices are irrelevant for length 0
+ int length = 0;
+ int expectedValue = 0; // No value obtainable from a rod of length 0
+ assertEquals(expectedValue, RodCutting.cutRod(prices, length), "The maximum obtainable value for a rod of length 0 should be 0.");
+ }
+
+ /**
+ * Test case for an empty prices array.
+ * The expected maximum obtainable value should still be 0 for any length.
+ */
+ @Test
+ void testCutRodEmptyPrices() {
+ int[] prices = {};
+ int length = 5;
+ assertThrows(IllegalArgumentException.class, () -> RodCutting.cutRod(prices, length), "An empty prices array should throw an IllegalArgumentException.");
+ }
+}
From ac2c88ca9f60b1d4f97c6e3e9a0bbb87a79dcf84 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Thu, 10 Oct 2024 23:49:37 +0530
Subject: [PATCH 041/348] =?UTF-8?q?Add=20tests,=20add=20`IllegalArgumentEx?=
=?UTF-8?q?ception`,=20remove=20`main`=20in=20`WineProb=E2=80=A6=20(#5662)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
DIRECTORY.md | 1 +
.../dynamicprogramming/WineProblem.java | 70 ++++++++++++------
.../dynamicprogramming/WineProblemTest.java | 72 +++++++++++++++++++
3 files changed, 120 insertions(+), 23 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index fb5ff2fed57b..1e5210730b4d 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -833,6 +833,7 @@
* [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java)
* [UniqueSubsequencesCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java)
* [WildcardMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java)
+ * [WineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java)
* geometry
* [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java)
* greedyalgorithms
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java b/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java
index 0f5359f4d95e..022b43184a88 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java
@@ -1,21 +1,40 @@
package com.thealgorithms.dynamicprogramming;
/**
- * Imagine you have a collection of N wines placed next to each other on the
- * shelf. The price of ith wine is pi(Prices of different wines are different).
- * Because wine gets better every year supposing today is year 1, on year y the
- * price would be y*pi i.e y times the value of the initial year. You want to
- * sell all wines but you have to sell one wine per year. One more constraint on
- * each year you are allowed to sell either leftmost or rightmost wine on the
- * shelf. You are not allowed to reorder. You have to find the maximum profit
+ * The WineProblem class provides a solution to the wine selling problem.
+ * Given a collection of N wines with different prices, the objective is to maximize profit by selling
+ * one wine each year, considering the constraint that only the leftmost or rightmost wine can be sold
+ * at any given time.
*
+ * The price of the ith wine is pi, and the selling price increases by a factor of the year in which
+ * it is sold. This class implements three approaches to solve the problem:
+ *
+ * 1. **Recursion**: A straightforward recursive method that computes the maximum profit.
+ * - Time Complexity: O(2^N)
+ * - Space Complexity: O(N) due to recursive calls.
+ *
+ * 2. **Top-Down Dynamic Programming (Memoization)**: This approach caches the results of subproblems
+ * to avoid redundant computations.
+ * - Time Complexity: O(N^2)
+ * - Space Complexity: O(N^2) for the storage of results and O(N) for recursion stack.
+ *
+ * 3. **Bottom-Up Dynamic Programming (Tabulation)**: This method builds a table iteratively to
+ * compute the maximum profit for all possible subproblems.
+ * - Time Complexity: O(N^2)
+ * - Space Complexity: O(N^2) for the table.
*/
public final class WineProblem {
private WineProblem() {
}
- // Method 1: Using Recursion
- // Time Complexity=0(2^N) Space Complexity=Recursion extra space
+ /**
+ * Calculate maximum profit using recursion.
+ *
+ * @param arr Array of wine prices.
+ * @param si Start index of the wine to consider.
+ * @param ei End index of the wine to consider.
+ * @return Maximum profit obtainable by selling the wines.
+ */
public static int wpRecursion(int[] arr, int si, int ei) {
int n = arr.length;
int year = (n - (ei - si + 1)) + 1;
@@ -29,8 +48,15 @@ public static int wpRecursion(int[] arr, int si, int ei) {
return Math.max(start, end);
}
- // Method 2: Top-Down DP(Memoization)
- // Time Complexity=0(N*N) Space Complexity=0(N*N)+Recursion extra space
+ /**
+ * Calculate maximum profit using top-down dynamic programming with memoization.
+ *
+ * @param arr Array of wine prices.
+ * @param si Start index of the wine to consider.
+ * @param ei End index of the wine to consider.
+ * @param strg 2D array to store results of subproblems.
+ * @return Maximum profit obtainable by selling the wines.
+ */
public static int wptd(int[] arr, int si, int ei, int[][] strg) {
int n = arr.length;
int year = (n - (ei - si + 1)) + 1;
@@ -45,15 +71,22 @@ public static int wptd(int[] arr, int si, int ei, int[][] strg) {
int end = wptd(arr, si, ei - 1, strg) + arr[ei] * year;
int ans = Math.max(start, end);
-
strg[si][ei] = ans;
return ans;
}
- // Method 3: Bottom-Up DP(Tabulation)
- // Time Complexity=0(N*N/2)->0(N*N) Space Complexity=0(N*N)
+ /**
+ * Calculate maximum profit using bottom-up dynamic programming with tabulation.
+ *
+ * @param arr Array of wine prices.
+ * @throws IllegalArgumentException if the input array is null or empty.
+ * @return Maximum profit obtainable by selling the wines.
+ */
public static int wpbu(int[] arr) {
+ if (arr == null || arr.length == 0) {
+ throw new IllegalArgumentException("Input array cannot be null or empty.");
+ }
int n = arr.length;
int[][] strg = new int[n][n];
@@ -73,13 +106,4 @@ public static int wpbu(int[] arr) {
}
return strg[0][n - 1];
}
-
- public static void main(String[] args) {
- int[] arr = {2, 3, 5, 1, 4};
- System.out.println("Method 1: " + wpRecursion(arr, 0, arr.length - 1));
- System.out.println("Method 2: " + wptd(arr, 0, arr.length - 1, new int[arr.length][arr.length]));
- System.out.println("Method 3: " + wpbu(arr));
- }
}
-// Memoization vs Tabulation : https://www.geeksforgeeks.org/tabulation-vs-memoization/
-// Question Link : https://www.geeksforgeeks.org/maximum-profit-sale-wines/
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java
new file mode 100644
index 000000000000..fbcc2c6f3a83
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java
@@ -0,0 +1,72 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the WineProblem class.
+ * This test class verifies the correctness of the wine selling problem solutions.
+ */
+class WineProblemTest {
+
+ /**
+ * Test for wpRecursion method.
+ */
+ @Test
+ void testWpRecursion() {
+ int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
+ int expectedProfit = 50; // The expected maximum profit
+ assertEquals(expectedProfit, WineProblem.wpRecursion(wines, 0, wines.length - 1), "The maximum profit using recursion should be 50.");
+ }
+
+ /**
+ * Test for wptd method (Top-Down DP with Memoization).
+ */
+ @Test
+ void testWptd() {
+ int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
+ int expectedProfit = 50; // The expected maximum profit
+ assertEquals(expectedProfit, WineProblem.wptd(wines, 0, wines.length - 1, new int[wines.length][wines.length]), "The maximum profit using top-down DP should be 50.");
+ }
+
+ /**
+ * Test for wpbu method (Bottom-Up DP with Tabulation).
+ */
+ @Test
+ void testWpbu() {
+ int[] wines = {2, 3, 5, 1, 4}; // Prices of wines
+ int expectedProfit = 50; // The expected maximum profit
+ assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit using bottom-up DP should be 50.");
+ }
+
+ /**
+ * Test with a single wine.
+ */
+ @Test
+ void testSingleWine() {
+ int[] wines = {10}; // Only one wine
+ int expectedProfit = 10; // Selling the only wine at year 1
+ assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit for a single wine should be 10.");
+ }
+
+ /**
+ * Test with multiple wines of the same price.
+ */
+ @Test
+ void testSamePriceWines() {
+ int[] wines = {5, 5, 5}; // All wines have the same price
+ int expectedProfit = 30; // Profit is 5 * (1 + 2 + 3)
+ assertEquals(expectedProfit, WineProblem.wpbu(wines), "The maximum profit with same price wines should be 30.");
+ }
+
+ /**
+ * Test with no wines.
+ */
+ @Test
+ void testNoWines() {
+ int[] wines = {};
+ assertThrows(IllegalArgumentException.class, () -> WineProblem.wpbu(wines), "The maximum profit for no wines should throw an IllegalArgumentException.");
+ }
+}
From ca5fbbf0a9748680cb1bf56b19ffc7b026b4c3ed Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 00:52:42 +0530
Subject: [PATCH 042/348] Add tests, remove `main` in `BinarySearch` (#5663)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/BinarySearch.java | 26 -----
.../searches/BinarySearchTest.java | 108 ++++++++++++++++++
3 files changed, 109 insertions(+), 26 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/BinarySearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 1e5210730b4d..cc4e90a4ffdc 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -997,6 +997,7 @@
* [SRTFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SRTFSchedulingTest.java)
* searches
* [BinarySearch2dArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java)
+ * [BinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BinarySearchTest.java)
* [BM25InvertedIndexTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java)
* [BreadthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java)
* [DepthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/BinarySearch.java b/src/main/java/com/thealgorithms/searches/BinarySearch.java
index 22096307d144..bedad1667f33 100644
--- a/src/main/java/com/thealgorithms/searches/BinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/BinarySearch.java
@@ -1,10 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.IntStream;
/**
* Binary search is one of the most popular algorithms The algorithm finds the
@@ -57,26 +53,4 @@ private > int search(T[] array, T key, int left, int rig
return search(array, key, median + 1, right);
}
}
-
- // Driver Program
- public static void main(String[] args) {
- // Just generate data
- Random r = ThreadLocalRandom.current();
-
- int size = 100;
- int maxElement = 100000;
-
- Integer[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().boxed().toArray(Integer[] ::new);
-
- // The element that should be found
- int shouldBeFound = integers[r.nextInt(size - 1)];
-
- BinarySearch search = new BinarySearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/BinarySearchTest.java b/src/test/java/com/thealgorithms/searches/BinarySearchTest.java
new file mode 100644
index 000000000000..bd4620a7fa7d
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/BinarySearchTest.java
@@ -0,0 +1,108 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the BinarySearch class.
+ */
+class BinarySearchTest {
+
+ /**
+ * Test for basic binary search functionality.
+ */
+ @Test
+ void testBinarySearchFound() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ int key = 7;
+ int expectedIndex = 6; // Index of the key in the array
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the found element should be 6.");
+ }
+
+ /**
+ * Test for binary search when the element is not present.
+ */
+ @Test
+ void testBinarySearchNotFound() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1, 2, 3, 4, 5};
+ int key = 6; // Element not present in the array
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for binary search with first element as the key.
+ */
+ @Test
+ void testBinarySearchFirstElement() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1, 2, 3, 4, 5};
+ int key = 1; // First element
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for binary search with last element as the key.
+ */
+ @Test
+ void testBinarySearchLastElement() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1, 2, 3, 4, 5};
+ int key = 5; // Last element
+ int expectedIndex = 4; // Index of the key in the array
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the last element should be 4.");
+ }
+
+ /**
+ * Test for binary search with a single element present.
+ */
+ @Test
+ void testBinarySearchSingleElementFound() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1};
+ int key = 1; // Only element present
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the single element should be 0.");
+ }
+
+ /**
+ * Test for binary search with a single element not present.
+ */
+ @Test
+ void testBinarySearchSingleElementNotFound() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {1};
+ int key = 2; // Key not present
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for binary search with an empty array.
+ */
+ @Test
+ void testBinarySearchEmptyArray() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = {}; // Empty array
+ int key = 1; // Key not present
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for binary search on large array.
+ */
+ @Test
+ void testBinarySearchLargeArray() {
+ BinarySearch binarySearch = new BinarySearch();
+ Integer[] array = IntStream.range(0, 10000).boxed().toArray(Integer[] ::new); // Array from 0 to 9999
+ int key = 9999; // Last element
+ int expectedIndex = 9999; // Index of the last element
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the last element should be 9999.");
+ }
+}
From a4e431912641cb0480412a7910fc318a6e6f016c Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 00:56:16 +0530
Subject: [PATCH 043/348] Add tests, remove `main`, improve docs in
`FibonacciSearch` (#5665)
---
DIRECTORY.md | 1 +
.../searches/FibonacciSearch.java | 55 +++++---
.../searches/FibonacciSearchTest.java | 124 ++++++++++++++++++
3 files changed, 160 insertions(+), 20 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index cc4e90a4ffdc..0726337c3f22 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1001,6 +1001,7 @@
* [BM25InvertedIndexTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java)
* [BreadthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java)
* [DepthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java)
+ * [FibonacciSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java)
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/FibonacciSearch.java b/src/main/java/com/thealgorithms/searches/FibonacciSearch.java
index 028ab07e0a86..2124938bc258 100644
--- a/src/main/java/com/thealgorithms/searches/FibonacciSearch.java
+++ b/src/main/java/com/thealgorithms/searches/FibonacciSearch.java
@@ -2,24 +2,42 @@
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-/*
- * Fibonacci Search is a popular algorithm which finds the position of a target value in
- * a sorted array
+/**
+ * FibonacciSearch is a search algorithm that finds the position of a target value in
+ * a sorted array using Fibonacci numbers.
*
- * The time complexity for this search algorithm is O(log3(n))
- * The space complexity for this search algorithm is O(1)
- * @author Kanakalatha Vemuru (https://github.com/KanakalathaVemuru)
+ *
+ * The time complexity for this search algorithm is O(log n).
+ * The space complexity for this search algorithm is O(1).
+ *
+ *
+ *
+ * Note: This algorithm requires that the input array be sorted.
+ *
*/
public class FibonacciSearch implements SearchAlgorithm {
/**
- * @param array is a sorted array where the element has to be searched
- * @param key is an element whose position has to be found
- * @param is any comparable type
- * @return index of the element
+ * Finds the index of the specified key in a sorted array using Fibonacci search.
+ *
+ * @param array The sorted array to search.
+ * @param key The element to search for.
+ * @param The type of the elements in the array, which must be comparable.
+ * @throws IllegalArgumentException if the input array is not sorted or empty, or if the key is null.
+ * @return The index of the key if found, otherwise -1.
*/
@Override
public > int find(T[] array, T key) {
+ if (array.length == 0) {
+ throw new IllegalArgumentException("Input array must not be empty.");
+ }
+ if (!isSorted(array)) {
+ throw new IllegalArgumentException("Input array must be sorted.");
+ }
+ if (key == null) {
+ throw new IllegalArgumentException("Key must not be null.");
+ }
+
int fibMinus1 = 1;
int fibMinus2 = 0;
int fibNumber = fibMinus1 + fibMinus2;
@@ -57,15 +75,12 @@ public > int find(T[] array, T key) {
return -1;
}
- // Driver Program
- public static void main(String[] args) {
- Integer[] integers = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
-
- int size = integers.length;
- Integer targetValue = 128;
- FibonacciSearch fsearch = new FibonacciSearch();
- int atIndex = fsearch.find(integers, targetValue);
-
- System.out.println("Should be found: " + targetValue + ". Found " + integers[atIndex] + " at index " + atIndex + ". An array length " + size);
+ private boolean isSorted(Comparable[] array) {
+ for (int i = 1; i < array.length; i++) {
+ if (array[i - 1].compareTo(array[i]) > 0) {
+ return false;
+ }
+ }
+ return true;
}
}
diff --git a/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java b/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java
new file mode 100644
index 000000000000..801c33b1d09a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java
@@ -0,0 +1,124 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the FibonacciSearch class.
+ */
+class FibonacciSearchTest {
+
+ /**
+ * Test for basic Fibonacci search functionality.
+ */
+ @Test
+ void testFibonacciSearchFound() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
+ int key = 128;
+ int expectedIndex = 7; // Index of the key in the array
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the found element should be 7.");
+ }
+
+ /**
+ * Test for Fibonacci search when the element is not present.
+ */
+ @Test
+ void testFibonacciSearchNotFound() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ int key = 6; // Element not present in the array
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for Fibonacci search with the first element as the key.
+ */
+ @Test
+ void testFibonacciSearchFirstElement() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ int key = 1; // First element
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for Fibonacci search with the last element as the key.
+ */
+ @Test
+ void testFibonacciSearchLastElement() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ int key = 16; // Last element
+ int expectedIndex = 4; // Index of the key in the array
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the last element should be 4.");
+ }
+
+ /**
+ * Test for Fibonacci search with a single element present.
+ */
+ @Test
+ void testFibonacciSearchSingleElementFound() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1};
+ int key = 1; // Only element present
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the single element should be 0.");
+ }
+
+ /**
+ * Test for Fibonacci search with a single element not present.
+ */
+ @Test
+ void testFibonacciSearchSingleElementNotFound() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1};
+ int key = 2; // Key not present
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for Fibonacci search with an empty array.
+ */
+ @Test
+ void testFibonacciSearchEmptyArray() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {}; // Empty array
+ int key = 1; // Key not present
+ assertThrows(IllegalArgumentException.class, () -> fibonacciSearch.find(array, key), "An empty array should throw an IllegalArgumentException.");
+ }
+
+ @Test
+ void testFibonacciSearchUnsortedArray() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {2, 1, 4, 3, 6, 5};
+ int key = 3; // Key not present
+ assertThrows(IllegalArgumentException.class, () -> fibonacciSearch.find(array, key), "An unsorted array should throw an IllegalArgumentException.");
+ }
+
+ @Test
+ void testFibonacciSearchNullKey() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = null; // Null key
+ assertThrows(IllegalArgumentException.class, () -> fibonacciSearch.find(array, key), "A null key should throw an IllegalArgumentException.");
+ }
+
+ /**
+ * Test for Fibonacci search on large array.
+ */
+ @Test
+ void testFibonacciSearchLargeArray() {
+ FibonacciSearch fibonacciSearch = new FibonacciSearch();
+ Integer[] array = IntStream.range(0, 10000).boxed().toArray(Integer[] ::new); // Array from 0 to 9999
+ int key = 9999;
+ int expectedIndex = 9999;
+ assertEquals(expectedIndex, fibonacciSearch.find(array, key), "The index of the last element should be 9999.");
+ }
+}
From d197fc7df2947e9e0758e32939fb19a109e68588 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:00:37 +0530
Subject: [PATCH 044/348] Add tests, remove `main`, improve docs in
`ExponentialSearch` (#5664)
---
DIRECTORY.md | 1 +
.../searches/ExponentalSearch.java | 59 ++++++-------
.../searches/ExponentialSearchTest.java | 84 +++++++++++++++++++
3 files changed, 116 insertions(+), 28 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 0726337c3f22..7690d09add9b 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1001,6 +1001,7 @@
* [BM25InvertedIndexTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java)
* [BreadthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java)
* [DepthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java)
+ * [ExponentialSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java)
* [FibonacciSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java)
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/ExponentalSearch.java b/src/main/java/com/thealgorithms/searches/ExponentalSearch.java
index a856bd659720..9187dcbc2f4b 100644
--- a/src/main/java/com/thealgorithms/searches/ExponentalSearch.java
+++ b/src/main/java/com/thealgorithms/searches/ExponentalSearch.java
@@ -2,44 +2,47 @@
import com.thealgorithms.devutils.searches.SearchAlgorithm;
import java.util.Arrays;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.IntStream;
+/**
+ * ExponentialSearch is an algorithm that efficiently finds the position of a target
+ * value within a sorted array. It works by expanding the range to find the bounds
+ * where the target might exist and then using binary search within that range.
+ *
+ *
+ * Worst-case time complexity: O(log n)
+ * Best-case time complexity: O(1) when the element is found at the first position.
+ * Average time complexity: O(log n)
+ * Worst-case space complexity: O(1)
+ *
+ *
+ *
+ * Note: This algorithm requires that the input array be sorted.
+ *
+ */
class ExponentialSearch implements SearchAlgorithm {
- public static void main(String[] args) {
- Random r = ThreadLocalRandom.current();
-
- int size = 100;
- int maxElement = 100000;
-
- Integer[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().boxed().toArray(Integer[] ::new);
-
- // The element that should be found
- int shouldBeFound = integers[r.nextInt(size - 1)];
-
- ExponentialSearch search = new ExponentialSearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
-
+ /**
+ * Finds the index of the specified key in a sorted array using exponential search.
+ *
+ * @param array The sorted array to search.
+ * @param key The element to search for.
+ * @param The type of the elements in the array, which must be comparable.
+ * @return The index of the key if found, otherwise -1.
+ */
@Override
public > int find(T[] array, T key) {
- if (array[0] == key) {
+ if (array.length == 0) {
+ return -1;
+ }
+ if (array[0].equals(key)) {
return 0;
}
- if (array[array.length - 1] == key) {
- return array.length;
+ if (array[array.length - 1].equals(key)) {
+ return array.length - 1;
}
int range = 1;
-
- while (range < array.length && array[range].compareTo(key) <= -1) {
+ while (range < array.length && array[range].compareTo(key) < 0) {
range = range * 2;
}
diff --git a/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java b/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java
new file mode 100644
index 000000000000..c84da531e8a4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java
@@ -0,0 +1,84 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the ExponentialSearch class.
+ */
+class ExponentialSearchTest {
+
+ /**
+ * Test for basic exponential search functionality.
+ */
+ @Test
+ void testExponentialSearchFound() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ int key = 7;
+ int expectedIndex = 6; // Index of the key in the array
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the found element should be 6.");
+ }
+
+ /**
+ * Test for exponential search with the first element as the key.
+ */
+ @Test
+ void testExponentialSearchFirstElement() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = {1, 2, 3, 4, 5};
+ int key = 1; // First element
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for exponential search with the last element as the key.
+ */
+ @Test
+ void testExponentialSearchLastElement() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = {1, 2, 3, 4, 5};
+ int key = 5; // Last element
+ int expectedIndex = 4; // Index of the key in the array
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the last element should be 4.");
+ }
+
+ /**
+ * Test for exponential search with a single element present.
+ */
+ @Test
+ void testExponentialSearchSingleElementFound() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = {1};
+ int key = 1; // Only element present
+ int expectedIndex = 0; // Index of the key in the array
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the single element should be 0.");
+ }
+
+ /**
+ * Test for exponential search with an empty array.
+ */
+ @Test
+ void testExponentialSearchEmptyArray() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = {}; // Empty array
+ int key = 1; // Key not present
+ int expectedIndex = -1; // Key not found
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for exponential search on large array.
+ */
+ @Test
+ void testExponentialSearchLargeArray() {
+ ExponentialSearch exponentialSearch = new ExponentialSearch();
+ Integer[] array = IntStream.range(0, 10000).boxed().toArray(Integer[] ::new); // Array from 0 to 9999
+ int key = 9999;
+ int expectedIndex = 9999;
+ assertEquals(expectedIndex, exponentialSearch.find(array, key), "The index of the last element should be 9999.");
+ }
+}
From ba3d3bf54e3994f9accf7f7345815e80c7bd386b Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:06:38 +0530
Subject: [PATCH 045/348] Add tests, remove `main`, improve docs in
`InterpolationSearch` (#5666)
---
DIRECTORY.md | 1 +
.../searches/InterpolationSearch.java | 47 ++++------
.../searches/InterpolationSearchTest.java | 90 +++++++++++++++++++
3 files changed, 108 insertions(+), 30 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 7690d09add9b..a23a6f03f02b 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1004,6 +1004,7 @@
* [ExponentialSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java)
* [FibonacciSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java)
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
+ * [InterpolationSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/InterpolationSearch.java b/src/main/java/com/thealgorithms/searches/InterpolationSearch.java
index aa1ff412b6a7..3ac6be25bf53 100644
--- a/src/main/java/com/thealgorithms/searches/InterpolationSearch.java
+++ b/src/main/java/com/thealgorithms/searches/InterpolationSearch.java
@@ -1,25 +1,31 @@
package com.thealgorithms.searches;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.stream.IntStream;
-
/**
- * Interpolation search algorithm implementation
+ * InterpolationSearch is an algorithm that searches for a target value within a sorted array
+ * by estimating the position based on the values at the corners of the current search range.
+ *
+ *
+ * The performance of this algorithm can vary:
+ * - Worst-case performance: O(n)
+ * - Best-case performance: O(1)
+ * - Average performance: O(log(log(n))) if the elements are uniformly distributed; otherwise O(n)
+ * - Worst-case space complexity: O(1)
+ *
*
*
- * Worst-case performance O(n) Best-case performance O(1) Average performance
- * O(log(log(n))) if the elements are uniformly distributed if not O(n)
- * Worst-case space complexity O(1)
+ * This search algorithm requires the input array to be sorted.
+ *
*
* @author Podshivalov Nikita (https://github.com/nikitap492)
*/
class InterpolationSearch {
/**
- * @param array is a sorted array
- * @param key is a value what shoulb be found in the array
- * @return an index if the array contains the key unless -1
+ * Finds the index of the specified key in a sorted array using interpolation search.
+ *
+ * @param array The sorted array to search.
+ * @param key The value to search for.
+ * @return The index of the key if found, otherwise -1.
*/
public int find(int[] array, int key) {
// Find indexes of two corners
@@ -48,23 +54,4 @@ public int find(int[] array, int key) {
}
return -1;
}
-
- // Driver method
- public static void main(String[] args) {
- Random r = new Random();
- int size = 100;
- int maxElement = 100000;
- int[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().toArray();
-
- // the element that should be found
- int shouldBeFound = integers[r.nextInt(size - 1)];
-
- InterpolationSearch search = new InterpolationSearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java b/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java
new file mode 100644
index 000000000000..b3b7e7ef129c
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java
@@ -0,0 +1,90 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.stream.IntStream;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the InterpolationSearch class.
+ */
+class InterpolationSearchTest {
+
+ /**
+ * Test for basic interpolation search functionality when the element is found.
+ */
+ @Test
+ void testInterpolationSearchFound() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
+ int key = 128;
+ int expectedIndex = 7; // Index of the key in the array
+ assertEquals(expectedIndex, interpolationSearch.find(array, key), "The index of the found element should be 7.");
+ }
+
+ /**
+ * Test for interpolation search when the element is not present in the array.
+ */
+ @Test
+ void testInterpolationSearchNotFound() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {1, 2, 4, 8, 16};
+ int key = 6; // Element not present in the array
+ assertEquals(-1, interpolationSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for interpolation search with the first element as the key.
+ */
+ @Test
+ void testInterpolationSearchFirstElement() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {1, 2, 4, 8, 16};
+ int key = 1; // First element
+ assertEquals(0, interpolationSearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for interpolation search with a single element not present.
+ */
+ @Test
+ void testInterpolationSearchSingleElementNotFound() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {1};
+ int key = 2; // Key not present
+ assertEquals(-1, interpolationSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for interpolation search with an empty array.
+ */
+ @Test
+ void testInterpolationSearchEmptyArray() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {}; // Empty array
+ int key = 1; // Key not present
+ assertEquals(-1, interpolationSearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for interpolation search on large uniformly distributed array.
+ */
+ @Test
+ void testInterpolationSearchLargeUniformArray() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = IntStream.range(0, 10000).map(i -> i * 2).toArray(); // Array from 0 to 19998, step 2
+ int key = 9998; // Last even number in the array
+ assertEquals(4999, interpolationSearch.find(array, key), "The index of the last element should be 4999.");
+ }
+
+ /**
+ * Test for interpolation search on large non-uniformly distributed array.
+ */
+ @Test
+ void testInterpolationSearchLargeNonUniformArray() {
+ InterpolationSearch interpolationSearch = new InterpolationSearch();
+ int[] array = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144}; // Fibonacci numbers
+ int key = 21; // Present in the array
+ assertEquals(6, interpolationSearch.find(array, key), "The index of the found element should be 6.");
+ }
+}
From 0a7065df38cbc16ebc6ce45fc6a07bdcc1eb491d Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:11:07 +0530
Subject: [PATCH 046/348] Add tests, remove `main` in `IterativeBinarySearch`
(#5667)
---
DIRECTORY.md | 1 +
.../searches/IterativeBinarySearch.java | 22 ----
.../searches/IterativeBinarySearchTest.java | 117 ++++++++++++++++++
3 files changed, 118 insertions(+), 22 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index a23a6f03f02b..23f2941a702c 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1005,6 +1005,7 @@
* [FibonacciSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java)
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
* [InterpolationSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java)
+ * [IterativeBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java b/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java
index 49a86e4e53a8..05fab0534267 100644
--- a/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java
@@ -1,9 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.stream.Stream;
/**
* Binary search is one of the most popular algorithms This class represents
@@ -55,23 +52,4 @@ public > int find(T[] array, T key) {
return -1;
}
-
- // Only a main method for test purpose
- public static void main(String[] args) {
- Random r = new Random();
- int size = 100;
- int maxElement = 100000;
- Integer[] integers = Stream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().toArray(Integer[] ::new);
-
- // the element that should be found
- Integer shouldBeFound = integers[r.nextInt(size - 1)];
-
- IterativeBinarySearch search = new IterativeBinarySearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java
new file mode 100644
index 000000000000..b2e121ac1ba0
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java
@@ -0,0 +1,117 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the IterativeBinarySearch class.
+ */
+class IterativeBinarySearchTest {
+
+ /**
+ * Test for basic binary search functionality when the element is found.
+ */
+ @Test
+ void testBinarySearchFound() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
+ Integer key = 128;
+ int expectedIndex = 7; // Index of the key in the array
+ assertEquals(expectedIndex, binarySearch.find(array, key), "The index of the found element should be 7.");
+ }
+
+ /**
+ * Test for binary search when the element is not present in the array.
+ */
+ @Test
+ void testBinarySearchNotFound() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 6; // Element not present in the array
+ assertEquals(-1, binarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for binary search with the first element as the key.
+ */
+ @Test
+ void testBinarySearchFirstElement() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 1; // First element
+ assertEquals(0, binarySearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for binary search with the last element as the key.
+ */
+ @Test
+ void testBinarySearchLastElement() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 16; // Last element
+ assertEquals(4, binarySearch.find(array, key), "The index of the last element should be 4.");
+ }
+
+ /**
+ * Test for binary search with a single element present.
+ */
+ @Test
+ void testBinarySearchSingleElementFound() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1};
+ Integer key = 1; // Only element present
+ assertEquals(0, binarySearch.find(array, key), "The index of the single element should be 0.");
+ }
+
+ /**
+ * Test for binary search with a single element not present.
+ */
+ @Test
+ void testBinarySearchSingleElementNotFound() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {1};
+ Integer key = 2; // Key not present
+ assertEquals(-1, binarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for binary search with an empty array.
+ */
+ @Test
+ void testBinarySearchEmptyArray() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = {}; // Empty array
+ Integer key = 1; // Key not present
+ assertEquals(-1, binarySearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for binary search on a large array.
+ */
+ @Test
+ void testBinarySearchLargeArray() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = new Integer[10000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2;
+ } // Array from 0 to 19998, step 2
+ Integer key = 9998; // Present in the array
+ assertEquals(4999, binarySearch.find(array, key), "The index of the found element should be 4999.");
+ }
+
+ /**
+ * Test for binary search on large array with a non-existent key.
+ */
+ @Test
+ void testBinarySearchLargeArrayNotFound() {
+ IterativeBinarySearch binarySearch = new IterativeBinarySearch();
+ Integer[] array = new Integer[10000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2;
+ } // Array from 0 to 19998, step 2
+ Integer key = 9999; // Key not present
+ assertEquals(-1, binarySearch.find(array, key), "The element should not be found in the array.");
+ }
+}
From f992fc425df914403475a35d700e09f67b69a8a4 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:15:26 +0530
Subject: [PATCH 047/348] Add tests, remove main in IterativeTernarySearch
(#5668)
---
DIRECTORY.md | 1 +
.../searches/IterativeTernarySearch.java | 52 ++++----
.../searches/IterativeTernarySearchTest.java | 117 ++++++++++++++++++
3 files changed, 140 insertions(+), 30 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 23f2941a702c..ff6e29806847 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1006,6 +1006,7 @@
* [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java)
* [InterpolationSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java)
* [IterativeBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java)
+ * [IterativeTernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java b/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java
index e78acd6a7ef8..585d6787d3f8 100644
--- a/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java
@@ -1,22 +1,26 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.stream.Stream;
/**
- * A iterative version of a ternary search algorithm This is better way to
- * implement the ternary search, because a recursive version adds some overhead
- * to a stack. But in java the compile can transform the recursive version to
- * iterative implicitly, so there are no much differences between these two
- * algorithms
+ * An iterative implementation of the Ternary Search algorithm.
*
*
- * Worst-case performance Θ(log3(N)) Best-case performance O(1) Average
- * performance Θ(log3(N)) Worst-case space complexity O(1)
+ * Ternary search is a divide-and-conquer algorithm that splits the array into three parts
+ * instead of two, as in binary search. This implementation is iterative, reducing the overhead
+ * associated with recursive function calls. However, the recursive version can also be optimized
+ * by the Java compiler to resemble the iterative version, resulting in similar performance.
+ *
+ *
+ * This class implements the {@link SearchAlgorithm} interface, providing a generic search method
+ * for any comparable type.
*
- * @author Podshivalov Nikita (https://github.com/nikitap492)
* @see SearchAlgorithm
* @see TernarySearch
* @since 2018-04-13
@@ -25,6 +29,13 @@ public class IterativeTernarySearch implements SearchAlgorithm {
@Override
public > int find(T[] array, T key) {
+ if (array == null || array.length == 0 || key == null) {
+ return -1;
+ }
+ if (array.length == 1) {
+ return array[0].compareTo(key) == 0 ? 0 : -1;
+ }
+
int left = 0;
int right = array.length - 1;
@@ -50,23 +61,4 @@ public > int find(T[] array, T key) {
return -1;
}
-
- public static void main(String[] args) {
- // just generate data
- Random r = new Random();
- int size = 100;
- int maxElement = 100000;
- Integer[] integers = Stream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().toArray(Integer[] ::new);
-
- // the element that should be found
- Integer shouldBeFound = integers[r.nextInt(size - 1)];
-
- IterativeTernarySearch search = new IterativeTernarySearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java b/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java
new file mode 100644
index 000000000000..c7640e6d0672
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java
@@ -0,0 +1,117 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the IterativeTernarySearch class.
+ */
+class IterativeTernarySearchTest {
+
+ /**
+ * Test for basic ternary search functionality when the element is found.
+ */
+ @Test
+ void testTernarySearchFound() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
+ Integer key = 128;
+ int expectedIndex = 7; // Index of the key in the array
+ assertEquals(expectedIndex, ternarySearch.find(array, key), "The index of the found element should be 7.");
+ }
+
+ /**
+ * Test for ternary search when the element is not present in the array.
+ */
+ @Test
+ void testTernarySearchNotFound() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 6; // Element not present in the array
+ assertEquals(-1, ternarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for ternary search with the first element as the key.
+ */
+ @Test
+ void testTernarySearchFirstElement() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 1; // First element
+ assertEquals(0, ternarySearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for ternary search with the last element as the key.
+ */
+ @Test
+ void testTernarySearchLastElement() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1, 2, 4, 8, 16};
+ Integer key = 16; // Last element
+ assertEquals(4, ternarySearch.find(array, key), "The index of the last element should be 4.");
+ }
+
+ /**
+ * Test for ternary search with a single element present.
+ */
+ @Test
+ void testTernarySearchSingleElementFound() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1};
+ Integer key = 1; // Only element present
+ assertEquals(0, ternarySearch.find(array, key), "The index of the single element should be 0.");
+ }
+
+ /**
+ * Test for ternary search with a single element not present.
+ */
+ @Test
+ void testTernarySearchSingleElementNotFound() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {1};
+ Integer key = 2; // Key not present
+ assertEquals(-1, ternarySearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for ternary search with an empty array.
+ */
+ @Test
+ void testTernarySearchEmptyArray() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = {}; // Empty array
+ Integer key = 1; // Key not present
+ assertEquals(-1, ternarySearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for ternary search on a large array.
+ */
+ @Test
+ void testTernarySearchLargeArray() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = new Integer[10000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2;
+ } // Array from 0 to 19998, step 2
+ Integer key = 9998; // Present in the array
+ assertEquals(4999, ternarySearch.find(array, key), "The index of the found element should be 4999.");
+ }
+
+ /**
+ * Test for ternary search on large array with a non-existent key.
+ */
+ @Test
+ void testTernarySearchLargeArrayNotFound() {
+ IterativeTernarySearch ternarySearch = new IterativeTernarySearch();
+ Integer[] array = new Integer[10000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2;
+ } // Array from 0 to 19998, step 2
+ Integer key = 9999; // Key not present
+ assertEquals(-1, ternarySearch.find(array, key), "The element should not be found in the array.");
+ }
+}
From 38285771c8bf1e4bf1c3741d4ce397d744b01136 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:21:06 +0530
Subject: [PATCH 048/348] Add tests, remove main in JumpSearch (#5669)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/JumpSearch.java | 55 ++++++-----
.../searches/JumpSearchTest.java | 94 +++++++++++++++++++
3 files changed, 128 insertions(+), 22 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/JumpSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index ff6e29806847..a22863e8b052 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1007,6 +1007,7 @@
* [InterpolationSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java)
* [IterativeBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java)
* [IterativeTernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java)
+ * [JumpSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/JumpSearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/JumpSearch.java b/src/main/java/com/thealgorithms/searches/JumpSearch.java
index f499cf8079cc..8dcec3a819a4 100644
--- a/src/main/java/com/thealgorithms/searches/JumpSearch.java
+++ b/src/main/java/com/thealgorithms/searches/JumpSearch.java
@@ -2,44 +2,55 @@
import com.thealgorithms.devutils.searches.SearchAlgorithm;
+/**
+ * An implementation of the Jump Search algorithm.
+ *
+ *
+ * Jump Search is an algorithm for searching sorted arrays. It works by dividing the array
+ * into blocks of a fixed size (the block size is typically the square root of the array length)
+ * and jumping ahead by this block size to find a range where the target element may be located.
+ * Once the range is found, a linear search is performed within that block.
+ *
+ *
+ * The Jump Search algorithm is particularly effective for large sorted arrays where the cost of
+ * performing a linear search on the entire array would be prohibitive.
+ *
+ *
+ * This class implements the {@link SearchAlgorithm} interface, providing a generic search method
+ * for any comparable type.
+ */
public class JumpSearch implements SearchAlgorithm {
- public static void main(String[] args) {
- JumpSearch jumpSearch = new JumpSearch();
- Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
- for (int i = 0; i < array.length; i++) {
- assert jumpSearch.find(array, i) == i;
- }
- assert jumpSearch.find(array, -1) == -1;
- assert jumpSearch.find(array, 11) == -1;
- }
-
/**
- * Jump Search algorithm implements
+ * Jump Search algorithm implementation.
*
- * @param array the array contains elements
- * @param key to be searched
- * @return index of {@code key} if found, otherwise -1
+ * @param array the sorted array containing elements
+ * @param key the element to be searched
+ * @return the index of {@code key} if found, otherwise -1
*/
@Override
public > int find(T[] array, T key) {
int length = array.length;
- /* length of array */
int blockSize = (int) Math.sqrt(length);
- /* block size to be jumped */
int limit = blockSize;
- while (key.compareTo(array[limit]) > 0 && limit < array.length - 1) {
- limit = Math.min(limit + blockSize, array.length - 1);
+ // Jumping ahead to find the block where the key may be located
+ while (limit < length && key.compareTo(array[limit]) > 0) {
+ limit = Math.min(limit + blockSize, length - 1);
}
- for (int i = limit - blockSize; i <= limit; i++) {
- if (array[i] == key) {
- /* execute linear search */
+ // Perform linear search within the identified block
+ for (int i = limit - blockSize; i <= limit && i < length; i++) {
+ if (array[i].equals(key)) {
return i;
}
}
return -1;
- /* not found */
}
}
diff --git a/src/test/java/com/thealgorithms/searches/JumpSearchTest.java b/src/test/java/com/thealgorithms/searches/JumpSearchTest.java
new file mode 100644
index 000000000000..3fa319b66a41
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/JumpSearchTest.java
@@ -0,0 +1,94 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the JumpSearch class.
+ */
+class JumpSearchTest {
+
+ /**
+ * Test for finding an element present in the array.
+ */
+ @Test
+ void testJumpSearchFound() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 5; // Element to find
+ assertEquals(5, jumpSearch.find(array, key), "The index of the found element should be 5.");
+ }
+
+ /**
+ * Test for finding the first element in the array.
+ */
+ @Test
+ void testJumpSearchFirstElement() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 0; // First element
+ assertEquals(0, jumpSearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for finding the last element in the array.
+ */
+ @Test
+ void testJumpSearchLastElement() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 10; // Last element
+ assertEquals(10, jumpSearch.find(array, key), "The index of the last element should be 10.");
+ }
+
+ /**
+ * Test for finding an element not present in the array.
+ */
+ @Test
+ void testJumpSearchNotFound() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = -1; // Element not in the array
+ assertEquals(-1, jumpSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for finding an element in an empty array.
+ */
+ @Test
+ void testJumpSearchEmptyArray() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = {}; // Empty array
+ Integer key = 1; // Key not present
+ assertEquals(-1, jumpSearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for finding an element in a large array.
+ */
+ @Test
+ void testJumpSearchLargeArray() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = new Integer[1000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2; // Fill the array with even numbers
+ }
+ Integer key = 256; // Present in the array
+ assertEquals(128, jumpSearch.find(array, key), "The index of the found element should be 128.");
+ }
+
+ /**
+ * Test for finding an element in a large array when it is not present.
+ */
+ @Test
+ void testJumpSearchLargeArrayNotFound() {
+ JumpSearch jumpSearch = new JumpSearch();
+ Integer[] array = new Integer[1000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i * 2; // Fill the array with even numbers
+ }
+ Integer key = 999; // Key not present
+ assertEquals(-1, jumpSearch.find(array, key), "The element should not be found in the array.");
+ }
+}
From a663e66782a1ceb3e7a82bffd1bd2ad41b42b13c Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:27:40 +0530
Subject: [PATCH 049/348] Add tests, remove `main` in `SquareRootBinarySearch`
(#5676)
---
DIRECTORY.md | 1 +
.../searches/SquareRootBinarySearch.java | 18 +-----
.../searches/SquareRootBinarySearchTest.java | 57 +++++++++++++++++++
3 files changed, 59 insertions(+), 17 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index a22863e8b052..e272be8e2401 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1016,6 +1016,7 @@
* [RecursiveBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java)
* [RowColumnWiseSorted2dArrayBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java)
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
+ * [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
* sorts
* [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java b/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java
index c00bfc9da6f5..95e062c274fd 100644
--- a/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java
@@ -1,7 +1,5 @@
package com.thealgorithms.searches;
-import java.util.Scanner;
-
/**
* Given an integer x, find the square root of x. If x is not a perfect square,
* then return floor(√x).
@@ -18,20 +16,6 @@ public final class SquareRootBinarySearch {
private SquareRootBinarySearch() {
}
- /**
- * This is the driver method.
- *
- * @param args Command line arguments
- */
- public static void main(String[] args) {
- Scanner sc = new Scanner(System.in);
- System.out.print("Enter a number you want to calculate square root of : ");
- int num = sc.nextInt();
- long ans = squareRoot(num);
- System.out.println("The square root is : " + ans);
- sc.close();
- }
-
/**
* This function calculates the floor of square root of a number. We use
* Binary Search algorithm to calculate the square root in a more optimised
@@ -40,7 +24,7 @@ public static void main(String[] args) {
* @param num Number
* @return answer
*/
- private static long squareRoot(long num) {
+ static long squareRoot(long num) {
if (num == 0 || num == 1) {
return num;
}
diff --git a/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java
new file mode 100644
index 000000000000..f23f4ee83fc3
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class SquareRootBinarySearchTest {
+
+ @Test
+ void testPerfectSquare() {
+ long input = 16;
+ long expected = 4;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 16 should be 4");
+ }
+
+ @Test
+ void testNonPerfectSquare() {
+ long input = 15;
+ long expected = 3;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 15 should be 3");
+ }
+
+ @Test
+ void testZero() {
+ long input = 0;
+ long expected = 0;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 0 should be 0");
+ }
+
+ @Test
+ void testOne() {
+ long input = 1;
+ long expected = 1;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 1 should be 1");
+ }
+
+ @Test
+ void testLargeNumberPerfectSquare() {
+ long input = 1000000;
+ long expected = 1000;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 1000000 should be 1000");
+ }
+
+ @Test
+ void testLargeNumberNonPerfectSquare() {
+ long input = 999999;
+ long expected = 999;
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of 999999 should be 999");
+ }
+
+ @Test
+ void testNegativeInput() {
+ long input = -4;
+ long expected = 0; // Assuming the implementation should return 0 for negative input
+ assertEquals(expected, SquareRootBinarySearch.squareRoot(input), "Square root of negative number should return 0");
+ }
+}
From fb11d455ddfdebe071466d8adb6ec53c14aedd27 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:32:13 +0530
Subject: [PATCH 050/348] Add tests in `SearchInARowAndColWiseSortedMatrix`
(#5675)
---
DIRECTORY.md | 1 +
.../SearchInARowAndColWiseSortedMatrix.java | 1 -
...earchInARowAndColWiseSortedMatrixTest.java | 66 +++++++++++++++++++
3 files changed, 67 insertions(+), 1 deletion(-)
create mode 100644 src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index e272be8e2401..18659ca229b3 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1015,6 +1015,7 @@
* [RabinKarpAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java)
* [RecursiveBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java)
* [RowColumnWiseSorted2dArrayBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java)
+ * [SearchInARowAndColWiseSortedMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java)
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
* [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
diff --git a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
index 2bdcdb48b653..91fda373dca7 100644
--- a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
+++ b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java
@@ -8,7 +8,6 @@ public class SearchInARowAndColWiseSortedMatrix {
* @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
diff --git a/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java b/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java
new file mode 100644
index 000000000000..88227804b775
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java
@@ -0,0 +1,66 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+
+import org.junit.jupiter.api.Test;
+
+class SearchInARowAndColWiseSortedMatrixTest {
+
+ private final SearchInARowAndColWiseSortedMatrix searcher = new SearchInARowAndColWiseSortedMatrix();
+
+ @Test
+ void testSearchValueExistsInMatrix() {
+ int[][] matrix = {{10, 20, 30, 40}, {15, 25, 35, 45}, {27, 29, 37, 48}, {32, 33, 39, 50}};
+ int value = 29;
+ int[] expected = {2, 1}; // Row 2, Column 1
+ assertArrayEquals(expected, searcher.search(matrix, value), "Value should be found in the matrix");
+ }
+
+ @Test
+ void testSearchValueNotExistsInMatrix() {
+ int[][] matrix = {{10, 20, 30, 40}, {15, 25, 35, 45}, {27, 29, 37, 48}, {32, 33, 39, 50}};
+ int value = 100;
+ int[] expected = {-1, -1}; // Not found
+ assertArrayEquals(expected, searcher.search(matrix, value), "Value should not be found in the matrix");
+ }
+
+ @Test
+ void testSearchInEmptyMatrix() {
+ int[][] matrix = {};
+ int value = 5;
+ int[] expected = {-1, -1}; // Not found
+ assertArrayEquals(expected, searcher.search(matrix, value), "Should return {-1, -1} for empty matrix");
+ }
+
+ @Test
+ void testSearchInSingleElementMatrixFound() {
+ int[][] matrix = {{5}};
+ int value = 5;
+ int[] expected = {0, 0}; // Found at (0,0)
+ assertArrayEquals(expected, searcher.search(matrix, value), "Value should be found in single element matrix");
+ }
+
+ @Test
+ void testSearchInSingleElementMatrixNotFound() {
+ int[][] matrix = {{10}};
+ int value = 5;
+ int[] expected = {-1, -1}; // Not found
+ assertArrayEquals(expected, searcher.search(matrix, value), "Should return {-1, -1} for value not found in single element matrix");
+ }
+
+ @Test
+ void testSearchInRowWiseSortedMatrix() {
+ int[][] matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
+ int value = 6;
+ int[] expected = {1, 2}; // Found at (1, 2)
+ assertArrayEquals(expected, searcher.search(matrix, value), "Value should be found in the row-wise sorted matrix");
+ }
+
+ @Test
+ void testSearchInColWiseSortedMatrix() {
+ int[][] matrix = {{1, 4, 7}, {2, 5, 8}, {3, 6, 9}};
+ int value = 5;
+ int[] expected = {1, 1}; // Found at (1, 1)
+ assertArrayEquals(expected, searcher.search(matrix, value), "Value should be found in the column-wise sorted matrix");
+ }
+}
From 401d87365e3b073c6089d6089357515cd535cbec Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:37:02 +0530
Subject: [PATCH 051/348] Add tests, remove `main` in `UnionFind` (#5678)
---
DIRECTORY.md | 1 +
.../com/thealgorithms/searches/UnionFind.java | 71 +++++++++-------
.../thealgorithms/searches/UnionFindTest.java | 81 +++++++++++++++++++
3 files changed, 126 insertions(+), 27 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/UnionFindTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 18659ca229b3..59b0ff5fa4a5 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1019,6 +1019,7 @@
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
* [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
+ * [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java)
* sorts
* [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java)
* [BinaryInsertionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/UnionFind.java b/src/main/java/com/thealgorithms/searches/UnionFind.java
index 2effdf37bea5..01202a982266 100644
--- a/src/main/java/com/thealgorithms/searches/UnionFind.java
+++ b/src/main/java/com/thealgorithms/searches/UnionFind.java
@@ -4,11 +4,28 @@
import java.util.Arrays;
import java.util.List;
+/**
+ * The Union-Find data structure, also known as Disjoint Set Union (DSU),
+ * is a data structure that tracks a set of elements partitioned into
+ * disjoint (non-overlapping) subsets. It supports two main operations:
+ *
+ * 1. **Find**: Determine which subset a particular element is in.
+ * 2. **Union**: Join two subsets into a single subset.
+ *
+ * This implementation uses path compression in the `find` operation
+ * and union by rank in the `union` operation for efficiency.
+ */
public class UnionFind {
- private final int[] p;
- private final int[] r;
+ private final int[] p; // Parent array
+ private final int[] r; // Rank array
+ /**
+ * Initializes a Union-Find data structure with n elements.
+ * Each element is its own parent initially.
+ *
+ * @param n the number of elements
+ */
public UnionFind(int n) {
p = new int[n];
r = new int[n];
@@ -18,6 +35,13 @@ public UnionFind(int n) {
}
}
+ /**
+ * Finds the root of the set containing the element i.
+ * Uses path compression to flatten the structure.
+ *
+ * @param i the element to find
+ * @return the root of the set
+ */
public int find(int i) {
int parent = p[i];
@@ -25,12 +49,19 @@ public int find(int i) {
return i;
}
+ // Path compression
final int result = find(parent);
p[i] = result;
-
return result;
}
+ /**
+ * Unites the sets containing elements x and y.
+ * Uses union by rank to attach the smaller tree under the larger tree.
+ *
+ * @param x the first element
+ * @param y the second element
+ */
public void union(int x, int y) {
int r0 = find(x);
int r1 = find(y);
@@ -39,6 +70,7 @@ public void union(int x, int y) {
return;
}
+ // Union by rank
if (r[r0] > r[r1]) {
p[r1] = r0;
} else if (r[r1] > r[r0]) {
@@ -49,39 +81,24 @@ public void union(int x, int y) {
}
}
+ /**
+ * Counts the number of disjoint sets.
+ *
+ * @return the number of disjoint sets
+ */
public int count() {
List parents = new ArrayList<>();
for (int i = 0; i < p.length; i++) {
- if (!parents.contains(find(i))) {
- parents.add(find(i));
+ int root = find(i);
+ if (!parents.contains(root)) {
+ parents.add(root);
}
}
return parents.size();
}
+ @Override
public String toString() {
return "p " + Arrays.toString(p) + " r " + Arrays.toString(r) + "\n";
}
-
- // Tests
- public static void main(String[] args) {
- UnionFind uf = new UnionFind(5);
- System.out.println("init /w 5 (should print 'p [0, 1, 2, 3, 4] r [0, 0, 0, 0, 0]'):");
- System.out.println(uf);
-
- uf.union(1, 2);
- System.out.println("union 1 2 (should print 'p [0, 1, 1, 3, 4] r [0, 1, 0, 0, 0]'):");
- System.out.println(uf);
-
- uf.union(3, 4);
- System.out.println("union 3 4 (should print 'p [0, 1, 1, 3, 3] r [0, 1, 0, 1, 0]'):");
- System.out.println(uf);
-
- uf.find(4);
- System.out.println("find 4 (should print 'p [0, 1, 1, 3, 3] r [0, 1, 0, 1, 0]'):");
- System.out.println(uf);
-
- System.out.println("count (should print '3'):");
- System.out.println(uf.count());
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/UnionFindTest.java b/src/test/java/com/thealgorithms/searches/UnionFindTest.java
new file mode 100644
index 000000000000..3cc025ff595c
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/UnionFindTest.java
@@ -0,0 +1,81 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class UnionFindTest {
+ private UnionFind uf;
+
+ @BeforeEach
+ void setUp() {
+ uf = new UnionFind(10); // Initialize with 10 elements
+ }
+
+ @Test
+ void testInitialState() {
+ // Verify that each element is its own parent and rank is 0
+ assertEquals("p [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] r [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n", uf.toString());
+ assertEquals(10, uf.count(), "Initial count of disjoint sets should be 10.");
+ }
+
+ @Test
+ void testUnionOperation() {
+ uf.union(0, 1);
+ uf.union(1, 2);
+ assertEquals(8, uf.count(), "Count should decrease after unions.");
+ assertEquals(0, uf.find(2), "Element 2 should point to root 0 after unions.");
+ }
+
+ @Test
+ void testUnionWithRank() {
+ uf.union(0, 1);
+ uf.union(1, 2); // Make 0 the root of 2
+ uf.union(3, 4);
+ uf.union(4, 5); // Make 3 the root of 5
+ uf.union(0, 3); // Union two trees
+
+ assertEquals(5, uf.count(), "Count should decrease after unions.");
+ assertEquals(0, uf.find(5), "Element 5 should point to root 0 after unions.");
+ }
+
+ @Test
+ void testFindOperation() {
+ uf.union(2, 3);
+ uf.union(4, 5);
+ uf.union(3, 5); // Connect 2-3 and 4-5
+
+ assertEquals(2, uf.find(3), "Find operation should return the root of the set.");
+ assertEquals(2, uf.find(5), "Find operation should return the root of the set.");
+ }
+
+ @Test
+ void testCountAfterMultipleUnions() {
+ uf.union(0, 1);
+ uf.union(2, 3);
+ uf.union(4, 5);
+ uf.union(1, 3); // Connect 0-1-2-3
+ uf.union(5, 6);
+
+ assertEquals(5, uf.count(), "Count should reflect the number of disjoint sets after multiple unions.");
+ }
+
+ @Test
+ void testNoUnion() {
+ assertEquals(10, uf.count(), "Count should remain 10 if no unions are made.");
+ }
+
+ @Test
+ void testUnionSameSet() {
+ uf.union(1, 2);
+ uf.union(1, 2); // Union same elements again
+
+ assertEquals(9, uf.count(), "Count should not decrease if union is called on the same set.");
+ }
+
+ @Test
+ void testFindOnSingleElement() {
+ assertEquals(7, uf.find(7), "Find on a single element should return itself.");
+ }
+}
From b1724fa73743014fe504fbe38d30dbe3fd30a4ce Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:42:07 +0530
Subject: [PATCH 052/348] Add tests, remove `main` in `LinearSearch` (#5670)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/LinearSearch.java | 18 ---
.../searches/LinearSearchTest.java | 118 ++++++++++++++++++
3 files changed, 119 insertions(+), 18 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/LinearSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 59b0ff5fa4a5..d0c62e600799 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1009,6 +1009,7 @@
* [IterativeTernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java)
* [JumpSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/JumpSearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
+ * [LinearSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
* [QuickSelectTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/LinearSearch.java b/src/main/java/com/thealgorithms/searches/LinearSearch.java
index 57927b30a632..c7b70edb5112 100644
--- a/src/main/java/com/thealgorithms/searches/LinearSearch.java
+++ b/src/main/java/com/thealgorithms/searches/LinearSearch.java
@@ -1,8 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Random;
-import java.util.stream.Stream;
/**
* Linear search is the easiest search algorithm It works with sorted and
@@ -36,20 +34,4 @@ public > int find(T[] array, T value) {
}
return -1;
}
-
- public static void main(String[] args) {
- // just generate data
- Random r = new Random();
- int size = 200;
- int maxElement = 100;
- Integer[] integers = Stream.generate(() -> r.nextInt(maxElement)).limit(size).toArray(Integer[] ::new);
-
- // the element that should be found
- Integer shouldBeFound = integers[r.nextInt(size - 1)];
-
- LinearSearch search = new LinearSearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/LinearSearchTest.java b/src/test/java/com/thealgorithms/searches/LinearSearchTest.java
new file mode 100644
index 000000000000..5c09dec6d578
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/LinearSearchTest.java
@@ -0,0 +1,118 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Random;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the LinearSearch class.
+ */
+class LinearSearchTest {
+
+ /**
+ * Test for finding an element present in the array.
+ */
+ @Test
+ void testLinearSearchFound() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 5; // Element to find
+ assertEquals(5, linearSearch.find(array, key), "The index of the found element should be 5.");
+ }
+
+ /**
+ * Test for finding the first element in the array.
+ */
+ @Test
+ void testLinearSearchFirstElement() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 0; // First element
+ assertEquals(0, linearSearch.find(array, key), "The index of the first element should be 0.");
+ }
+
+ /**
+ * Test for finding the last element in the array.
+ */
+ @Test
+ void testLinearSearchLastElement() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 10; // Last element
+ assertEquals(10, linearSearch.find(array, key), "The index of the last element should be 10.");
+ }
+
+ /**
+ * Test for finding an element not present in the array.
+ */
+ @Test
+ void testLinearSearchNotFound() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = -1; // Element not in the array
+ assertEquals(-1, linearSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for finding an element in an empty array.
+ */
+ @Test
+ void testLinearSearchEmptyArray() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {}; // Empty array
+ Integer key = 1; // Key not present
+ assertEquals(-1, linearSearch.find(array, key), "The element should not be found in an empty array.");
+ }
+
+ /**
+ * Test for finding an element in a large array.
+ */
+ @Test
+ void testLinearSearchLargeArray() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = new Integer[1000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i; // Fill the array with integers 0 to 999
+ }
+ Integer key = 256; // Present in the array
+ assertEquals(256, linearSearch.find(array, key), "The index of the found element should be 256.");
+ }
+
+ /**
+ * Test for finding an element in a large array when it is not present.
+ */
+ @Test
+ void testLinearSearchLargeArrayNotFound() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = new Integer[1000];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i; // Fill the array with integers 0 to 999
+ }
+ Integer key = 1001; // Key not present
+ assertEquals(-1, linearSearch.find(array, key), "The element should not be found in the array.");
+ }
+
+ /**
+ * Test for finding multiple occurrences of the same element in the array.
+ */
+ @Test
+ void testLinearSearchMultipleOccurrences() {
+ LinearSearch linearSearch = new LinearSearch();
+ Integer[] array = {1, 2, 3, 4, 5, 3, 6, 7, 3}; // 3 occurs multiple times
+ Integer key = 3; // Key to find
+ assertEquals(2, linearSearch.find(array, key), "The index of the first occurrence of the element should be 2.");
+ }
+
+ /**
+ * Test for performance with random large array.
+ */
+ @Test
+ void testLinearSearchRandomArray() {
+ LinearSearch linearSearch = new LinearSearch();
+ Random random = new Random();
+ Integer[] array = random.ints(0, 1000).distinct().limit(1000).boxed().toArray(Integer[] ::new);
+ Integer key = array[random.nextInt(array.length)]; // Key should be in the array
+ assertEquals(java.util.Arrays.asList(array).indexOf(key), linearSearch.find(array, key), "The index of the found element should match.");
+ }
+}
From e8b32513c8871c1530908d66648aabb882b32ca0 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:50:39 +0530
Subject: [PATCH 053/348] Add tests, remove `main` in `MonteCarloTreeSearch`
(#5673)
---
DIRECTORY.md | 1 +
.../searches/MonteCarloTreeSearch.java | 6 -
.../searches/MonteCarloTreeSearchTest.java | 126 ++++++++++++++++++
3 files changed, 127 insertions(+), 6 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index d0c62e600799..cfc8841fbcbe 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1010,6 +1010,7 @@
* [JumpSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/JumpSearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [LinearSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchTest.java)
+ * [MonteCarloTreeSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
* [QuickSelectTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java b/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java
index 268c33cef610..aa74398b708b 100644
--- a/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java
+++ b/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java
@@ -39,12 +39,6 @@ public Node(Node parent, boolean isPlayersTurn) {
static final int WIN_SCORE = 10;
static final int TIME_LIMIT = 500; // Time the algorithm will be running for (in milliseconds).
- public static void main(String[] args) {
- MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
-
- mcts.monteCarloTreeSearch(mcts.new Node(null, true));
- }
-
/**
* Explores a game tree using Monte Carlo Tree Search (MCTS) and returns the
* most promising node.
diff --git a/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java b/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java
new file mode 100644
index 000000000000..69c958f67a40
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java
@@ -0,0 +1,126 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class MonteCarloTreeSearchTest {
+
+ /**
+ * Test the creation of a node and its initial state.
+ */
+ @Test
+ void testNodeCreation() {
+ MonteCarloTreeSearch.Node node = new MonteCarloTreeSearch().new Node(null, true);
+ assertNotNull(node, "Node should be created");
+ assertTrue(node.childNodes.isEmpty(), "Child nodes should be empty upon creation");
+ assertTrue(node.isPlayersTurn, "Initial turn should be player's turn");
+ assertEquals(0, node.score, "Initial score should be zero");
+ assertEquals(0, node.visitCount, "Initial visit count should be zero");
+ }
+
+ /**
+ * Test adding child nodes to a parent node.
+ */
+ @Test
+ void testAddChildNodes() {
+ MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
+ MonteCarloTreeSearch.Node parentNode = mcts.new Node(null, true);
+
+ mcts.addChildNodes(parentNode, 5);
+
+ assertEquals(5, parentNode.childNodes.size(), "Parent should have 5 child nodes");
+ for (MonteCarloTreeSearch.Node child : parentNode.childNodes) {
+ assertFalse(child.isPlayersTurn, "Child node should not be player's turn");
+ assertEquals(0, child.visitCount, "Child node visit count should be zero");
+ }
+ }
+
+ /**
+ * Test the UCT selection of a promising node.
+ */
+ @Test
+ void testGetPromisingNode() {
+ MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
+ MonteCarloTreeSearch.Node parentNode = mcts.new Node(null, true);
+
+ // Create child nodes with different visit counts and scores
+ for (int i = 0; i < 3; i++) {
+ MonteCarloTreeSearch.Node child = mcts.new Node(parentNode, false);
+ child.visitCount = i + 1;
+ child.score = i * 2;
+ parentNode.childNodes.add(child);
+ }
+
+ // Get promising node
+ MonteCarloTreeSearch.Node promisingNode = mcts.getPromisingNode(parentNode);
+
+ // The child with the highest UCT value should be chosen.
+ assertNotNull(promisingNode, "Promising node should not be null");
+ assertEquals(0, parentNode.childNodes.indexOf(promisingNode), "The first child should be the most promising");
+ }
+
+ /**
+ * Test simulation of random play and backpropagation.
+ */
+ @Test
+ void testSimulateRandomPlay() {
+ MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
+ MonteCarloTreeSearch.Node node = mcts.new Node(null, true);
+ node.visitCount = 10; // Simulating existing visits
+
+ // Simulate random play
+ mcts.simulateRandomPlay(node);
+
+ // Check visit count after simulation
+ assertEquals(11, node.visitCount, "Visit count should increase after simulation");
+
+ // Check if score is updated correctly
+ assertTrue(node.score >= 0 && node.score <= MonteCarloTreeSearch.WIN_SCORE, "Score should be between 0 and WIN_SCORE");
+ }
+
+ /**
+ * Test retrieving the winning node based on scores.
+ */
+ @Test
+ void testGetWinnerNode() {
+ MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
+ MonteCarloTreeSearch.Node parentNode = mcts.new Node(null, true);
+
+ // Create child nodes with varying scores
+ MonteCarloTreeSearch.Node winningNode = mcts.new Node(parentNode, false);
+ winningNode.score = 10; // Highest score
+ parentNode.childNodes.add(winningNode);
+
+ MonteCarloTreeSearch.Node losingNode = mcts.new Node(parentNode, false);
+ losingNode.score = 5;
+ parentNode.childNodes.add(losingNode);
+
+ MonteCarloTreeSearch.Node anotherLosingNode = mcts.new Node(parentNode, false);
+ anotherLosingNode.score = 3;
+ parentNode.childNodes.add(anotherLosingNode);
+
+ // Get the winning node
+ MonteCarloTreeSearch.Node winnerNode = mcts.getWinnerNode(parentNode);
+
+ assertEquals(winningNode, winnerNode, "Winning node should have the highest score");
+ }
+
+ /**
+ * Test the full Monte Carlo Tree Search process.
+ */
+ @Test
+ void testMonteCarloTreeSearch() {
+ MonteCarloTreeSearch mcts = new MonteCarloTreeSearch();
+ MonteCarloTreeSearch.Node rootNode = mcts.new Node(null, true);
+
+ // Execute MCTS and check the resulting node
+ MonteCarloTreeSearch.Node optimalNode = mcts.monteCarloTreeSearch(rootNode);
+
+ assertNotNull(optimalNode, "MCTS should return a non-null optimal node");
+ assertTrue(rootNode.childNodes.contains(optimalNode), "Optimal node should be a child of the root");
+ }
+}
From 29ad197a64f1403e27344616f8b594147d949aa9 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:54:52 +0530
Subject: [PATCH 054/348] Add tests, remove `main` in `SaddlebackSearch`
(#5674)
---
DIRECTORY.md | 1 +
.../searches/SaddlebackSearch.java | 35 ++------
.../searches/SaddlebackSearchTest.java | 85 +++++++++++++++++++
3 files changed, 92 insertions(+), 29 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index cfc8841fbcbe..cbe176f27440 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1017,6 +1017,7 @@
* [RabinKarpAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java)
* [RecursiveBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java)
* [RowColumnWiseSorted2dArrayBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java)
+ * [SaddlebackSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java)
* [SearchInARowAndColWiseSortedMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java)
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
* [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java b/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java
index 5c7a914e3bf2..192c4d26c735 100644
--- a/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java
+++ b/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java
@@ -1,7 +1,5 @@
package com.thealgorithms.searches;
-import java.util.Scanner;
-
/**
* Program to perform Saddleback Search Given a sorted 2D array(elements are
* sorted across every row and column, assuming ascending order) of size n*m we
@@ -27,10 +25,15 @@ private SaddlebackSearch() {
* @param row the current row.
* @param col the current column.
* @param key the element that we want to search for.
+ * @throws IllegalArgumentException if the array is empty.
* @return The index(row and column) of the element if found. Else returns
* -1 -1.
*/
- private static int[] find(int[][] arr, int row, int col, int key) {
+ static int[] find(int[][] arr, int row, int col, int key) {
+ if (arr.length == 0) {
+ throw new IllegalArgumentException("Array is empty");
+ }
+
// array to store the answer row and column
int[] ans = {-1, -1};
if (row < 0 || col >= arr[row].length) {
@@ -47,30 +50,4 @@ else if (arr[row][col] > key) {
// else we move right
return find(arr, row, col + 1, key);
}
-
- /**
- * Main method
- *
- * @param args Command line arguments
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Scanner sc = new Scanner(System.in);
- int[][] arr;
- int i;
- int j;
- int rows = sc.nextInt();
- int col = sc.nextInt();
- arr = new int[rows][col];
- for (i = 0; i < rows; i++) {
- for (j = 0; j < col; j++) {
- arr[i][j] = sc.nextInt();
- }
- }
- int ele = sc.nextInt();
- // we start from bottom left corner
- int[] ans = find(arr, rows - 1, 0, ele);
- System.out.println(ans[0] + " " + ans[1]);
- sc.close();
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java b/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java
new file mode 100644
index 000000000000..ec22cbf38152
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java
@@ -0,0 +1,85 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+class SaddlebackSearchTest {
+
+ /**
+ * Test searching for an element that exists in the array.
+ */
+ @Test
+ void testFindElementExists() {
+ int[][] arr = {{-10, -5, -3, 4, 9}, {-6, -2, 0, 5, 10}, {-4, -1, 1, 6, 12}, {2, 3, 7, 8, 13}, {100, 120, 130, 140, 150}};
+
+ int[] result = SaddlebackSearch.find(arr, arr.length - 1, 0, 4);
+ assertArrayEquals(new int[] {0, 3}, result, "Element 4 should be found at (0, 3)");
+ }
+
+ /**
+ * Test searching for an element that does not exist in the array.
+ */
+ @Test
+ void testFindElementNotExists() {
+ int[][] arr = {{-10, -5, -3, 4, 9}, {-6, -2, 0, 5, 10}, {-4, -1, 1, 6, 12}, {2, 3, 7, 8, 13}, {100, 120, 130, 140, 150}};
+
+ int[] result = SaddlebackSearch.find(arr, arr.length - 1, 0, 1000);
+ assertArrayEquals(new int[] {-1, -1}, result, "Element 1000 should not be found");
+ }
+
+ /**
+ * Test searching for the smallest element in the array.
+ */
+ @Test
+ void testFindSmallestElement() {
+ int[][] arr = {{-10, -5, -3, 4, 9}, {-6, -2, 0, 5, 10}, {-4, -1, 1, 6, 12}, {2, 3, 7, 8, 13}, {100, 120, 130, 140, 150}};
+
+ int[] result = SaddlebackSearch.find(arr, arr.length - 1, 0, -10);
+ assertArrayEquals(new int[] {0, 0}, result, "Element -10 should be found at (0, 0)");
+ }
+
+ /**
+ * Test searching for the largest element in the array.
+ */
+ @Test
+ void testFindLargestElement() {
+ int[][] arr = {{-10, -5, -3, 4, 9}, {-6, -2, 0, 5, 10}, {-4, -1, 1, 6, 12}, {2, 3, 7, 8, 13}, {100, 120, 130, 140, 150}};
+
+ int[] result = SaddlebackSearch.find(arr, arr.length - 1, 0, 150);
+ assertArrayEquals(new int[] {4, 4}, result, "Element 150 should be found at (4, 4)");
+ }
+
+ /**
+ * Test searching in an empty array.
+ */
+ @Test
+ void testFindInEmptyArray() {
+ int[][] arr = {};
+
+ assertThrows(IllegalArgumentException.class, () -> { SaddlebackSearch.find(arr, 0, 0, 4); });
+ }
+
+ /**
+ * Test searching in a single element array that matches the search key.
+ */
+ @Test
+ void testFindSingleElementExists() {
+ int[][] arr = {{5}};
+
+ int[] result = SaddlebackSearch.find(arr, 0, 0, 5);
+ assertArrayEquals(new int[] {0, 0}, result, "Element 5 should be found at (0, 0)");
+ }
+
+ /**
+ * Test searching in a single element array that does not match the search key.
+ */
+ @Test
+ void testFindSingleElementNotExists() {
+ int[][] arr = {{5}};
+
+ int[] result = SaddlebackSearch.find(arr, 0, 0, 10);
+ assertArrayEquals(new int[] {-1, -1}, result, "Element 10 should not be found in single element array");
+ }
+}
From 680202925192bbf6b5024aef9f0a0cba959e3315 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 01:59:20 +0530
Subject: [PATCH 055/348] Add tests, remove `main` in `LinearSearchThread`
(#5671)
---
DIRECTORY.md | 1 +
.../searches/LinearSearchThread.java | 83 ++++++++++---------
.../searches/LinearSearchThreadTest.java | 74 +++++++++++++++++
3 files changed, 118 insertions(+), 40 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index cbe176f27440..f0c4486eebe6 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1010,6 +1010,7 @@
* [JumpSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/JumpSearchTest.java)
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [LinearSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchTest.java)
+ * [LinearSearchThreadTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java)
* [MonteCarloTreeSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/LinearSearchThread.java b/src/main/java/com/thealgorithms/searches/LinearSearchThread.java
index b354d312d1b3..ba3cff915f5f 100644
--- a/src/main/java/com/thealgorithms/searches/LinearSearchThread.java
+++ b/src/main/java/com/thealgorithms/searches/LinearSearchThread.java
@@ -1,52 +1,47 @@
package com.thealgorithms.searches;
-import java.util.Scanner;
-
+/**
+ * LinearSearchThread is a multithreaded implementation of the linear search algorithm.
+ * It creates multiple threads to search for a specific number in an array.
+ *
+ *
+ * The class generates an array of random integers, prompts the user to enter a number to search for,
+ * and divides the array into four segments, each handled by a separate thread.
+ * The threads run concurrently and search for the specified number within their designated segments.
+ * Finally, it consolidates the results to determine if the number was found.
+ *
+ *
+ *
+ * Example usage:
+ * 1. The program will output the generated array.
+ * 2. The user will be prompted to input a number to search for.
+ * 3. The program will display whether the number was found in the array.
+ *
+ */
public final class LinearSearchThread {
private LinearSearchThread() {
}
-
- public static void main(String[] args) {
- int[] list = new int[200];
- for (int j = 0; j < list.length; j++) {
- list[j] = (int) (Math.random() * 100);
- }
- for (int y : list) {
- System.out.print(y + " ");
- }
- System.out.println();
- System.out.print("Enter number to search for: ");
- Scanner in = new Scanner(System.in);
- int x = in.nextInt();
- Searcher t = new Searcher(list, 0, 50, x);
- Searcher t1 = new Searcher(list, 50, 100, x);
- Searcher t2 = new Searcher(list, 100, 150, x);
- Searcher t3 = new Searcher(list, 150, 200, x);
- t.start();
- t1.start();
- t2.start();
- t3.start();
- try {
- t.join();
- t1.join();
- t2.join();
- t3.join();
- } catch (InterruptedException e) {
- }
- boolean found = t.getResult() || t1.getResult() || t2.getResult() || t3.getResult();
- System.out.println("Found = " + found);
- in.close();
- }
}
+/**
+ * The Searcher class extends Thread and is responsible for searching for a specific
+ * number in a segment of an array.
+ */
class Searcher extends Thread {
+ private final int[] arr; // The array to search in
+ private final int left; // Starting index of the segment
+ private final int right; // Ending index of the segment
+ private final int x; // The number to search for
+ private boolean found; // Result flag
- private final int[] arr;
- private final int left;
- private final int right;
- private final int x;
- private boolean found;
-
+ /**
+ * Constructor to initialize the Searcher.
+ *
+ * @param arr The array to search in
+ * @param left The starting index of the segment
+ * @param right The ending index of the segment
+ * @param x The number to search for
+ */
Searcher(int[] arr, int left, int right, int x) {
this.arr = arr;
this.left = left;
@@ -54,6 +49,9 @@ class Searcher extends Thread {
this.x = x;
}
+ /**
+ * The run method for the thread, performing the linear search in its segment.
+ */
@Override
public void run() {
int k = left;
@@ -65,6 +63,11 @@ public void run() {
}
}
+ /**
+ * Returns whether the number was found in the segment.
+ *
+ * @return true if the number was found, false otherwise
+ */
boolean getResult() {
return found;
}
diff --git a/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java b/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
new file mode 100644
index 000000000000..534c2a4487b2
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java
@@ -0,0 +1,74 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class LinearSearchThreadTest {
+
+ /**
+ * Test for finding an element that is present in the array.
+ */
+ @Test
+ void testSearcherFound() throws InterruptedException {
+ int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Searcher searcher = new Searcher(array, 0, array.length, 5);
+ searcher.start();
+ searcher.join();
+ assertTrue(searcher.getResult(), "The element 5 should be found in the array.");
+ }
+
+ /**
+ * Test for finding an element that is not present in the array.
+ */
+ @Test
+ void testSearcherNotFound() throws InterruptedException {
+ int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Searcher searcher = new Searcher(array, 0, array.length, 11);
+ searcher.start();
+ searcher.join();
+ assertFalse(searcher.getResult(), "The element 11 should not be found in the array.");
+ }
+
+ /**
+ * Test for searching a segment of the array.
+ */
+ @Test
+ void testSearcherSegmentFound() throws InterruptedException {
+ int[] array = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Searcher searcher = new Searcher(array, 0, 5, 3);
+ searcher.start();
+ searcher.join();
+ assertTrue(searcher.getResult(), "The element 3 should be found in the segment.");
+ }
+
+ /**
+ * Test for searching an empty array segment.
+ */
+ @Test
+ void testSearcherEmptySegment() throws InterruptedException {
+ int[] array = {};
+ Searcher searcher = new Searcher(array, 0, 0, 1); // Empty array
+ searcher.start();
+ searcher.join();
+ assertFalse(searcher.getResult(), "The element should not be found in an empty segment.");
+ }
+
+ /**
+ * Test for searching with random numbers.
+ */
+ @Test
+ void testSearcherRandomNumbers() throws InterruptedException {
+ int size = 200;
+ int[] array = new int[size];
+ for (int i = 0; i < size; i++) {
+ array[i] = (int) (Math.random() * 100);
+ }
+ int target = array[(int) (Math.random() * size)]; // Randomly select a target that is present
+ Searcher searcher = new Searcher(array, 0, size, target);
+ searcher.start();
+ searcher.join();
+ assertTrue(searcher.getResult(), "The randomly selected target should be found in the array.");
+ }
+}
From 4ec270130286146cfc9e9e02993580d484fce26a Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 02:02:32 +0530
Subject: [PATCH 056/348] Add tests, remove `main` in `TernarySearch` (#5677)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/TernarySearch.java | 22 -----
.../searches/TernarySearchTest.java | 81 +++++++++++++++++++
3 files changed, 82 insertions(+), 22 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/TernarySearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index f0c4486eebe6..3863f62c507b 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1022,6 +1022,7 @@
* [SearchInARowAndColWiseSortedMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java)
* [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java)
* [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java)
+ * [TernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TernarySearchTest.java)
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
* [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java)
* sorts
diff --git a/src/main/java/com/thealgorithms/searches/TernarySearch.java b/src/main/java/com/thealgorithms/searches/TernarySearch.java
index 3395bc0b7f30..4d9f55ea9917 100644
--- a/src/main/java/com/thealgorithms/searches/TernarySearch.java
+++ b/src/main/java/com/thealgorithms/searches/TernarySearch.java
@@ -1,9 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.stream.Stream;
/**
* A ternary search algorithm is a technique in computer science for finding the
@@ -60,23 +57,4 @@ private > int ternarySearch(T[] arr, T key, int start, i
return ternarySearch(arr, key, mid1, mid2);
}
}
-
- public static void main(String[] args) {
- // just generate data
- Random r = new Random();
- int size = 100;
- int maxElement = 100000;
- Integer[] integers = Stream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().toArray(Integer[] ::new);
-
- // the element that should be found
- Integer shouldBeFound = integers[r.nextInt(size - 1)];
-
- TernarySearch search = new TernarySearch();
- int atIndex = search.find(integers, shouldBeFound);
-
- System.out.printf("Should be found: %d. Found %d at index %d. An array length %d%n", shouldBeFound, integers[atIndex], atIndex, size);
-
- int toCheck = Arrays.binarySearch(integers, shouldBeFound);
- System.out.printf("Found by system method at an index: %d. Is equal: %b%n", toCheck, toCheck == atIndex);
- }
}
diff --git a/src/test/java/com/thealgorithms/searches/TernarySearchTest.java b/src/test/java/com/thealgorithms/searches/TernarySearchTest.java
new file mode 100644
index 000000000000..367b595e55d9
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/TernarySearchTest.java
@@ -0,0 +1,81 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class TernarySearchTest {
+
+ @Test
+ void testFindElementInSortedArray() {
+ Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 5);
+
+ assertEquals(4, index, "Should find the element 5 at index 4");
+ }
+
+ @Test
+ void testElementNotFound() {
+ Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 11);
+
+ assertEquals(-1, index, "Should return -1 for element 11 which is not present");
+ }
+
+ @Test
+ void testFindFirstElement() {
+ Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 1);
+
+ assertEquals(0, index, "Should find the first element 1 at index 0");
+ }
+
+ @Test
+ void testFindLastElement() {
+ Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 10);
+
+ assertEquals(9, index, "Should find the last element 10 at index 9");
+ }
+
+ @Test
+ void testFindInLargeArray() {
+ Integer[] arr = new Integer[1000];
+ for (int i = 0; i < 1000; i++) {
+ arr[i] = i + 1; // Array from 1 to 1000
+ }
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 500);
+
+ assertEquals(499, index, "Should find element 500 at index 499");
+ }
+
+ @Test
+ void testNegativeNumbers() {
+ Integer[] arr = {-10, -5, -3, -1, 0, 1, 3, 5, 7, 10};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, -3);
+
+ assertEquals(2, index, "Should find the element -3 at index 2");
+ }
+
+ @Test
+ void testEdgeCaseEmptyArray() {
+ Integer[] arr = {};
+ TernarySearch search = new TernarySearch();
+
+ int index = search.find(arr, 5);
+
+ assertEquals(-1, index, "Should return -1 for an empty array");
+ }
+}
From b1aeac5cd68c3cafc56739f8a021587c8f3e33d7 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 02:06:06 +0530
Subject: [PATCH 057/348] Add tests, remove `main` in `UpperBound` (#5679)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/UpperBound.java | 25 -----
.../searches/UpperBoundTest.java | 99 +++++++++++++++++++
3 files changed, 100 insertions(+), 25 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/UpperBoundTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 3863f62c507b..7ebc176b02cf 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1025,6 +1025,7 @@
* [TernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TernarySearchTest.java)
* [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java)
* [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java)
+ * [UpperBoundTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UpperBoundTest.java)
* sorts
* [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java)
* [BinaryInsertionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/UpperBound.java b/src/main/java/com/thealgorithms/searches/UpperBound.java
index bbce617a143b..ec52c7a0ae5c 100644
--- a/src/main/java/com/thealgorithms/searches/UpperBound.java
+++ b/src/main/java/com/thealgorithms/searches/UpperBound.java
@@ -1,9 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.IntStream;
/**
* The UpperBound method is used to return an index pointing to the first
@@ -25,28 +22,6 @@
*/
class UpperBound implements SearchAlgorithm {
- // Driver Program
- public static void main(String[] args) {
- // Just generate data
- Random r = ThreadLocalRandom.current();
-
- int size = 100;
- int maxElement = 100000;
-
- Integer[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().boxed().toArray(Integer[] ::new);
-
- // The element for which the upper bound is to be found
- int val = integers[r.nextInt(size - 1)] + 1;
-
- UpperBound search = new UpperBound();
- int atIndex = search.find(integers, val);
-
- System.out.printf("Val: %d. Upper Bound Found %d at index %d. An array length %d%n", val, integers[atIndex], atIndex, size);
-
- boolean toCheck = integers[atIndex] > val || integers[size - 1] < val;
- System.out.printf("Upper Bound found at an index: %d. Is greater or max element: %b%n", atIndex, toCheck);
- }
-
/**
* @param array is an array where the UpperBound value is to be found
* @param key is an element for which the UpperBound is to be found
diff --git a/src/test/java/com/thealgorithms/searches/UpperBoundTest.java b/src/test/java/com/thealgorithms/searches/UpperBoundTest.java
new file mode 100644
index 000000000000..dc0cbdd97e19
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/UpperBoundTest.java
@@ -0,0 +1,99 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Random;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class UpperBoundTest {
+
+ private UpperBound upperBound;
+ private Integer[] sortedArray;
+
+ @BeforeEach
+ void setUp() {
+ upperBound = new UpperBound();
+
+ // Generate a sorted array of random integers for testing
+ Random random = new Random();
+ int size = 100;
+ int maxElement = 100;
+ sortedArray = random.ints(size, 1, maxElement)
+ .distinct() // Ensure all elements are unique
+ .sorted()
+ .boxed()
+ .toArray(Integer[] ::new);
+ }
+
+ @Test
+ void testUpperBoundFound() {
+ int key = sortedArray[sortedArray.length - 1] + 1; // Test with a key larger than max element
+ int index = upperBound.find(sortedArray, key);
+
+ // The upper bound should be equal to the length of the array
+ assertEquals(sortedArray.length - 1, index, "Upper bound for a larger key should be the size of the array.");
+ }
+
+ @Test
+ void testUpperBoundExactMatch() {
+ int key = sortedArray[sortedArray.length / 2]; // Choose a key from the middle of the array
+ int index = upperBound.find(sortedArray, key);
+
+ // The index should point to the first element greater than the key
+ assertTrue(index < sortedArray.length, "Upper bound should not exceed array length.");
+ assertTrue(sortedArray[index] > key, "The element at the index should be greater than the key.");
+ }
+
+ @Test
+ void testUpperBoundMultipleValues() {
+ Integer[] arrayWithDuplicates = new Integer[] {1, 1, 2, 3, 4, 4, 5, 6, 7, 8, 9}; // Test array with duplicates
+ int key = 4;
+ int index = upperBound.find(arrayWithDuplicates, key);
+
+ assertTrue(index < arrayWithDuplicates.length, "Upper bound index should be valid.");
+ assertEquals(6, index, "The upper bound for 4 should be the index of the first 5.");
+ assertTrue(arrayWithDuplicates[index] > key, "Element at the upper bound index should be greater than the key.");
+ }
+
+ @Test
+ void testUpperBoundLowerThanMin() {
+ int key = 0; // Test with a key lower than the minimum element
+ int index = upperBound.find(sortedArray, key);
+
+ assertEquals(0, index, "Upper bound for a key lower than minimum should be 0.");
+ assertTrue(sortedArray[index] > key, "The element at index 0 should be greater than the key.");
+ }
+
+ @Test
+ void testUpperBoundHigherThanMax() {
+ int key = sortedArray[sortedArray.length - 1] + 1; // Test with a key higher than maximum element
+ int index = upperBound.find(sortedArray, key);
+
+ assertEquals(sortedArray.length - 1, index, "Upper bound for a key higher than maximum should be the size of the array.");
+ }
+
+ @Test
+ void testUpperBoundEdgeCase() {
+ // Edge case: empty array
+ Integer[] emptyArray = {};
+ int index = upperBound.find(emptyArray, 5);
+
+ assertEquals(0, index, "Upper bound for an empty array should be 0.");
+ }
+
+ @Test
+ void testUpperBoundSingleElementArray() {
+ Integer[] singleElementArray = {10};
+ int index = upperBound.find(singleElementArray, 5);
+
+ assertEquals(0, index, "Upper bound for 5 in a single element array should be 0.");
+
+ index = upperBound.find(singleElementArray, 10);
+ assertEquals(0, index, "Upper bound for 10 in a single element array should be 0.");
+
+ index = upperBound.find(singleElementArray, 15);
+ assertEquals(0, index, "Upper bound for 15 in a single element array should be 0.");
+ }
+}
From 79544c81eb5525ebc0e5a930c897d6d2e141481e Mon Sep 17 00:00:00 2001
From: Saahil Mahato <115351000+saahil-mahato@users.noreply.github.com>
Date: Fri, 11 Oct 2024 02:26:58 +0545
Subject: [PATCH 058/348] feat: add solovay strassen primality test (#5692)
* feat: add solovay strassen primality test
* chore: add wikipedia link
* fix: format and coverage
* fix: mvn stylecheck
* fix: PMD errors
* refactor: make random final
---------
Co-authored-by: Alex Klymenko
---
.../maths/SolovayStrassenPrimalityTest.java | 133 ++++++++++++++++++
.../SolovayStrassenPrimalityTestTest.java | 122 ++++++++++++++++
2 files changed, 255 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java
create mode 100644 src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java
diff --git a/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java b/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java
new file mode 100644
index 000000000000..caa1abfc3203
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java
@@ -0,0 +1,133 @@
+package com.thealgorithms.maths;
+
+import java.util.Random;
+
+/**
+ * This class implements the Solovay-Strassen primality test,
+ * which is a probabilistic algorithm to determine whether a number is prime.
+ * The algorithm is based on properties of the Jacobi symbol and modular exponentiation.
+ *
+ * For more information, go to {@link https://en.wikipedia.org/wiki/Solovay%E2%80%93Strassen_primality_test}
+ */
+final class SolovayStrassenPrimalityTest {
+
+ private final Random random;
+
+ /**
+ * Constructs a SolovayStrassenPrimalityTest instance with a specified seed for randomness.
+ *
+ * @param seed the seed for generating random numbers
+ */
+ private SolovayStrassenPrimalityTest(int seed) {
+ random = new Random(seed);
+ }
+
+ /**
+ * Factory method to create an instance of SolovayStrassenPrimalityTest.
+ *
+ * @param seed the seed for generating random numbers
+ * @return a new instance of SolovayStrassenPrimalityTest
+ */
+ public static SolovayStrassenPrimalityTest getSolovayStrassenPrimalityTest(int seed) {
+ return new SolovayStrassenPrimalityTest(seed);
+ }
+
+ /**
+ * Calculates modular exponentiation using the method of exponentiation by squaring.
+ *
+ * @param base the base number
+ * @param exponent the exponent
+ * @param mod the modulus
+ * @return (base^exponent) mod mod
+ */
+ private static long calculateModularExponentiation(long base, long exponent, long mod) {
+ long x = 1; // This will hold the result of (base^exponent) % mod
+ long y = base; // This holds the current base value being squared
+
+ while (exponent > 0) {
+ // If exponent is odd, multiply the current base (y) with x
+ if (exponent % 2 == 1) {
+ x = x * y % mod; // Update result with current base
+ }
+ // Square the base for the next iteration
+ y = y * y % mod; // Update base to be y^2
+ exponent = exponent / 2; // Halve the exponent for next iteration
+ }
+
+ return x % mod; // Return final result after all iterations
+ }
+
+ /**
+ * Computes the Jacobi symbol (a/n), which is a generalization of the Legendre symbol.
+ *
+ * @param a the numerator
+ * @param num the denominator (must be an odd positive integer)
+ * @return the Jacobi symbol value: 1, -1, or 0
+ */
+ public int calculateJacobi(long a, long num) {
+ // Check if num is non-positive or even; Jacobi symbol is not defined in these cases
+ if (num <= 0 || num % 2 == 0) {
+ return 0;
+ }
+
+ a = a % num; // Reduce a modulo num to simplify calculations
+ int jacobi = 1; // Initialize Jacobi symbol value
+
+ while (a != 0) {
+ // While a is even, reduce it and adjust jacobi based on properties of num
+ while (a % 2 == 0) {
+ a /= 2; // Divide a by 2 until it becomes odd
+ long nMod8 = num % 8; // Get num modulo 8 to check conditions for jacobi adjustment
+ if (nMod8 == 3 || nMod8 == 5) {
+ jacobi = -jacobi; // Flip jacobi sign based on properties of num modulo 8
+ }
+ }
+
+ long temp = a; // Temporarily store value of a
+ a = num; // Set a to be num for next iteration
+ num = temp; // Set num to be previous value of a
+
+ // Adjust jacobi based on properties of both numbers when both are odd and congruent to 3 modulo 4
+ if (a % 4 == 3 && num % 4 == 3) {
+ jacobi = -jacobi; // Flip jacobi sign again based on congruences
+ }
+
+ a = a % num; // Reduce a modulo num for next iteration of Jacobi computation
+ }
+
+ return (num == 1) ? jacobi : 0; // If num reduces to 1, return jacobi value, otherwise return 0 (not defined)
+ }
+
+ /**
+ * Performs the Solovay-Strassen primality test on a given number.
+ *
+ * @param num the number to be tested for primality
+ * @param iterations the number of iterations to run for accuracy
+ * @return true if num is likely prime, false if it is composite
+ */
+ public boolean solovayStrassen(long num, int iterations) {
+ if (num <= 1) {
+ return false; // Numbers <=1 are not prime by definition.
+ }
+ if (num <= 3) {
+ return true; // Numbers <=3 are prime.
+ }
+
+ for (int i = 0; i < iterations; i++) {
+ long r = Math.abs(random.nextLong() % (num - 1)) + 2; // Generate a non-negative random number.
+ long a = r % (num - 1) + 1; // Choose random 'a' in range [1, n-1].
+
+ long jacobi = (num + calculateJacobi(a, num)) % num;
+ // Calculate Jacobi symbol and adjust it modulo n.
+
+ long mod = calculateModularExponentiation(a, (num - 1) / 2, num);
+ // Calculate modular exponentiation: a^((n-1)/2) mod n.
+
+ if (jacobi == 0 || mod != jacobi) {
+ return false; // If Jacobi symbol is zero or doesn't match modular result, n is composite.
+ }
+ }
+
+ return true; // If no contradictions found after all iterations, n is likely prime.
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java b/src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java
new file mode 100644
index 000000000000..18cc35266c8c
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java
@@ -0,0 +1,122 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+/**
+ * Unit tests for the {@link SolovayStrassenPrimalityTest} class.
+ * This class tests the functionality of the Solovay-Strassen primality test implementation.
+ */
+class SolovayStrassenPrimalityTestTest {
+
+ private static final int RANDOM_SEED = 123; // Seed for reproducibility
+ private SolovayStrassenPrimalityTest testInstance;
+
+ /**
+ * Sets up a new instance of {@link SolovayStrassenPrimalityTest}
+ * before each test case, using a fixed random seed for consistency.
+ */
+ @BeforeEach
+ void setUp() {
+ testInstance = SolovayStrassenPrimalityTest.getSolovayStrassenPrimalityTest(RANDOM_SEED);
+ }
+
+ /**
+ * Provides test cases for prime numbers with various values of n and k (iterations).
+ *
+ * @return an array of objects containing pairs of n and k values
+ */
+ static Object[][] primeNumbers() {
+ return new Object[][] {{2, 1}, {3, 1}, {5, 5}, {7, 10}, {11, 20}, {13, 10}, {17, 5}, {19, 1}};
+ }
+
+ /**
+ * Tests known prime numbers with various values of n and k (iterations).
+ *
+ * @param n the number to be tested for primality
+ * @param k the number of iterations to use in the primality test
+ */
+ @ParameterizedTest
+ @MethodSource("primeNumbers")
+ void testPrimeNumbersWithDifferentNAndK(int n, int k) {
+ assertTrue(testInstance.solovayStrassen(n, k), n + " should be prime");
+ }
+
+ /**
+ * Provides test cases for composite numbers with various values of n and k (iterations).
+ *
+ * @return an array of objects containing pairs of n and k values
+ */
+ static Object[][] compositeNumbers() {
+ return new Object[][] {{4, 1}, {6, 5}, {8, 10}, {9, 20}, {10, 1}, {12, 5}, {15, 10}};
+ }
+
+ /**
+ * Tests known composite numbers with various values of n and k (iterations).
+ *
+ * @param n the number to be tested for primality
+ * @param k the number of iterations to use in the primality test
+ */
+ @ParameterizedTest
+ @MethodSource("compositeNumbers")
+ void testCompositeNumbersWithDifferentNAndK(int n, int k) {
+ assertFalse(testInstance.solovayStrassen(n, k), n + " should be composite");
+ }
+
+ /**
+ * Tests edge cases for the primality test.
+ * This includes negative numbers and small integers (0 and 1).
+ */
+ @Test
+ void testEdgeCases() {
+ assertFalse(testInstance.solovayStrassen(-1, 10), "-1 should not be prime");
+ assertFalse(testInstance.solovayStrassen(0, 10), "0 should not be prime");
+ assertFalse(testInstance.solovayStrassen(1, 10), "1 should not be prime");
+
+ // Test small primes and composites
+ assertTrue(testInstance.solovayStrassen(2, 1), "2 is a prime number (single iteration)");
+ assertFalse(testInstance.solovayStrassen(9, 1), "9 is a composite number (single iteration)");
+
+ // Test larger primes and composites
+ long largePrime = 104729; // Known large prime number
+ long largeComposite = 104730; // Composite number (even)
+
+ assertTrue(testInstance.solovayStrassen(largePrime, 20), "104729 is a prime number");
+ assertFalse(testInstance.solovayStrassen(largeComposite, 20), "104730 is a composite number");
+
+ // Test very large numbers (may take longer)
+ long veryLargePrime = 512927357; // Known very large prime number
+ long veryLargeComposite = 512927358; // Composite number (even)
+
+ assertTrue(testInstance.solovayStrassen(veryLargePrime, 20), Long.MAX_VALUE - 1 + " is likely a prime number.");
+
+ assertFalse(testInstance.solovayStrassen(veryLargeComposite, 20), Long.MAX_VALUE + " is a composite number.");
+ }
+
+ /**
+ * Tests the Jacobi symbol calculation directly for known values.
+ * This verifies that the Jacobi symbol method behaves as expected.
+ */
+ @Test
+ void testJacobiSymbolCalculation() {
+ // Jacobi symbol (a/n) where n is odd and positive
+ int jacobi1 = testInstance.calculateJacobi(6, 11); // Should return -1
+ int jacobi2 = testInstance.calculateJacobi(5, 11); // Should return +1
+
+ assertEquals(-1, jacobi1);
+ assertEquals(+1, jacobi2);
+
+ // Edge case: Jacobi symbol with even n or non-positive n
+ int jacobi4 = testInstance.calculateJacobi(5, -11); // Should return 0 (invalid)
+ int jacobi5 = testInstance.calculateJacobi(5, 0); // Should return 0 (invalid)
+
+ assertEquals(0, jacobi4);
+ assertEquals(0, jacobi5);
+ }
+}
From 7326ab2c121ff7059bd17e5745afa7d70b98d0f0 Mon Sep 17 00:00:00 2001
From: Rupa <102663541+Rupa-Rd@users.noreply.github.com>
Date: Fri, 11 Oct 2024 02:16:43 +0530
Subject: [PATCH 059/348] Add Space Optimized Solution to Subset sum problem
(#5612)
---
.../SubsetSumSpaceOptimized.java | 35 +++++++++++++++++++
.../SubsetSumSpaceOptimizedTest.java | 18 ++++++++++
2 files changed, 53 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java
new file mode 100644
index 000000000000..946da46cb292
--- /dev/null
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java
@@ -0,0 +1,35 @@
+package com.thealgorithms.dynamicprogramming;
+/*
+The Sum of Subset problem determines whether a subset of elements from a
+given array sums up to a specific target value.
+*/
+public final class SubsetSumSpaceOptimized {
+ private SubsetSumSpaceOptimized() {
+ }
+ /**
+ * This method checks whether the subset of an array
+ * contains a given sum or not. This is an space
+ * optimized solution using 1D boolean array
+ * Time Complexity: O(n * sum), Space complexity: O(sum)
+ *
+ * @param arr An array containing integers
+ * @param sum The target sum of the subset
+ * @return True or False
+ */
+ public static boolean isSubsetSum(int[] arr, int sum) {
+ int n = arr.length;
+ // Declare the boolean array with size sum + 1
+ boolean[] dp = new boolean[sum + 1];
+
+ // Initialize the first element as true
+ dp[0] = true;
+
+ // Find the subset sum using 1D array
+ for (int i = 0; i < n; i++) {
+ for (int j = sum; j >= arr[i]; j--) {
+ dp[j] = dp[j] || dp[j - arr[i]];
+ }
+ }
+ return dp[sum];
+ }
+}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java
new file mode 100644
index 000000000000..3a965f4e68b8
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java
@@ -0,0 +1,18 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class SubsetSumSpaceOptimizedTest {
+
+ @Test
+ void basicCheck() {
+ assertTrue(SubsetSumSpaceOptimized.isSubsetSum(new int[] {7, 3, 2, 5, 8}, 14));
+ assertTrue(SubsetSumSpaceOptimized.isSubsetSum(new int[] {4, 3, 2, 1}, 5));
+ assertTrue(SubsetSumSpaceOptimized.isSubsetSum(new int[] {1, 7, 2, 9, 10}, 13));
+ assertFalse(SubsetSumSpaceOptimized.isSubsetSum(new int[] {1, 2, 7, 10, 9}, 14));
+ assertFalse(SubsetSumSpaceOptimized.isSubsetSum(new int[] {2, 15, 1, 6, 7}, 4));
+ }
+}
From 2040df88d94ab3d0c2bcec17f5b499b5ae644768 Mon Sep 17 00:00:00 2001
From: xuyang471 <2621860014@qq.com>
Date: Fri, 11 Oct 2024 13:47:36 +0800
Subject: [PATCH 060/348] Add Elliptic Curve Cryptography (#5700)
---
.../java/com/thealgorithms/ciphers/ECC.java | 236 ++++++++++++++++++
.../com/thealgorithms/ciphers/ECCTest.java | 106 ++++++++
2 files changed, 342 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/ciphers/ECC.java
create mode 100644 src/test/java/com/thealgorithms/ciphers/ECCTest.java
diff --git a/src/main/java/com/thealgorithms/ciphers/ECC.java b/src/main/java/com/thealgorithms/ciphers/ECC.java
new file mode 100644
index 000000000000..7b1e37f0e1e1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ECC.java
@@ -0,0 +1,236 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * ECC - Elliptic Curve Cryptography
+ * Elliptic Curve Cryptography is a public-key cryptography method that uses the algebraic structure of
+ * elliptic curves over finite fields. ECC provides a higher level of security with smaller key sizes compared
+ * to other public-key methods like RSA, making it particularly suitable for environments where computational
+ * resources are limited, such as mobile devices and embedded systems.
+ *
+ * This class implements elliptic curve cryptography, providing encryption and decryption
+ * functionalities based on public and private key pairs.
+ *
+ * @author xuyang
+ */
+public class ECC {
+
+ private BigInteger privateKey; // Private key used for decryption
+ private ECPoint publicKey; // Public key used for encryption
+ private EllipticCurve curve; // Elliptic curve used in cryptography
+ private ECPoint basePoint; // Base point G on the elliptic curve
+
+ public ECC(int bits) {
+ generateKeys(bits); // Generates public-private key pair
+ }
+
+ public EllipticCurve getCurve() {
+ return curve; // Returns the elliptic curve
+ }
+
+ public void setCurve(EllipticCurve curve) {
+ this.curve = curve;
+ }
+
+ // Getter and Setter for private key
+ public BigInteger getPrivateKey() {
+ return privateKey;
+ }
+
+ public void setPrivateKey(BigInteger privateKey) {
+ this.privateKey = privateKey;
+ }
+
+ /**
+ * Encrypts the message using the public key.
+ * The message is transformed into an ECPoint and encrypted with elliptic curve operations.
+ *
+ * @param message The plain message to be encrypted
+ * @return The encrypted message as an array of ECPoints (R, S)
+ */
+ public ECPoint[] encrypt(String message) {
+ BigInteger m = new BigInteger(message.getBytes()); // Convert message to BigInteger
+ SecureRandom r = new SecureRandom(); // Generate random value for k
+ BigInteger k = new BigInteger(curve.getFieldSize(), r); // Generate random scalar k
+
+ // Calculate point r = k * G, where G is the base point
+ ECPoint rPoint = basePoint.multiply(k, curve.getP(), curve.getA());
+
+ // Calculate point s = k * publicKey + encodedMessage
+ ECPoint sPoint = publicKey.multiply(k, curve.getP(), curve.getA()).add(curve.encodeMessage(m), curve.getP(), curve.getA());
+
+ return new ECPoint[] {rPoint, sPoint}; // Return encrypted message as two ECPoints
+ }
+
+ /**
+ * Decrypts the encrypted message using the private key.
+ * The decryption process is the reverse of encryption, recovering the original message.
+ *
+ * @param encryptedMessage The encrypted message as an array of ECPoints (R, S)
+ * @return The decrypted plain message as a String
+ */
+ public String decrypt(ECPoint[] encryptedMessage) {
+ ECPoint rPoint = encryptedMessage[0]; // First part of ciphertext
+ ECPoint sPoint = encryptedMessage[1]; // Second part of ciphertext
+
+ // Perform decryption: s - r * privateKey
+ ECPoint decodedMessage = sPoint.subtract(rPoint.multiply(privateKey, curve.getP(), curve.getA()), curve.getP(), curve.getA());
+
+ BigInteger m = curve.decodeMessage(decodedMessage); // Decode the message from ECPoint
+
+ return new String(m.toByteArray()); // Convert BigInteger back to String
+ }
+
+ /**
+ * Generates a new public-private key pair for encryption and decryption.
+ *
+ * @param bits The size (in bits) of the keys to generate
+ */
+ public final void generateKeys(int bits) {
+ SecureRandom r = new SecureRandom();
+ curve = new EllipticCurve(bits); // Initialize a new elliptic curve
+ basePoint = curve.getBasePoint(); // Set the base point G
+
+ // Generate private key as a random BigInteger
+ privateKey = new BigInteger(bits, r);
+
+ // Generate public key as the point publicKey = privateKey * G
+ publicKey = basePoint.multiply(privateKey, curve.getP(), curve.getA());
+ }
+
+ /**
+ * Class representing an elliptic curve with the form y^2 = x^3 + ax + b.
+ */
+ public static class EllipticCurve {
+ private final BigInteger a; // Coefficient a in the curve equation
+ private final BigInteger b; // Coefficient b in the curve equation
+ private final BigInteger p; // Prime number p, defining the finite field
+ private final ECPoint basePoint; // Base point G on the curve
+
+ // Constructor with explicit parameters for a, b, p, and base point
+ public EllipticCurve(BigInteger a, BigInteger b, BigInteger p, ECPoint basePoint) {
+ this.a = a;
+ this.b = b;
+ this.p = p;
+ this.basePoint = basePoint;
+ }
+
+ // Constructor that randomly generates the curve parameters
+ public EllipticCurve(int bits) {
+ SecureRandom r = new SecureRandom();
+ this.p = BigInteger.probablePrime(bits, r); // Random prime p
+ this.a = new BigInteger(bits, r); // Random coefficient a
+ this.b = new BigInteger(bits, r); // Random coefficient b
+ this.basePoint = new ECPoint(BigInteger.valueOf(4), BigInteger.valueOf(8)); // Fixed base point G
+ }
+
+ public ECPoint getBasePoint() {
+ return basePoint;
+ }
+
+ public BigInteger getP() {
+ return p;
+ }
+
+ public BigInteger getA() {
+ return a;
+ }
+
+ public BigInteger getB() {
+ return b;
+ }
+
+ public int getFieldSize() {
+ return p.bitLength();
+ }
+
+ public ECPoint encodeMessage(BigInteger message) {
+ // Simple encoding of a message as an ECPoint (this is a simplified example)
+ return new ECPoint(message, message);
+ }
+
+ public BigInteger decodeMessage(ECPoint point) {
+ return point.getX(); // Decode the message from ECPoint (simplified)
+ }
+ }
+
+ /**
+ * Class representing a point on the elliptic curve.
+ */
+ public static class ECPoint {
+ private final BigInteger x; // X-coordinate of the point
+ private final BigInteger y; // Y-coordinate of the point
+
+ public ECPoint(BigInteger x, BigInteger y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public BigInteger getX() {
+ return x;
+ }
+
+ public BigInteger getY() {
+ return y;
+ }
+
+ @Override
+ public String toString() {
+ return "ECPoint(x=" + x.toString() + ", y=" + y.toString() + ")";
+ }
+
+ /**
+ * Add two points on the elliptic curve.
+ */
+ public ECPoint add(ECPoint other, BigInteger p, BigInteger a) {
+ if (this.x.equals(BigInteger.ZERO) && this.y.equals(BigInteger.ZERO)) {
+ return other; // If this point is the identity, return the other point
+ }
+ if (other.x.equals(BigInteger.ZERO) && other.y.equals(BigInteger.ZERO)) {
+ return this; // If the other point is the identity, return this point
+ }
+
+ BigInteger lambda;
+ if (this.equals(other)) {
+ // Special case: point doubling
+ lambda = this.x.pow(2).multiply(BigInteger.valueOf(3)).add(a).multiply(this.y.multiply(BigInteger.valueOf(2)).modInverse(p)).mod(p);
+ } else {
+ // General case: adding two different points
+ lambda = other.y.subtract(this.y).multiply(other.x.subtract(this.x).modInverse(p)).mod(p);
+ }
+
+ BigInteger xr = lambda.pow(2).subtract(this.x).subtract(other.x).mod(p);
+ BigInteger yr = lambda.multiply(this.x.subtract(xr)).subtract(this.y).mod(p);
+
+ return new ECPoint(xr, yr);
+ }
+
+ /**
+ * Subtract two points on the elliptic curve.
+ */
+ public ECPoint subtract(ECPoint other, BigInteger p, BigInteger a) {
+ ECPoint negOther = new ECPoint(other.x, p.subtract(other.y)); // Negate the Y coordinate
+ return this.add(negOther, p, a); // Add the negated point
+ }
+
+ /**
+ * Multiply a point by a scalar (repeated addition).
+ */
+ public ECPoint multiply(BigInteger k, BigInteger p, BigInteger a) {
+ ECPoint result = new ECPoint(BigInteger.ZERO, BigInteger.ZERO); // Identity point
+ ECPoint addend = this;
+
+ while (k.signum() > 0) {
+ if (k.testBit(0)) {
+ result = result.add(addend, p, a); // Add the current point
+ }
+ addend = addend.add(addend, p, a); // Double the point
+ k = k.shiftRight(1); // Divide k by 2
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/ECCTest.java b/src/test/java/com/thealgorithms/ciphers/ECCTest.java
new file mode 100644
index 000000000000..701f801af1c8
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/ECCTest.java
@@ -0,0 +1,106 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import java.math.BigInteger;
+import org.junit.jupiter.api.Test;
+
+/**
+ * ECCTest - Unit tests for the ECC (Elliptic Curve Cryptography) implementation.
+ * This class contains various test cases to validate the encryption and decryption functionalities.
+ * It ensures the correctness and randomness of ECC operations.
+ *
+ * @author xuyang
+ */
+public class ECCTest {
+ ECC ecc = new ECC(256); // Generate a 256-bit ECC key pair. Calls generateKeys(bits) to create keys including privateKey and publicKey.
+
+ /**
+ * Test the encryption functionality: convert plaintext to ciphertext and output relevant encryption data.
+ */
+ @Test
+ void testEncrypt() {
+ String textToEncrypt = "Elliptic Curve Cryptography";
+
+ ECC.ECPoint[] cipherText = ecc.encrypt(textToEncrypt); // Perform encryption
+
+ // Output private key information
+ System.out.println("Private Key: " + ecc.getPrivateKey());
+
+ // Output elliptic curve parameters
+ ECC.EllipticCurve curve = ecc.getCurve();
+ System.out.println("Elliptic Curve Parameters:");
+ System.out.println("a: " + curve.getA());
+ System.out.println("b: " + curve.getB());
+ System.out.println("p: " + curve.getP());
+ System.out.println("Base Point G: " + curve.getBasePoint());
+
+ // Verify that the ciphertext is not empty
+ assertEquals(cipherText.length, 2); // Check if the ciphertext contains two points (R and S)
+
+ // Output the encrypted coordinate points
+ System.out.println("Encrypted Points:");
+ for (ECC.ECPoint point : cipherText) {
+ System.out.println(point); // Calls ECPoint's toString() method
+ }
+ }
+
+ /**
+ * Test the decryption functionality: convert ciphertext back to plaintext using known private key and elliptic curve parameters.
+ */
+ @Test
+ void testDecryptWithKnownValues() {
+ // 1. Define the known private key
+ BigInteger knownPrivateKey = new BigInteger("28635978664199231399690075483195602260051035216440375973817268759912070302603");
+
+ // 2. Define the known elliptic curve parameters
+ BigInteger a = new BigInteger("64505295837372135469230827475895976532873592609649950000895066186842236488761"); // Replace with known a value
+ BigInteger b = new BigInteger("89111668838830965251111555638616364203833415376750835901427122343021749874324"); // Replace with known b value
+ BigInteger p = new BigInteger("107276428198310591598877737561885175918069075479103276920057092968372930219921"); // Replace with known p value
+ ECC.ECPoint basePoint = new ECC.ECPoint(new BigInteger("4"), new BigInteger("8")); // Replace with known base point coordinates
+
+ // 3. Create the elliptic curve object
+ ECC.EllipticCurve curve = new ECC.EllipticCurve(a, b, p, basePoint);
+
+ // 4. Define the known ciphertext containing two ECPoints (R, S)
+ ECC.ECPoint rPoint = new ECC.ECPoint(new BigInteger("103077584019003058745849614420912636617007257617156724481937620119667345237687"), new BigInteger("68193862907937248121971710522760893811582068323088661566426323952783362061817"));
+ ECC.ECPoint sPoint = new ECC.ECPoint(new BigInteger("31932232426664380635434632300383525435115368414929679432313910646436992147798"), new BigInteger("77299754382292904069123203569944908076819220797512755280123348910207308129766"));
+ ECC.ECPoint[] cipherText = new ECC.ECPoint[] {rPoint, sPoint};
+
+ // 5. Create an ECC instance and set the private key and curve parameters
+ ecc.setPrivateKey(knownPrivateKey); // Use setter method to set the private key
+ ecc.setCurve(curve); // Use setter method to set the elliptic curve
+
+ // 6. Decrypt the known ciphertext
+ String decryptedMessage = ecc.decrypt(cipherText);
+
+ // 7. Compare the decrypted plaintext with the expected value
+ String expectedMessage = "Elliptic Curve Cryptography"; // Expected plaintext
+ assertEquals(expectedMessage, decryptedMessage);
+ }
+
+ /**
+ * Test that encrypting the same plaintext with ECC produces different ciphertexts.
+ */
+ @Test
+ void testCipherTextRandomness() {
+ String message = "Elliptic Curve Cryptography";
+
+ ECC.ECPoint[] cipherText1 = ecc.encrypt(message);
+ ECC.ECPoint[] cipherText2 = ecc.encrypt(message);
+
+ assertNotEquals(cipherText1, cipherText2); // Ensure that the two ciphertexts are different
+ }
+
+ /**
+ * Test the entire ECC encryption and decryption process.
+ */
+ @Test
+ void testECCEncryptionAndDecryption() {
+ String textToEncrypt = "Elliptic Curve Cryptography";
+ ECC.ECPoint[] cipherText = ecc.encrypt(textToEncrypt);
+ String decryptedText = ecc.decrypt(cipherText);
+ assertEquals(textToEncrypt, decryptedText); // Verify that the decrypted text matches the original text
+ }
+}
From 233842857838c9be50c8f2f4c6b34a86c07a1583 Mon Sep 17 00:00:00 2001
From: Varnan Rathod <119997446+Krounosity@users.noreply.github.com>
Date: Fri, 11 Oct 2024 11:35:26 +0530
Subject: [PATCH 061/348] Add cipher class, cipher tests, enhance docs in
'AtbashCipher.java' (#5690)
---
DIRECTORY.md | 2 +
.../thealgorithms/ciphers/AtbashCipher.java | 71 +++++++++++++++++++
.../com/thealgorithms/ciphers/AtbashTest.java | 28 ++++++++
3 files changed, 101 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
create mode 100644 src/test/java/com/thealgorithms/ciphers/AtbashTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 7ebc176b02cf..e022ddc23e5a 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -50,6 +50,7 @@
* [AES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AES.java)
* [AESEncryption](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AESEncryption.java)
* [AffineCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AffineCipher.java)
+ * [AtbashCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java)
* [Autokey](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Autokey.java)
* [Blowfish](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Blowfish.java)
* [Caesar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Caesar.java)
@@ -663,6 +664,7 @@
* [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
* [AESEncryptionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java)
* [AffineCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java)
+ * [AtbashTest](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AtbashTest.java)
* [AutokeyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AutokeyTest.java)
* [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
* [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
diff --git a/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
new file mode 100644
index 000000000000..c3b673144c63
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
@@ -0,0 +1,71 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * The Atbash cipher is a simple substitution cipher that replaces each letter
+ * in the alphabet with its reverse.
+ * For example, 'A' becomes 'Z', 'B' becomes 'Y', and so on. It works
+ * identically for both uppercase and lowercase letters.
+ * It's a symmetric cipher, meaning applying it twice returns the original text.
+ * Hence, the encrypting and the decrypting functions are identical
+ * @author https://github.com/Krounosity
+ * Learn more: https://en.wikipedia.org/wiki/Atbash
+ */
+
+public class AtbashCipher {
+
+ private String toConvert;
+
+ // Default constructor.
+ AtbashCipher() {
+ }
+
+ // String setting constructor.
+ AtbashCipher(String str) {
+ toConvert = str;
+ }
+
+ // String getter method.
+ public String getString() {
+ return toConvert;
+ }
+
+ // String setter method.
+ public void setString(String str) {
+ toConvert = str;
+ }
+
+ // Checking whether the current character is capital.
+ private boolean isCapital(char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ // Checking whether the current character is smallcased.
+ private boolean isSmall(char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ // Converting text to atbash cipher code or vice versa.
+ public String convert() {
+
+ // Using StringBuilder to store new string.
+ StringBuilder convertedString = new StringBuilder();
+
+ // Iterating for each character.
+ for (char ch : toConvert.toCharArray()) {
+
+ // If the character is smallcased.
+ if (isSmall(ch)) {
+ convertedString.append((char) ('z' - (ch - 'a')));
+ }
+ // If the character is capital cased.
+ else if (isCapital(ch)) {
+ convertedString.append((char) ('Z' - (ch - 'A')));
+ }
+ // Non-alphabetical character.
+ else {
+ convertedString.append(ch);
+ }
+ }
+ return convertedString.toString();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/AtbashTest.java b/src/test/java/com/thealgorithms/ciphers/AtbashTest.java
new file mode 100644
index 000000000000..26812cf2b0d4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/AtbashTest.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class AtbashTest {
+
+ @Test
+ public void atbashEncrypt() {
+ AtbashCipher normalToEncrypt = new AtbashCipher("Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!");
+ String expectedText = "Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!";
+
+ normalToEncrypt.setString(normalToEncrypt.convert());
+
+ assertEquals(expectedText, normalToEncrypt.getString());
+ }
+
+ @Test
+ public void atbashDecrypt() {
+ AtbashCipher encryptToNormal = new AtbashCipher("Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!");
+ String expectedText = "Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!";
+
+ encryptToNormal.setString(encryptToNormal.convert());
+
+ assertEquals(expectedText, encryptToNormal.getString());
+ }
+}
From 0ca43981885ea294987b33ee03ea03645c2061ca Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Fri, 11 Oct 2024 19:28:34 +0530
Subject: [PATCH 062/348] feat: Add `RandomSearch` new algorithm with Junit
tests (#5701)
---
DIRECTORY.md | 10 ++-
.../thealgorithms/searches/RandomSearch.java | 45 ++++++++++
.../searches/RandomSearchTest.java | 87 +++++++++++++++++++
3 files changed, 141 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/com/thealgorithms/searches/RandomSearch.java
create mode 100644 src/test/java/com/thealgorithms/searches/RandomSearchTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index e022ddc23e5a..d0f50b421297 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -56,6 +56,7 @@
* [Caesar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Caesar.java)
* [ColumnarTranspositionCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java)
* [DES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/DES.java)
+ * [ECC](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ECC.java)
* [HillCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/HillCipher.java)
* [PlayfairCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
* [Polybius](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Polybius.java)
@@ -275,6 +276,7 @@
* [ShortestCommonSupersequenceLength](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLength.java)
* [SubsetCount](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java)
* [SubsetSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java)
+ * [SubsetSumSpaceOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java)
* [SumOfSubset](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java)
* [Tribonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Tribonacci.java)
* [UniquePaths](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java)
@@ -396,6 +398,7 @@
* [SecondMinMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SecondMinMax.java)
* [SieveOfEratosthenes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java)
* [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SimpsonIntegration.java)
+ * [SolovayStrassenPrimalityTest](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java)
* [SquareFreeInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareFreeInteger.java)
* [SquareRootWithBabylonianMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java)
* [SquareRootWithNewtonRaphsonMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java)
@@ -511,6 +514,7 @@
* [PerfectBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java)
* [QuickSelect](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/QuickSelect.java)
* [RabinKarpAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java)
+ * [RandomSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RandomSearch.java)
* [RecursiveBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java)
* [RowColumnWiseSorted2dArrayBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java)
* [SaddlebackSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java)
@@ -664,12 +668,13 @@
* [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
* [AESEncryptionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java)
* [AffineCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java)
- * [AtbashTest](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AtbashTest.java)
+ * [AtbashTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AtbashTest.java)
* [AutokeyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AutokeyTest.java)
* [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
* [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
* [ColumnarTranspositionCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java)
* [DESTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DESTest.java)
+ * [ECCTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/ECCTest.java)
* [HillCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java)
* [PlayfairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java)
* [PolybiusTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PolybiusTest.java)
@@ -829,6 +834,7 @@
* [RodCuttingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java)
* [ShortestCommonSupersequenceLengthTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLengthTest.java)
* [SubsetCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetCountTest.java)
+ * [SubsetSumSpaceOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java)
* [SubsetSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumTest.java)
* [SumOfSubsetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SumOfSubsetTest.java)
* [TribonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/TribonacciTest.java)
@@ -935,6 +941,7 @@
* [ReverseNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ReverseNumberTest.java)
* [SecondMinMaxTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java)
* [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java)
+ * [SolovayStrassenPrimalityTestTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java)
* [SquareFreeIntegerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java)
* [SquareRootwithBabylonianMethodTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareRootwithBabylonianMethodTest.java)
* [SquareRootWithNewtonRaphsonTestMethod](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java)
@@ -1018,6 +1025,7 @@
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
* [QuickSelectTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/QuickSelectTest.java)
* [RabinKarpAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java)
+ * [RandomSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RandomSearchTest.java)
* [RecursiveBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java)
* [RowColumnWiseSorted2dArrayBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java)
* [SaddlebackSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/RandomSearch.java b/src/main/java/com/thealgorithms/searches/RandomSearch.java
new file mode 100644
index 000000000000..3417ff7ddb21
--- /dev/null
+++ b/src/main/java/com/thealgorithms/searches/RandomSearch.java
@@ -0,0 +1,45 @@
+package com.thealgorithms.searches;
+
+import com.thealgorithms.devutils.searches.SearchAlgorithm;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+
+/**
+ * A Random Search algorithm that randomly selects an index and checks if the
+ * value at that index matches the target. It repeats the process until it
+ * finds the target or checks all elements.
+ *
+ *
+ * Time Complexity: O(n) in the worst case.
+ *
+ *
+ * @author Hardvan
+ */
+public class RandomSearch implements SearchAlgorithm {
+
+ private final Random random = new Random();
+
+ /**
+ * Finds the index of a given element using random search.
+ *
+ * @param array Array to search through
+ * @param key Element to search for
+ * @return Index of the element if found, -1 otherwise
+ */
+ @Override
+ public > int find(T[] array, T key) {
+ Set visitedIndices = new HashSet<>();
+ int size = array.length;
+
+ while (visitedIndices.size() < size) {
+ int randomIndex = random.nextInt(size);
+ if (array[randomIndex].compareTo(key) == 0) {
+ return randomIndex;
+ }
+ visitedIndices.add(randomIndex);
+ }
+
+ return -1;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/searches/RandomSearchTest.java b/src/test/java/com/thealgorithms/searches/RandomSearchTest.java
new file mode 100644
index 000000000000..0a1dbeafd888
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/RandomSearchTest.java
@@ -0,0 +1,87 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class RandomSearchTest {
+
+ private RandomSearch randomSearch;
+
+ @BeforeEach
+ void setUp() {
+ randomSearch = new RandomSearch();
+ }
+
+ @Test
+ void testElementFound() {
+ Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 5;
+ int index = randomSearch.find(array, key);
+
+ assertNotEquals(-1, index, "Element should be found in the array.");
+ assertEquals(key, array[index], "Element found should match the key.");
+ }
+
+ @Test
+ void testElementNotFound() {
+ Integer[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer key = 11;
+ int index = randomSearch.find(array, key);
+
+ assertEquals(-1, index, "Element not present in the array should return -1.");
+ }
+
+ @Test
+ void testEmptyArray() {
+ Integer[] emptyArray = {};
+ Integer key = 5;
+ int index = randomSearch.find(emptyArray, key);
+
+ assertEquals(-1, index, "Searching in an empty array should return -1.");
+ }
+
+ @Test
+ void testSingleElementArrayFound() {
+ Integer[] array = {5};
+ Integer key = 5;
+ int index = randomSearch.find(array, key);
+
+ assertEquals(0, index, "The key should be found at index 0 in a single-element array.");
+ }
+
+ @Test
+ void testSingleElementArrayNotFound() {
+ Integer[] array = {1};
+ Integer key = 5;
+ int index = randomSearch.find(array, key);
+
+ assertEquals(-1, index, "The key should not be found in a single-element array if it does not match.");
+ }
+
+ @Test
+ void testDuplicateElementsFound() {
+ Integer[] array = {1, 2, 3, 4, 5, 5, 5, 7, 8, 9, 10};
+ Integer key = 5;
+ int index = randomSearch.find(array, key);
+
+ assertNotEquals(-1, index, "The key should be found in the array with duplicates.");
+ assertEquals(key, array[index], "The key found should be 5.");
+ }
+
+ @Test
+ void testLargeArray() {
+ Integer[] largeArray = new Integer[1000];
+ for (int i = 0; i < largeArray.length; i++) {
+ largeArray[i] = i + 1; // Fill with values 1 to 1000
+ }
+
+ Integer key = 500;
+ int index = randomSearch.find(largeArray, key);
+
+ assertNotEquals(-1, index, "The key should be found in the large array.");
+ assertEquals(key, largeArray[index], "The key found should match 500.");
+ }
+}
From 1c978c52f1252fdaea68e01cb056ffb396589190 Mon Sep 17 00:00:00 2001
From: Saahil Mahato <115351000+saahil-mahato@users.noreply.github.com>
Date: Fri, 11 Oct 2024 19:58:51 +0545
Subject: [PATCH 063/348] feat: add karatsuba multiplication (#5719)
* feat: add karatsuba multiplication
* fix: fallback size
* fix: big integer instances
---------
Co-authored-by: Alex Klymenko
---
.../maths/KaratsubaMultiplication.java | 93 +++++++++++++++++++
.../maths/KaratsubaMultiplicationTest.java | 58 ++++++++++++
2 files changed, 151 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java
create mode 100644 src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java
diff --git a/src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java b/src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java
new file mode 100644
index 000000000000..298fcb7e85f8
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java
@@ -0,0 +1,93 @@
+package com.thealgorithms.maths;
+
+import java.math.BigInteger;
+
+/**
+ * This class provides an implementation of the Karatsuba multiplication algorithm.
+ *
+ *
+ * Karatsuba multiplication is a divide-and-conquer algorithm for multiplying two large
+ * numbers. It is faster than the classical multiplication algorithm and reduces the
+ * time complexity to O(n^1.585) by breaking the multiplication of two n-digit numbers
+ * into three multiplications of n/2-digit numbers.
+ *
+ *
+ *
+ * The main idea of the Karatsuba algorithm is based on the following observation:
+ *
+ *
+ *
+ * Let x and y be two numbers:
+ * x = a * 10^m + b
+ * y = c * 10^m + d
+ *
+ * Then, the product of x and y can be expressed as:
+ * x * y = (a * c) * 10^(2*m) + ((a * d) + (b * c)) * 10^m + (b * d)
+ *
+ *
+ * The Karatsuba algorithm calculates this more efficiently by reducing the number of
+ * multiplications from four to three by using the identity:
+ *
+ *
+ * (a + b)(c + d) = ac + ad + bc + bd
+ *
+ *
+ *
+ * The recursion continues until the numbers are small enough to multiply directly using
+ * the traditional method.
+ *
+ */
+public final class KaratsubaMultiplication {
+
+ /**
+ * Private constructor to hide the implicit public constructor
+ */
+ private KaratsubaMultiplication() {
+ }
+
+ /**
+ * Multiplies two large numbers using the Karatsuba algorithm.
+ *
+ *
+ * This method recursively splits the numbers into smaller parts until they are
+ * small enough to be multiplied directly using the traditional method.
+ *
+ *
+ * @param x The first large number to be multiplied (BigInteger).
+ * @param y The second large number to be multiplied (BigInteger).
+ * @return The product of the two numbers (BigInteger).
+ */
+ public static BigInteger karatsuba(BigInteger x, BigInteger y) {
+ // Base case: when numbers are small enough, use direct multiplication
+ // If the number is 4 bits or smaller, switch to the classical method
+ if (x.bitLength() <= 4 || y.bitLength() <= 4) {
+ return x.multiply(y);
+ }
+
+ // Find the maximum bit length of the two numbers
+ int n = Math.max(x.bitLength(), y.bitLength());
+
+ // Split the numbers in the middle
+ int m = n / 2;
+
+ // High and low parts of the first number x (x = a * 10^m + b)
+ BigInteger high1 = x.shiftRight(m); // a = x / 2^m (higher part)
+ BigInteger low1 = x.subtract(high1.shiftLeft(m)); // b = x - a * 2^m (lower part)
+
+ // High and low parts of the second number y (y = c * 10^m + d)
+ BigInteger high2 = y.shiftRight(m); // c = y / 2^m (higher part)
+ BigInteger low2 = y.subtract(high2.shiftLeft(m)); // d = y - c * 2^m (lower part)
+
+ // Recursively calculate three products
+ BigInteger z0 = karatsuba(low1, low2); // z0 = b * d (low1 * low2)
+ BigInteger z1 = karatsuba(low1.add(high1), low2.add(high2)); // z1 = (a + b) * (c + d)
+ BigInteger z2 = karatsuba(high1, high2); // z2 = a * c (high1 * high2)
+
+ // Combine the results using Karatsuba's formula
+ // z0 + ((z1 - z2 - z0) << m) + (z2 << 2m)
+ return z2
+ .shiftLeft(2 * m) // z2 * 10^(2*m)
+ .add(z1.subtract(z2).subtract(z0).shiftLeft(m)) // (z1 - z2 - z0) * 10^m
+ .add(z0); // z0
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java b/src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java
new file mode 100644
index 000000000000..e184d998724a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.math.BigInteger;
+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;
+
+/**
+ * Unit test class for {@link KaratsubaMultiplication} class.
+ *
+ *
+ * This class tests various edge cases and normal cases for the
+ * Karatsuba multiplication algorithm implemented in the KaratsubaMultiplication class.
+ * It uses parameterized tests to handle multiple test cases.
+ *
+ */
+class KaratsubaMultiplicationTest {
+
+ /**
+ * Provides test data for the parameterized test.
+ * Each entry in the stream contains three elements: x, y, and the expected result.
+ *
+ * @return a stream of arguments for the parameterized test
+ */
+ static Stream provideTestCases() {
+ return Stream.of(
+ // Test case 1: Two small numbers
+ Arguments.of(new BigInteger("1234"), new BigInteger("5678"), new BigInteger("7006652")),
+ // Test case 2: Two large numbers
+ Arguments.of(new BigInteger("342364"), new BigInteger("393958"), new BigInteger("134877036712")),
+ // Test case 3: One number is zero
+ Arguments.of(BigInteger.ZERO, new BigInteger("5678"), BigInteger.ZERO),
+ // Test case 4: Both numbers are zero
+ Arguments.of(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO),
+ // Test case 5: Single-digit numbers
+ Arguments.of(new BigInteger("9"), new BigInteger("8"), new BigInteger("72")));
+ }
+
+ /**
+ * Parameterized test for Karatsuba multiplication.
+ *
+ *
+ * This method runs the Karatsuba multiplication algorithm for multiple test cases.
+ *
+ *
+ * @param x the first number to multiply
+ * @param y the second number to multiply
+ * @param expected the expected result of x * y
+ */
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testKaratsubaMultiplication(BigInteger x, BigInteger y, BigInteger expected) {
+ assertEquals(expected, KaratsubaMultiplication.karatsuba(x, y));
+ }
+}
From 2a167f4bc333a4ba8e4b96e561e37b9665c1a896 Mon Sep 17 00:00:00 2001
From: Giulio Tantaro
Date: Fri, 11 Oct 2024 21:21:13 +0200
Subject: [PATCH 064/348] Add tests Sudoku (#5722)
* Add tests Sudoku
* Fix
* Update file
---------
Co-authored-by: Giulio Tantaro
Co-authored-by: Alex Klymenko
---
.../com/thealgorithms/others/SudokuTest.java | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 src/test/java/com/thealgorithms/others/SudokuTest.java
diff --git a/src/test/java/com/thealgorithms/others/SudokuTest.java b/src/test/java/com/thealgorithms/others/SudokuTest.java
new file mode 100644
index 000000000000..5018b2768302
--- /dev/null
+++ b/src/test/java/com/thealgorithms/others/SudokuTest.java
@@ -0,0 +1,38 @@
+package com.thealgorithms.others;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class SudokuTest {
+
+ @Test
+ void testIsSafe2() {
+ int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}};
+
+ assertFalse(Sudoku.isSafe(board, 0, 1, 3));
+ assertTrue(Sudoku.isSafe(board, 1, 2, 1));
+ assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, 10, 10, 5); });
+ assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.isSafe(board, -1, 0, 5); });
+ }
+
+ @Test
+ void testSolveSudoku() {
+ int[][] board = {{3, 0, 6, 5, 0, 8, 4, 0, 0}, {5, 2, 0, 0, 0, 0, 0, 0, 0}, {0, 8, 7, 0, 0, 0, 0, 3, 1}, {0, 0, 3, 0, 1, 0, 0, 8, 0}, {9, 0, 0, 8, 6, 3, 0, 0, 5}, {0, 5, 0, 0, 9, 0, 6, 0, 0}, {1, 3, 0, 0, 0, 0, 2, 5, 0}, {0, 0, 0, 0, 0, 0, 0, 7, 4}, {0, 0, 5, 2, 0, 6, 3, 0, 0}};
+
+ assertTrue(Sudoku.solveSudoku(board, board.length));
+ assertEquals(1, board[0][1]);
+ assertThrows(ArrayIndexOutOfBoundsException.class, () -> { Sudoku.solveSudoku(board, 10); });
+ assertTrue(Sudoku.solveSudoku(board, -1));
+ }
+
+ @Test
+ void testUnsolvableSudoku() {
+ int[][] unsolvableBoard = {{5, 1, 6, 8, 4, 9, 7, 3, 2}, {3, 0, 7, 6, 0, 5, 0, 0, 0}, {8, 0, 9, 7, 0, 0, 0, 6, 5}, {1, 3, 5, 0, 6, 0, 9, 0, 7}, {4, 7, 2, 5, 9, 1, 0, 0, 6}, {9, 6, 8, 3, 7, 0, 0, 5, 0}, {2, 5, 3, 1, 8, 6, 0, 7, 4}, {6, 8, 4, 2, 5, 7, 3, 9, 0}, {7, 9, 1, 4, 3, 0, 5, 0, 0}};
+
+ assertFalse(Sudoku.solveSudoku(unsolvableBoard, unsolvableBoard.length));
+ }
+}
From 966b4e369dc5a8097e3ee0ff16b5fdd91c187d8a Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:30:12 +0530
Subject: [PATCH 065/348] feat: Add ClearLeftmostSetBit new algorithm with
Junit tests (#5702)
---
DIRECTORY.md | 5 +++
.../bitmanipulation/ClearLeftmostSetBit.java | 39 +++++++++++++++++++
.../ClearLeftmostSetBitTest.java | 16 ++++++++
3 files changed, 60 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index d0f50b421297..51af99583ed7 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -24,6 +24,7 @@
* [WordSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordSearch.java)
* bitmanipulation
* [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
+ * [ClearLeftmostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java)
* [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
* [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
* [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
@@ -355,6 +356,7 @@
* [JosephusProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/JosephusProblem.java)
* [JugglerSequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/JugglerSequence.java)
* [KaprekarNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KaprekarNumbers.java)
+ * [KaratsubaMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java)
* [KeithNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KeithNumber.java)
* [KrishnamurthyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KrishnamurthyNumber.java)
* [LeastCommonMultiple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeastCommonMultiple.java)
@@ -646,6 +648,7 @@
* [WordSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordSearchTest.java)
* bitmanipulation
* [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
+ * [ClearLeftmostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java)
* [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
* [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
* [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
@@ -905,6 +908,7 @@
* [HeronsFormulaTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java)
* [JosephusProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/JosephusProblemTest.java)
* [KaprekarNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java)
+ * [KaratsubaMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java)
* [LeastCommonMultipleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeastCommonMultipleTest.java)
* [LeonardoNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeonardoNumberTest.java)
* [LiouvilleLambdaFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java)
@@ -989,6 +993,7 @@
* [RemoveDuplicateFromStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/RemoveDuplicateFromStringTest.java)
* [ReverseStackUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ReverseStackUsingRecursionTest.java)
* [SkylineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SkylineProblemTest.java)
+ * [SudokuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SudokuTest.java)
* [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java)
* [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java)
* [WorstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/WorstFitCPUTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
new file mode 100644
index 000000000000..3e9a4a21183f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * ClearLeftmostSetBit class contains a method to clear the leftmost set bit of a number.
+ * The leftmost set bit is the leftmost bit that is set to 1 in the binary representation of a number.
+ *
+ * Example:
+ * 26 (11010) -> 10 (01010)
+ * 1 (1) -> 0 (0)
+ * 7 (111) -> 3 (011)
+ * 6 (0110) -> 2 (0010)
+ *
+ * @author Hardvan
+ */
+public final class ClearLeftmostSetBit {
+ private ClearLeftmostSetBit() {
+ }
+
+ /**
+ * Clears the leftmost set bit (1) of a given number.
+ * Step 1: Find the position of the leftmost set bit
+ * Step 2: Create a mask with all bits set except for the leftmost set bit
+ * Step 3: Clear the leftmost set bit using AND with the mask
+ *
+ * @param num The input number.
+ * @return The number after clearing the leftmost set bit.
+ */
+ public static int clearLeftmostSetBit(int num) {
+ int pos = 0;
+ int temp = num;
+ while (temp > 0) {
+ temp >>= 1;
+ pos++;
+ }
+
+ int mask = ~(1 << (pos - 1));
+ return num & mask;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java b/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java
new file mode 100644
index 000000000000..e77889fb7b0a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java
@@ -0,0 +1,16 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class ClearLeftmostSetBitTest {
+
+ @Test
+ public void testClearLeftmostSetBit() {
+ assertEquals(10, ClearLeftmostSetBit.clearLeftmostSetBit(26)); // 11010 -> 01010
+ assertEquals(0, ClearLeftmostSetBit.clearLeftmostSetBit(1)); // 1 -> 0
+ assertEquals(3, ClearLeftmostSetBit.clearLeftmostSetBit(7)); // 111 -> 011
+ assertEquals(2, ClearLeftmostSetBit.clearLeftmostSetBit(6)); // 0110 -> 0010
+ }
+}
From b8633ad14c3b7f638d9f71a19713b9bcdef699ad Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:49:55 +0530
Subject: [PATCH 066/348] feat: Add `countLeadingZeros` new algorithm with
Junit tests (#5703)
---
DIRECTORY.md | 2 +
.../bitmanipulation/CountLeadingZeros.java | 39 +++++++++++++++++++
.../CountLeadingZerosTest.java | 16 ++++++++
3 files changed, 57 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 51af99583ed7..1ecacc3c395e 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -25,6 +25,7 @@
* bitmanipulation
* [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
* [ClearLeftmostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java)
+ * [CountLeadingZeros](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java)
* [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
* [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
* [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
@@ -649,6 +650,7 @@
* bitmanipulation
* [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
* [ClearLeftmostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java)
+ * [CountLeadingZerosTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java)
* [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
* [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
* [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
new file mode 100644
index 000000000000..318334f0b951
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * CountLeadingZeros class contains a method to count the number of leading zeros in the binary representation of a number.
+ * The number of leading zeros is the number of zeros before the leftmost 1 bit.
+ * For example, the number 5 has 29 leading zeros in its 32-bit binary representation.
+ * The number 0 has 32 leading zeros.
+ * The number 1 has 31 leading zeros.
+ * The number -1 has no leading zeros.
+ *
+ * @author Hardvan
+ */
+public final class CountLeadingZeros {
+ private CountLeadingZeros() {
+ }
+
+ /**
+ * Counts the number of leading zeros in the binary representation of a number.
+ * Method: Keep shifting the mask to the right until the leftmost bit is 1.
+ * The number of shifts is the number of leading zeros.
+ *
+ * @param num The input number.
+ * @return The number of leading zeros.
+ */
+ public static int countLeadingZeros(int num) {
+ if (num == 0) {
+ return 32;
+ }
+
+ int count = 0;
+ int mask = 1 << 31;
+ while ((mask & num) == 0) {
+ count++;
+ mask >>>= 1;
+ }
+
+ return count;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java b/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java
new file mode 100644
index 000000000000..6ab15fd2ab5a
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java
@@ -0,0 +1,16 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class CountLeadingZerosTest {
+
+ @Test
+ public void testCountLeadingZeros() {
+ assertEquals(29, CountLeadingZeros.countLeadingZeros(5)); // 000...0101 has 29 leading zeros
+ assertEquals(32, CountLeadingZeros.countLeadingZeros(0)); // 000...0000 has 32 leading zeros
+ assertEquals(31, CountLeadingZeros.countLeadingZeros(1)); // 000...0001 has 31 leading zeros
+ assertEquals(0, CountLeadingZeros.countLeadingZeros(-1)); // No leading zeros in negative number (-1)
+ }
+}
From c0ffbb0e45f89c7d29c1955add9af81599c6530e Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 11:56:04 +0530
Subject: [PATCH 067/348] Add `GrayCodeConversion` algorithm (#5705)
---
DIRECTORY.md | 2 +
.../bitmanipulation/GrayCodeConversion.java | 44 +++++++++++++++++++
.../GrayCodeConversionTest.java | 29 ++++++++++++
3 files changed, 75 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 1ecacc3c395e..ebbb8ddc3110 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -27,6 +27,7 @@
* [ClearLeftmostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java)
* [CountLeadingZeros](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java)
* [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
+ * [GrayCodeConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java)
* [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
* [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
* [IsEven](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java)
@@ -652,6 +653,7 @@
* [ClearLeftmostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java)
* [CountLeadingZerosTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java)
* [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
+ * [GrayCodeConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java)
* [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
* [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
* [IsEvenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
new file mode 100644
index 000000000000..83cd30c7d50a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Gray code is a binary numeral system where two successive values differ in only one bit.
+ * This is a simple conversion between binary and Gray code.
+ * Example:
+ * 7 -> 0111 -> 0100 -> 4
+ * 4 -> 0100 -> 0111 -> 7
+ * 0 -> 0000 -> 0000 -> 0
+ * 1 -> 0001 -> 0000 -> 0
+ * 2 -> 0010 -> 0011 -> 3
+ * 3 -> 0011 -> 0010 -> 2
+ *
+ * @author Hardvan
+ */
+public final class GrayCodeConversion {
+ private GrayCodeConversion() {
+ }
+
+ /**
+ * Converts a binary number to Gray code.
+ *
+ * @param num The binary number.
+ * @return The corresponding Gray code.
+ */
+ public static int binaryToGray(int num) {
+ return num ^ (num >> 1);
+ }
+
+ /**
+ * Converts a Gray code number back to binary.
+ *
+ * @param gray The Gray code number.
+ * @return The corresponding binary number.
+ */
+ public static int grayToBinary(int gray) {
+ int binary = gray;
+ while (gray > 0) {
+ gray >>= 1;
+ binary ^= gray;
+ }
+ return binary;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java b/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java
new file mode 100644
index 000000000000..1fe792028dca
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class GrayCodeConversionTest {
+
+ @Test
+ public void testBinaryToGray() {
+ assertEquals(7, GrayCodeConversion.binaryToGray(5)); // 101 -> 111
+ assertEquals(4, GrayCodeConversion.binaryToGray(7)); // 111 -> 100
+ assertEquals(1, GrayCodeConversion.binaryToGray(1)); // 001 -> 001
+ }
+
+ @Test
+ public void testGrayToBinary() {
+ assertEquals(5, GrayCodeConversion.grayToBinary(7)); // 111 -> 101
+ assertEquals(4, GrayCodeConversion.grayToBinary(6)); // 110 -> 100
+ assertEquals(1, GrayCodeConversion.grayToBinary(1)); // 001 -> 001
+ }
+
+ @Test
+ public void testBinaryGrayCycle() {
+ int binary = 9; // 1001 in binary
+ int gray = GrayCodeConversion.binaryToGray(binary);
+ assertEquals(binary, GrayCodeConversion.grayToBinary(gray)); // Should return to original binary
+ }
+}
From bf0377f44b737f090aea99fd350dbf982a279884 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:01:04 +0530
Subject: [PATCH 068/348] Add `HammingDistance` algorithm (#5706)
---
DIRECTORY.md | 2 ++
.../bitmanipulation/HammingDistance.java | 29 +++++++++++++++++++
.../bitmanipulation/HammingDistanceTest.java | 17 +++++++++++
3 files changed, 48 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index ebbb8ddc3110..3692b436a353 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -28,6 +28,7 @@
* [CountLeadingZeros](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java)
* [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
* [GrayCodeConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java)
+ * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java)
* [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
* [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
* [IsEven](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java)
@@ -654,6 +655,7 @@
* [CountLeadingZerosTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java)
* [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
* [GrayCodeConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java)
+ * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java)
* [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
* [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
* [IsEvenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
new file mode 100644
index 000000000000..4c24909ef234
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
@@ -0,0 +1,29 @@
+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/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java b/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
new file mode 100644
index 000000000000..bde39a69f190
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java
@@ -0,0 +1,17 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class HammingDistanceTest {
+
+ @Test
+ public void testHammingDistance() {
+ assertEquals(3, HammingDistance.hammingDistance(9, 14)); // 1001 vs 1110, Hamming distance is 3
+ assertEquals(0, HammingDistance.hammingDistance(10, 10)); // Same number, Hamming distance is 0
+ assertEquals(1, HammingDistance.hammingDistance(1, 0)); // 0001 vs 0000, Hamming distance is 1
+ assertEquals(2, HammingDistance.hammingDistance(4, 1)); // 100 vs 001, Hamming distance is 2
+ assertEquals(4, HammingDistance.hammingDistance(0, 15)); // 0000 vs 1111, Hamming distance is 4
+ }
+}
From 4d6dd13b569082d348f19ec4b24a264f7fa2abb8 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:06:29 +0530
Subject: [PATCH 069/348] Add `BinaryPalindromeCheck` algorithm (#5708)
---
DIRECTORY.md | 2 +
.../BinaryPalindromeCheck.java | 43 +++++++++++++++++++
.../BinaryPalindromeCheckTest.java | 18 ++++++++
3 files changed, 63 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 3692b436a353..b62cde038651 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -23,6 +23,7 @@
* [WordPatternMatcher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java)
* [WordSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordSearch.java)
* bitmanipulation
+ * [BinaryPalindromeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java)
* [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java)
* [ClearLeftmostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java)
* [CountLeadingZeros](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java)
@@ -650,6 +651,7 @@
* [WordPatternMatcherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java)
* [WordSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordSearchTest.java)
* bitmanipulation
+ * [BinaryPalindromeCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java)
* [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java)
* [ClearLeftmostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java)
* [CountLeadingZerosTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
new file mode 100644
index 000000000000..0d6fd140c720
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
@@ -0,0 +1,43 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class contains a method to check if the binary representation of a number is a palindrome.
+ *
+ * A binary palindrome is a number whose binary representation is the same when read from left to right and right to left.
+ * For example, the number 9 has a binary representation of 1001, which is a palindrome.
+ * The number 10 has a binary representation of 1010, which is not a palindrome.
+ *
+ *
+ * @author Hardvan
+ */
+public final class BinaryPalindromeCheck {
+ private BinaryPalindromeCheck() {
+ }
+
+ /**
+ * Checks if the binary representation of a number is a palindrome.
+ *
+ * @param x The number to check.
+ * @return True if the binary representation is a palindrome, otherwise false.
+ */
+ public static boolean isBinaryPalindrome(int x) {
+ int reversed = reverseBits(x);
+ return x == reversed;
+ }
+
+ /**
+ * Helper function to reverse all the bits of an integer.
+ *
+ * @param x The number to reverse the bits of.
+ * @return The number with reversed bits.
+ */
+ private static int reverseBits(int x) {
+ int result = 0;
+ while (x > 0) {
+ result <<= 1;
+ result |= (x & 1);
+ x >>= 1;
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java b/src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java
new file mode 100644
index 000000000000..ff41344266e4
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java
@@ -0,0 +1,18 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class BinaryPalindromeCheckTest {
+
+ @Test
+ public void testIsBinaryPalindrome() {
+ assertTrue(BinaryPalindromeCheck.isBinaryPalindrome(9)); // 1001 is a palindrome
+ assertFalse(BinaryPalindromeCheck.isBinaryPalindrome(10)); // 1010 is not a palindrome
+ assertTrue(BinaryPalindromeCheck.isBinaryPalindrome(0)); // 0 is a palindrome
+ assertTrue(BinaryPalindromeCheck.isBinaryPalindrome(1)); // 1 is a palindrome
+ assertFalse(BinaryPalindromeCheck.isBinaryPalindrome(12)); // 1100 is not a palindrome
+ }
+}
From eba6823c3ad8f81fac5ae1f4cc3de217063fd606 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:15:28 +0530
Subject: [PATCH 070/348] Add `HigherLowerPowerOfTwo` algorithm (#5707)
---
DIRECTORY.md | 2 +
.../HigherLowerPowerOfTwo.java | 54 +++++++++++++++++++
.../HigherLowerPowerOfTwoTest.java | 26 +++++++++
3 files changed, 82 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index b62cde038651..880a5f12bdcc 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -30,6 +30,7 @@
* [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java)
* [GrayCodeConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java)
* [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java)
+ * [HigherLowerPowerOfTwo](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java)
* [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java)
* [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java)
* [IsEven](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java)
@@ -658,6 +659,7 @@
* [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java)
* [GrayCodeConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java)
* [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java)
+ * [HigherLowerPowerOfTwoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java)
* [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java)
* [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java)
* [IsEvenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
new file mode 100644
index 000000000000..0fb058b2b8a3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * HigherLowerPowerOfTwo class has two methods to find the next higher and lower power of two.
+ *
+ * nextHigherPowerOfTwo method finds the next higher power of two.
+ * nextLowerPowerOfTwo method finds the next lower power of two.
+ * Both methods take an integer as input and return the next higher or lower power of two.
+ * If the input is less than 1, the next higher power of two is 1.
+ * If the input is less than or equal to 1, the next lower power of two is 0.
+ * nextHigherPowerOfTwo method uses bitwise operations to find the next higher power of two.
+ * nextLowerPowerOfTwo method uses Integer.highestOneBit method to find the next lower power of two.
+ * The time complexity of both methods is O(1).
+ * The space complexity of both methods is O(1).
+ *
+ *
+ * @author Hardvan
+ */
+public final class HigherLowerPowerOfTwo {
+ private HigherLowerPowerOfTwo() {
+ }
+
+ /**
+ * Finds the next higher power of two.
+ *
+ * @param x The given number.
+ * @return The next higher power of two.
+ */
+ public static int nextHigherPowerOfTwo(int x) {
+ if (x < 1) {
+ return 1;
+ }
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+
+ /**
+ * Finds the next lower power of two.
+ *
+ * @param x The given number.
+ * @return The next lower power of two.
+ */
+ public static int nextLowerPowerOfTwo(int x) {
+ if (x < 1) {
+ return 0;
+ }
+ return Integer.highestOneBit(x);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java b/src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java
new file mode 100644
index 000000000000..34391002941b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java
@@ -0,0 +1,26 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class HigherLowerPowerOfTwoTest {
+
+ @Test
+ public void testNextHigherPowerOfTwo() {
+ assertEquals(32, HigherLowerPowerOfTwo.nextHigherPowerOfTwo(19)); // next higher power of two is 32
+ assertEquals(1, HigherLowerPowerOfTwo.nextHigherPowerOfTwo(1)); // next higher power of two is 1
+ assertEquals(16, HigherLowerPowerOfTwo.nextHigherPowerOfTwo(15)); // next higher power of two is 16
+ assertEquals(8, HigherLowerPowerOfTwo.nextHigherPowerOfTwo(8)); // next higher power of two is 8
+ assertEquals(16, HigherLowerPowerOfTwo.nextHigherPowerOfTwo(9)); // next higher power of two is 16
+ }
+
+ @Test
+ public void testNextLowerPowerOfTwo() {
+ assertEquals(16, HigherLowerPowerOfTwo.nextLowerPowerOfTwo(19)); // next lower power of two is 16
+ assertEquals(1, HigherLowerPowerOfTwo.nextLowerPowerOfTwo(1)); // next lower power of two is 1
+ assertEquals(8, HigherLowerPowerOfTwo.nextLowerPowerOfTwo(9)); // next lower power of two is 8
+ assertEquals(8, HigherLowerPowerOfTwo.nextLowerPowerOfTwo(15)); // next lower power of two is 8
+ assertEquals(8, HigherLowerPowerOfTwo.nextLowerPowerOfTwo(8)); // next lower power of two is 8
+ }
+}
From 138793df1d2681a554204c6fc2190348632567ec Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:21:41 +0530
Subject: [PATCH 071/348] =?UTF-8?q?Improve=20docs,=20remove=20`main`,=20ad?=
=?UTF-8?q?d=20tests=20for=20`MatrixChainRecursiveTopDo=E2=80=A6=20(#5659)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
DIRECTORY.md | 1 +
...atrixChainRecursiveTopDownMemoisation.java | 46 +++++++++----
...xChainRecursiveTopDownMemoisationTest.java | 68 +++++++++++++++++++
3 files changed, 102 insertions(+), 13 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 880a5f12bdcc..751141eb8d1c 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -836,6 +836,7 @@
* [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java)
* [LongestValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java)
* [MatrixChainMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java)
+ * [MatrixChainRecursiveTopDownMemoisationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java)
* [MaximumSumOfNonAdjacentElementsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java)
* [MinimumPathSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java)
* [MinimumSumPartitionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java b/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java
index 6c1c4cf54ffc..0c1031c6805c 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java
@@ -1,15 +1,31 @@
package com.thealgorithms.dynamicprogramming;
-// Matrix-chain Multiplication
-// Problem Statement
-// we have given a chain A1,A2,...,Ani of n matrices, where for i = 1,2,...,n,
-// matrix Ai has dimension pi−1 ×pi
-// , fully parenthesize the product A1A2 ···An in a way that
-// minimizes the number of scalar multiplications.
+/**
+ * The MatrixChainRecursiveTopDownMemoisation class implements the matrix-chain
+ * multiplication problem using a top-down recursive approach with memoization.
+ *
+ *
Given a chain of matrices A1, A2, ..., An, where matrix Ai has dimensions
+ * pi-1 × pi, this algorithm finds the optimal way to fully parenthesize the
+ * product A1A2...An in a way that minimizes the total number of scalar
+ * multiplications required.
+ *
+ *
This implementation uses a memoization technique to store the results of
+ * subproblems, which significantly reduces the number of recursive calls and
+ * improves performance compared to a naive recursive approach.
+ */
public final class MatrixChainRecursiveTopDownMemoisation {
private MatrixChainRecursiveTopDownMemoisation() {
}
+ /**
+ * Calculates the minimum number of scalar multiplications needed to multiply
+ * a chain of matrices.
+ *
+ * @param p an array of integers representing the dimensions of the matrices.
+ * The length of the array is n + 1, where n is the number of matrices.
+ * @return the minimum number of multiplications required to multiply the chain
+ * of matrices.
+ */
static int memoizedMatrixChain(int[] p) {
int n = p.length;
int[][] m = new int[n][n];
@@ -21,6 +37,17 @@ static int memoizedMatrixChain(int[] p) {
return lookupChain(m, p, 1, n - 1);
}
+ /**
+ * A recursive helper method to lookup the minimum number of multiplications
+ * for multiplying matrices from index i to index j.
+ *
+ * @param m the memoization table storing the results of subproblems.
+ * @param p an array of integers representing the dimensions of the matrices.
+ * @param i the starting index of the matrix chain.
+ * @param j the ending index of the matrix chain.
+ * @return the minimum number of multiplications needed to multiply matrices
+ * from i to j.
+ */
static int lookupChain(int[][] m, int[] p, int i, int j) {
if (i == j) {
m[i][j] = 0;
@@ -38,11 +65,4 @@ static int lookupChain(int[][] m, int[] p, int i, int j) {
}
return m[i][j];
}
-
- // in this code we are taking the example of 4 matrixes whose orders are 1x2,2x3,3x4,4x5
- // respectively output should be Minimum number of multiplications is 38
- public static void main(String[] args) {
- int[] arr = {1, 2, 3, 4, 5};
- System.out.println("Minimum number of multiplications is " + memoizedMatrixChain(arr));
- }
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java
new file mode 100644
index 000000000000..f8270f6d50b5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java
@@ -0,0 +1,68 @@
+package com.thealgorithms.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class MatrixChainRecursiveTopDownMemoisationTest {
+
+ /**
+ * Test case for four matrices with dimensions 1x2, 2x3, 3x4, and 4x5.
+ * The expected minimum number of multiplications is 38.
+ */
+ @Test
+ void testFourMatrices() {
+ int[] dimensions = {1, 2, 3, 4, 5};
+ int expected = 38;
+ int actual = MatrixChainRecursiveTopDownMemoisation.memoizedMatrixChain(dimensions);
+ assertEquals(expected, actual, "The minimum number of multiplications should be 38.");
+ }
+
+ /**
+ * Test case for three matrices with dimensions 10x20, 20x30, and 30x40.
+ * The expected minimum number of multiplications is 6000.
+ */
+ @Test
+ void testThreeMatrices() {
+ int[] dimensions = {10, 20, 30, 40};
+ int expected = 18000;
+ int actual = MatrixChainRecursiveTopDownMemoisation.memoizedMatrixChain(dimensions);
+ assertEquals(expected, actual, "The minimum number of multiplications should be 18000.");
+ }
+
+ /**
+ * Test case for two matrices with dimensions 5x10 and 10x20.
+ * The expected minimum number of multiplications is 1000.
+ */
+ @Test
+ void testTwoMatrices() {
+ int[] dimensions = {5, 10, 20};
+ int expected = 1000;
+ int actual = MatrixChainRecursiveTopDownMemoisation.memoizedMatrixChain(dimensions);
+ assertEquals(expected, actual, "The minimum number of multiplications should be 1000.");
+ }
+
+ /**
+ * Test case for a single matrix.
+ * The expected minimum number of multiplications is 0, as there are no multiplications needed.
+ */
+ @Test
+ void testSingleMatrix() {
+ int[] dimensions = {10, 20}; // Single matrix dimensions
+ int expected = 0;
+ int actual = MatrixChainRecursiveTopDownMemoisation.memoizedMatrixChain(dimensions);
+ assertEquals(expected, actual, "The minimum number of multiplications should be 0.");
+ }
+
+ /**
+ * Test case for matrices with varying dimensions.
+ * The expected minimum number of multiplications is calculated based on the dimensions provided.
+ */
+ @Test
+ void testVaryingDimensions() {
+ int[] dimensions = {2, 3, 4, 5, 6}; // Dimensions for 4 matrices
+ int expected = 124; // Expected value needs to be calculated based on the problem
+ int actual = MatrixChainRecursiveTopDownMemoisation.memoizedMatrixChain(dimensions);
+ assertEquals(expected, actual, "The minimum number of multiplications should be 124.");
+ }
+}
From b81671e66d2f87d1d704f550b0387d1436bf8715 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:34:54 +0530
Subject: [PATCH 072/348] Add tests, remove `main` in `LowerBound` (#5672)
---
DIRECTORY.md | 1 +
.../thealgorithms/searches/LowerBound.java | 25 --------
.../searches/LowerBoundTest.java | 59 +++++++++++++++++++
3 files changed, 60 insertions(+), 25 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/searches/LowerBoundTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 751141eb8d1c..dea06ca10f4f 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1036,6 +1036,7 @@
* [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java)
* [LinearSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchTest.java)
* [LinearSearchThreadTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java)
+ * [LowerBoundTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LowerBoundTest.java)
* [MonteCarloTreeSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java)
* [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java)
* [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java)
diff --git a/src/main/java/com/thealgorithms/searches/LowerBound.java b/src/main/java/com/thealgorithms/searches/LowerBound.java
index ee6f51e637f2..5a1401edd3c2 100644
--- a/src/main/java/com/thealgorithms/searches/LowerBound.java
+++ b/src/main/java/com/thealgorithms/searches/LowerBound.java
@@ -1,9 +1,6 @@
package com.thealgorithms.searches;
import com.thealgorithms.devutils.searches.SearchAlgorithm;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.IntStream;
/**
* The LowerBound method is used to return an index pointing to the first
@@ -25,28 +22,6 @@
*/
class LowerBound implements SearchAlgorithm {
- // Driver Program
- public static void main(String[] args) {
- // Just generate data
- Random r = ThreadLocalRandom.current();
-
- int size = 100;
- int maxElement = 100000;
-
- Integer[] integers = IntStream.generate(() -> r.nextInt(maxElement)).limit(size).sorted().boxed().toArray(Integer[] ::new);
-
- // The element for which the lower bound is to be found
- int val = integers[r.nextInt(size - 1)] + 1;
-
- LowerBound search = new LowerBound();
- int atIndex = search.find(integers, val);
-
- System.out.printf("Val: %d. Lower Bound Found %d at index %d. An array length %d%n", val, integers[atIndex], atIndex, size);
-
- boolean toCheck = integers[atIndex] >= val || integers[size - 1] < val;
- System.out.printf("Lower Bound found at an index: %d. Is greater or max element: %b%n", atIndex, toCheck);
- }
-
/**
* @param array is an array where the LowerBound value is to be found
* @param key is an element for which the LowerBound is to be found
diff --git a/src/test/java/com/thealgorithms/searches/LowerBoundTest.java b/src/test/java/com/thealgorithms/searches/LowerBoundTest.java
new file mode 100644
index 000000000000..30f4a5cb257c
--- /dev/null
+++ b/src/test/java/com/thealgorithms/searches/LowerBoundTest.java
@@ -0,0 +1,59 @@
+package com.thealgorithms.searches;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class LowerBoundTest {
+
+ /**
+ * Test finding the lower bound for an element present in the array.
+ */
+ @Test
+ void testLowerBoundElementPresent() {
+ Integer[] array = {1, 2, 3, 4, 5};
+ LowerBound lowerBound = new LowerBound();
+
+ // Test for a value that is present
+ assertEquals(2, lowerBound.find(array, 3), "Lower bound for 3 should be at index 2");
+ assertEquals(0, lowerBound.find(array, 1), "Lower bound for 1 should be at index 0");
+ assertEquals(4, lowerBound.find(array, 5), "Lower bound for 5 should be at index 4");
+ }
+
+ /**
+ * Test finding the lower bound for a value greater than the maximum element in the array.
+ */
+ @Test
+ void testLowerBoundElementGreaterThanMax() {
+ Integer[] array = {1, 2, 3, 4, 5};
+ LowerBound lowerBound = new LowerBound();
+
+ // Test for a value greater than the maximum
+ assertEquals(4, lowerBound.find(array, 6), "Lower bound for 6 should be at index 4");
+ }
+
+ /**
+ * Test finding the lower bound for a value less than the minimum element in the array.
+ */
+ @Test
+ void testLowerBoundElementLessThanMin() {
+ Integer[] array = {1, 2, 3, 4, 5};
+ LowerBound lowerBound = new LowerBound();
+
+ // Test for a value less than the minimum
+ assertEquals(0, lowerBound.find(array, 0), "Lower bound for 0 should be at index 0");
+ }
+
+ /**
+ * Test finding the lower bound for a non-existent value that falls between two elements.
+ */
+ @Test
+ void testLowerBoundNonExistentValue() {
+ Integer[] array = {1, 2, 3, 4, 5};
+ LowerBound lowerBound = new LowerBound();
+
+ // Test for a value that is not present
+ assertEquals(4, lowerBound.find(array, 7), "Lower bound for 7 should be at index 4");
+ assertEquals(0, lowerBound.find(array, 0), "Lower bound for 0 should be at index 0");
+ }
+}
From e38611e9db0fdf318ac8513709f75077c55f25e3 Mon Sep 17 00:00:00 2001
From: PANKAJ PATWAL <120747214+Chiefpatwal@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:41:25 +0530
Subject: [PATCH 073/348] Optimize and Format Knapsack Memoization Algorithm
(#5685)
---
.../dynamicprogramming/KnapsackMemoization.java | 11 +++++------
.../KnapsackMemoizationTest.java | 15 +++++++++++++++
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java
index 396efb1a7893..3501e302a6ef 100644
--- a/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java
+++ b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java
@@ -1,5 +1,7 @@
package com.thealgorithms.dynamicprogramming;
+import java.util.Arrays;
+
/**
* Recursive Solution for 0-1 knapsack with memoization
* This method is basically an extension to the recursive approach so that we
@@ -15,10 +17,8 @@ int knapSack(int capacity, int[] weights, int[] profits, int numOfItems) {
int[][] dpTable = new int[numOfItems + 1][capacity + 1];
// Loop to initially fill the table with -1
- for (int i = 0; i < numOfItems + 1; i++) {
- for (int j = 0; j < capacity + 1; j++) {
- dpTable[i][j] = -1;
- }
+ for (int[] table : dpTable) {
+ Arrays.fill(table, -1);
}
return solveKnapsackRecursive(capacity, weights, profits, numOfItems, dpTable);
@@ -38,7 +38,6 @@ int solveKnapsackRecursive(int capacity, int[] weights, int[] profits, int numOf
if (weights[numOfItems - 1] > capacity) {
// Store the value of function call stack in table
dpTable[numOfItems][capacity] = solveKnapsackRecursive(capacity, weights, profits, numOfItems - 1, dpTable);
- return dpTable[numOfItems][capacity];
} else {
// case 1. include the item, if it is less than the capacity
final int includeCurrentItem = profits[numOfItems - 1] + solveKnapsackRecursive(capacity - weights[numOfItems - 1], weights, profits, numOfItems - 1, dpTable);
@@ -48,7 +47,7 @@ int solveKnapsackRecursive(int capacity, int[] weights, int[] profits, int numOf
// Store the value of function call stack in table and return
dpTable[numOfItems][capacity] = Math.max(includeCurrentItem, excludeCurrentItem);
- return dpTable[numOfItems][capacity];
}
+ return dpTable[numOfItems][capacity];
}
}
diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java
index d220a2bb512e..3545eb2667ed 100644
--- a/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java
+++ b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java
@@ -31,4 +31,19 @@ void test3() {
int capacity = 50;
assertEquals(220, knapsackMemoization.knapSack(capacity, weight, value, weight.length));
}
+
+ @Test
+ void test4() {
+ int[] weight = {1, 2, 3};
+ int[] value = {10, 20, 30};
+ int capacity = 0;
+ assertEquals(0, knapsackMemoization.knapSack(capacity, weight, value, weight.length));
+ }
+ @Test
+ void test5() {
+ int[] weight = {1, 2, 3, 8};
+ int[] value = {10, 20, 30, 40};
+ int capacity = 50;
+ assertEquals(100, knapsackMemoization.knapSack(capacity, weight, value, weight.length));
+ }
}
From e263edcfe04dc70969ff4dcd3f8983a144ca2946 Mon Sep 17 00:00:00 2001
From: Sailok Chinta
Date: Sat, 12 Oct 2024 12:53:41 +0530
Subject: [PATCH 074/348] Add `QuadTree` data structure (#5681)
---
DIRECTORY.md | 1 +
.../datastructures/trees/QuadTree.java | 176 ++++++++++++++++++
.../datastructures/trees/QuadTreeTest.java | 58 ++++++
3 files changed, 235 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index dea06ca10f4f..3dbd1519ff08 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -218,6 +218,7 @@
* [PostOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PostOrderTraversal.java)
* [PreOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PreOrderTraversal.java)
* [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java)
+ * [QuadTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java)
* [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java)
* [SameTreesCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java)
* [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java)
diff --git a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java
new file mode 100644
index 000000000000..e0d255b1e784
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java
@@ -0,0 +1,176 @@
+package com.thealgorithms.datastructures.trees;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Point is a simple class that represents a point in 2D space.
+ *
+ * @see Point
+ * @author Sailok Chinta
+ */
+class Point {
+ public double x;
+ public double y;
+
+ Point(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+/**
+ * BoundingBox is a simple class that represents a bounding box in 2D space.
+ *
+ * @see Bounding Box
+ * @author Sailok Chinta
+ */
+class BoundingBox {
+ public Point center;
+ public double halfWidth;
+
+ BoundingBox(Point center, double halfWidth) {
+ this.center = center;
+ this.halfWidth = halfWidth;
+ }
+
+ /**
+ * Checks if the point is inside the bounding box
+ *
+ * @param point The point to check
+ * @return true if the point is inside the bounding box, false otherwise
+ */
+ public boolean containsPoint(Point point) {
+ return point.x >= center.x - halfWidth && point.x <= center.x + halfWidth && point.y >= center.y - halfWidth && point.y <= center.y + halfWidth;
+ }
+
+ /**
+ * Checks if the bounding box intersects with the other bounding box
+ *
+ * @param otherBoundingBox The other bounding box
+ * @return true if the bounding box intersects with the other bounding box, false otherwise
+ */
+ public boolean intersectsBoundingBox(BoundingBox otherBoundingBox) {
+ return otherBoundingBox.center.x - otherBoundingBox.halfWidth <= center.x + halfWidth && otherBoundingBox.center.x + otherBoundingBox.halfWidth >= center.x - halfWidth && otherBoundingBox.center.y - otherBoundingBox.halfWidth <= center.y + halfWidth
+ && otherBoundingBox.center.y + otherBoundingBox.halfWidth >= center.y - halfWidth;
+ }
+}
+
+/**
+ * QuadTree is a tree data structure that is used to store spatial information
+ * in an efficient way.
+ *
+ * This implementation is specific to Point QuadTrees
+ *
+ * @see Quad Tree
+ * @author Sailok Chinta
+ */
+public class QuadTree {
+ private final BoundingBox boundary;
+ private final int capacity;
+
+ private List pointList;
+ private boolean divided;
+ private QuadTree northWest;
+ private QuadTree northEast;
+ private QuadTree southWest;
+ private QuadTree southEast;
+
+ public QuadTree(BoundingBox boundary, int capacity) {
+ this.boundary = boundary;
+ this.capacity = capacity;
+
+ this.pointList = new ArrayList<>();
+ this.divided = false;
+ this.northWest = null;
+ this.northEast = null;
+ this.southWest = null;
+ this.southEast = null;
+ }
+
+ /**
+ * Inserts a point into the tree
+ *
+ * @param point The point to insert
+ * @return true if the point is successfully inserted, false otherwise
+ */
+ public boolean insert(Point point) {
+ if (point == null) {
+ return false;
+ }
+
+ // Ignore points that don't belong to this quad tree
+ if (!boundary.containsPoint(point)) {
+ return false;
+ }
+
+ // if the space is not already occupied, add it to the list
+ if (pointList.size() < capacity) {
+ pointList.add(point);
+ return true;
+ }
+
+ // if subdivision hasn't happened, divide the tree
+ if (!divided) {
+ subDivide();
+ }
+
+ // try to add the point in one of the four quadrants
+ if (northWest.insert(point)) {
+ return true;
+ }
+
+ if (northEast.insert(point)) {
+ return true;
+ }
+
+ if (southWest.insert(point)) {
+ return true;
+ }
+
+ if (southEast.insert(point)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Create four children that fully divide this quad into four quads of equal area
+ */
+ private void subDivide() {
+ double quadrantHalfWidth = boundary.halfWidth / 2;
+
+ northWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity);
+ northEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity);
+ southWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity);
+ southEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity);
+ divided = true;
+ }
+
+ /**
+ * Queries all the points that intersect with the other bounding box
+ *
+ * @param otherBoundingBox The other bounding box
+ * @return List of points that intersect with the other bounding box
+ */
+ public List query(BoundingBox otherBoundingBox) {
+ List points = new ArrayList<>();
+
+ if (!boundary.intersectsBoundingBox(otherBoundingBox)) {
+ return points;
+ }
+
+ // filter the points that intersect with the other bounding box
+ points.addAll(pointList.stream().filter(otherBoundingBox::containsPoint).toList());
+
+ if (divided) {
+ points.addAll(northWest.query(otherBoundingBox));
+ points.addAll(northEast.query(otherBoundingBox));
+ points.addAll(southWest.query(otherBoundingBox));
+ points.addAll(southEast.query(otherBoundingBox));
+ }
+
+ return points;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java
new file mode 100644
index 000000000000..62b86da214db
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.datastructures.trees;
+
+import java.util.List;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class QuadTreeTest {
+ int quadTreeCapacity = 4;
+ BoundingBox boundingBox = new BoundingBox(new Point(0, 0), 500);
+ QuadTree quadTree = new QuadTree(boundingBox, quadTreeCapacity);
+
+ @Test
+ public void testNullPointInsertIntoQuadTree() {
+ Assertions.assertFalse(quadTree.insert(null));
+ }
+
+ @Test
+ public void testInsertIntoQuadTree() {
+ Assertions.assertTrue(quadTree.insert(new Point(10, -10)));
+ Assertions.assertTrue(quadTree.insert(new Point(-10, 10)));
+ Assertions.assertTrue(quadTree.insert(new Point(-10, -10)));
+ Assertions.assertTrue(quadTree.insert(new Point(10, 10)));
+ Assertions.assertFalse(quadTree.insert(new Point(1050, 1050)));
+ }
+
+ @Test
+ public void testInsertIntoQuadTreeAndSubDivide() {
+ Assertions.assertTrue(quadTree.insert(new Point(10, -10)));
+ Assertions.assertTrue(quadTree.insert(new Point(-10, 10)));
+ Assertions.assertTrue(quadTree.insert(new Point(-10, -10)));
+ Assertions.assertTrue(quadTree.insert(new Point(10, 10)));
+ Assertions.assertTrue(quadTree.insert(new Point(-100, 100)));
+ Assertions.assertTrue(quadTree.insert(new Point(100, -101)));
+ Assertions.assertTrue(quadTree.insert(new Point(-100, -100)));
+ Assertions.assertTrue(quadTree.insert(new Point(100, 100)));
+ }
+
+ @Test
+ public void testQueryInQuadTree() {
+ quadTree.insert(new Point(10, -10));
+ quadTree.insert(new Point(-10, 10));
+ quadTree.insert(new Point(-10, -10));
+ quadTree.insert(new Point(10, 10));
+ quadTree.insert(new Point(-100, 100));
+ quadTree.insert(new Point(100, -100));
+ quadTree.insert(new Point(-100, -100));
+ quadTree.insert(new Point(100, 100));
+
+ List points = quadTree.query(new BoundingBox(new Point(0, 0), 100));
+ Assertions.assertEquals(8, points.size());
+
+ points = quadTree.query(new BoundingBox(new Point(5, 5), 5));
+ Assertions.assertEquals(1, points.size());
+
+ points = quadTree.query(new BoundingBox(new Point(-200, -200), 5));
+ Assertions.assertEquals(0, points.size());
+ }
+}
From 872259843487610e3a971bbefb83af425d7bdbe5 Mon Sep 17 00:00:00 2001
From: Hardik Pawar <97388607+Hardvan@users.noreply.github.com>
Date: Sat, 12 Oct 2024 12:58:42 +0530
Subject: [PATCH 075/348] Add `ParityCheck` algorithm (#5704)
---
DIRECTORY.md | 3 ++
.../bitmanipulation/ParityCheck.java | 34 +++++++++++++++++++
.../bitmanipulation/ParityCheckTest.java | 15 ++++++++
3 files changed, 52 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 3dbd1519ff08..30fa2cbee199 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -40,6 +40,7 @@
* [NumberAppearingOddTimes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java)
* [NumbersDifferentSigns](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java)
* [OnesComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java)
+ * [ParityCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java)
* [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java)
* [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java)
* [SingleElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java)
@@ -670,6 +671,7 @@
* [NumberAppearingOddTimesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java)
* [NumbersDifferentSignsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java)
* [OnesComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java)
+ * [ParityCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java)
* [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java)
* [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java)
* [SingleElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java)
@@ -801,6 +803,7 @@
* [LevelOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/LevelOrderTraversalTest.java)
* [PostOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/PostOrderTraversalTest.java)
* [PreOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/PreOrderTraversalTest.java)
+ * [QuadTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java)
* [SameTreesCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java)
* [SplayTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java)
* [TreapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java)
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
new file mode 100644
index 000000000000..5acab4d4a362
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * The ParityCheck class provides a method to check the parity of a given number.
+ *
+ * Parity is a mathematical term that describes the property of an integer's binary representation.
+ * The parity of a binary number is the number of 1s in its binary representation.
+ * If the number of 1s is even, the parity is even; otherwise, it is odd.
+ *
+ * For example, the binary representation of 5 is 101, which has two 1s, so the parity of 5 is even.
+ * The binary representation of 6 is 110, which has two 1s, so the parity of 6 is even.
+ * The binary representation of 7 is 111, which has three 1s, so the parity of 7 is odd.
+ *
+ * @author Hardvan
+ */
+public final class ParityCheck {
+ private ParityCheck() {
+ }
+
+ /**
+ * This method checks the parity of the given number.
+ *
+ * @param n the number to check the parity of
+ * @return true if the number has even parity, false otherwise
+ */
+ public static boolean checkParity(int n) {
+ int count = 0;
+ while (n > 0) {
+ count += n & 1;
+ n >>= 1;
+ }
+ return count % 2 == 0;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java b/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java
new file mode 100644
index 000000000000..90147a61207b
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java
@@ -0,0 +1,15 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class ParityCheckTest {
+ @Test
+ public void testIsOddParity() {
+ assertTrue(ParityCheck.checkParity(5)); // 101 has 2 ones (even parity)
+ assertFalse(ParityCheck.checkParity(7)); // 111 has 3 ones (odd parity)
+ assertFalse(ParityCheck.checkParity(8)); // 1000 has 1 one (odd parity)
+ }
+}
From f8397bf09b3c7554da52470d6db3bf5b7b8d1e34 Mon Sep 17 00:00:00 2001
From: Benjamin Burstein <98127047+bennybebo@users.noreply.github.com>
Date: Sat, 12 Oct 2024 03:34:49 -0400
Subject: [PATCH 076/348] Add ADFGVX Cipher (#5631)
---
.../thealgorithms/ciphers/ADFGVXCipher.java | 123 ++++++++++++++++++
.../ciphers/ADFGVXCipherTest.java | 36 +++++
2 files changed, 159 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
create mode 100644 src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java
diff --git a/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
new file mode 100644
index 000000000000..3e62d6a26dcb
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
@@ -0,0 +1,123 @@
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+/**
+ * The ADFGVX cipher is a historically significant cipher used by
+ * the German Army during World War I. It is a fractionating transposition
+ * cipher that combines a Polybius square substitution with a columnar
+ * transposition. It's named after the six letters (A, D, F, G, V, X)
+ * that it uses in its substitution process.
+ * https://en.wikipedia.org/wiki/ADFGVX_cipher
+ *
+ * @author bennybebo
+ */
+public class ADFGVXCipher {
+
+ private static final char[] POLYBIUS_LETTERS = {'A', 'D', 'F', 'G', 'V', 'X'};
+ private static final char[][] POLYBIUS_SQUARE = {{'N', 'A', '1', 'C', '3', 'H'}, {'8', 'T', 'B', '2', 'O', 'M'}, {'E', '5', 'W', 'R', 'P', 'D'}, {'4', 'F', '6', 'G', '7', 'I'}, {'9', 'J', '0', 'K', 'L', 'Q'}, {'S', 'U', 'V', 'X', 'Y', 'Z'}};
+ private static final Map POLYBIUS_MAP = new HashMap<>();
+ private static final Map REVERSE_POLYBIUS_MAP = new HashMap<>();
+
+ static {
+ for (int i = 0; i < POLYBIUS_SQUARE.length; i++) {
+ for (int j = 0; j < POLYBIUS_SQUARE[i].length; j++) {
+ String key = "" + POLYBIUS_LETTERS[i] + POLYBIUS_LETTERS[j];
+ POLYBIUS_MAP.put(key, POLYBIUS_SQUARE[i][j]);
+ REVERSE_POLYBIUS_MAP.put(POLYBIUS_SQUARE[i][j], key);
+ }
+ }
+ }
+
+ // Encrypts the plaintext using the ADFGVX cipher
+ public String encrypt(String plaintext, String key) {
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", "");
+ StringBuilder fractionatedText = new StringBuilder();
+
+ // Step 1: Polybius square substitution
+ for (char c : plaintext.toCharArray()) {
+ fractionatedText.append(REVERSE_POLYBIUS_MAP.get(c));
+ }
+
+ // Step 2: Columnar transposition
+ return columnarTransposition(fractionatedText.toString(), key);
+ }
+
+ // Decrypts the ciphertext using the ADFGVX cipher
+ public String decrypt(String ciphertext, String key) {
+ // Step 1: Reverse the columnar transposition
+ String fractionatedText = reverseColumnarTransposition(ciphertext, key);
+
+ // Step 2: Polybius square substitution
+ StringBuilder plaintext = new StringBuilder();
+ for (int i = 0; i < fractionatedText.length(); i += 2) {
+ String pair = fractionatedText.substring(i, i + 2);
+ plaintext.append(POLYBIUS_MAP.get(pair));
+ }
+
+ return plaintext.toString();
+ }
+
+ private String columnarTransposition(String text, String key) {
+ int numRows = (int) Math.ceil((double) text.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+ for (char[] row : table) {
+ Arrays.fill(row, '_'); // Fill with underscores to handle empty cells
+ }
+
+ // Fill the table row by row
+ for (int i = 0; i < text.length(); i++) {
+ table[i / key.length()][i % key.length()] = text.charAt(i);
+ }
+
+ // Read columns based on the alphabetical order of the key
+ StringBuilder ciphertext = new StringBuilder();
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (char[] row : table) {
+ if (row[column] != '_') {
+ ciphertext.append(row[column]);
+ }
+ }
+ }
+
+ return ciphertext.toString();
+ }
+
+ private String reverseColumnarTransposition(String ciphertext, String key) {
+ int numRows = (int) Math.ceil((double) ciphertext.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ int index = 0;
+ // Fill the table column by column according to the sorted key order
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (int row = 0; row < numRows; row++) {
+ if (index < ciphertext.length()) {
+ table[row][column] = ciphertext.charAt(index++);
+ } else {
+ table[row][column] = '_'; // Fill empty cells with an underscore
+ }
+ }
+ }
+
+ // Read the table row by row to get the fractionated text
+ StringBuilder fractionatedText = new StringBuilder();
+ for (char[] row : table) {
+ for (char cell : row) {
+ if (cell != '_') {
+ fractionatedText.append(cell);
+ }
+ }
+ }
+
+ return fractionatedText.toString();
+ }
+}
diff --git a/src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java b/src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java
new file mode 100644
index 000000000000..a1fc4fd9ebe5
--- /dev/null
+++ b/src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java
@@ -0,0 +1,36 @@
+package com.thealgorithms.ciphers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class ADFGVXCipherTest {
+
+ ADFGVXCipher adfgvxCipher = new ADFGVXCipher();
+
+ @Test
+ void adfgvxCipherEncryptTest() {
+ // given
+ String message = "attack at 1200am"; // Plaintext message
+ String keyword = "PRIVACY";
+
+ // when
+ String cipherText = adfgvxCipher.encrypt(message, keyword);
+
+ // then
+ assertEquals("DGDDDAGDDGAFADDFDADVDVFAADVX", cipherText);
+ }
+
+ @Test
+ void adfgvxCipherDecryptTest() {
+ // given
+ String cipherText = "DGDDDAGDDGAFADDFDADVDVFAADVX"; // Ciphertext message
+ String keyword = "PRIVACY";
+
+ // when
+ String plainText = adfgvxCipher.decrypt(cipherText, keyword);
+
+ // then
+ assertEquals("ATTACKAT1200AM", plainText);
+ }
+}
From 31de2db0ae282054b81695e322dccb1baa3a32a1 Mon Sep 17 00:00:00 2001
From: Saahil Mahato <115351000+saahil-mahato@users.noreply.github.com>
Date: Sat, 12 Oct 2024 13:24:05 +0545
Subject: [PATCH 077/348] Add fast exponentiation algorithm (#5715)
---
.../maths/FastExponentiation.java | 67 +++++++++++++++++++
.../maths/FastExponentiationTest.java | 67 +++++++++++++++++++
2 files changed, 134 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/maths/FastExponentiation.java
create mode 100644 src/test/java/com/thealgorithms/maths/FastExponentiationTest.java
diff --git a/src/main/java/com/thealgorithms/maths/FastExponentiation.java b/src/main/java/com/thealgorithms/maths/FastExponentiation.java
new file mode 100644
index 000000000000..27f49e27ff30
--- /dev/null
+++ b/src/main/java/com/thealgorithms/maths/FastExponentiation.java
@@ -0,0 +1,67 @@
+package com.thealgorithms.maths;
+
+/**
+ * This class provides a method to perform fast exponentiation (exponentiation by squaring),
+ * which calculates (base^exp) % mod efficiently.
+ *
+ *
The algorithm works by repeatedly squaring the base and reducing the exponent
+ * by half at each step. It exploits the fact that:
+ *
+ *
If exp is even, (base^exp) = (base^(exp/2))^2
+ *
If exp is odd, (base^exp) = base * (base^(exp-1))
+ *
+ * The result is computed modulo `mod` at each step to avoid overflow and keep the result within bounds.
+ *
+ *
+ *
Time complexity: O(log(exp)) — much faster than naive exponentiation (O(exp)).
+ *
+ * For more information, please visit {@link https://en.wikipedia.org/wiki/Exponentiation_by_squaring}
+ */
+public final class FastExponentiation {
+
+ /**
+ * Private constructor to hide the implicit public one.
+ */
+ private FastExponentiation() {
+ }
+
+ /**
+ * Performs fast exponentiation to calculate (base^exp) % mod using the method
+ * of exponentiation by squaring.
+ *
+ *
This method efficiently computes the result by squaring the base and halving
+ * the exponent at each step. It multiplies the base to the result when the exponent is odd.
+ *
+ * @param base the base number to be raised to the power of exp
+ * @param exp the exponent to which the base is raised
+ * @param mod the modulus to ensure the result does not overflow
+ * @return (base^exp) % mod
+ * @throws IllegalArgumentException if the modulus is less than or equal to 0
+ * @throws ArithmeticException if the exponent is negative (not supported in this implementation)
+ */
+ public static long fastExponentiation(long base, long exp, long mod) {
+ if (mod <= 0) {
+ throw new IllegalArgumentException("Modulus must be positive.");
+ }
+
+ if (exp < 0) {
+ throw new ArithmeticException("Negative exponent is not supported.");
+ }
+
+ long result = 1;
+ base = base % mod; // Take the modulus of the base to handle large base values
+
+ // Fast exponentiation by squaring algorithm
+ while (exp > 0) {
+ // If exp is odd, multiply the base to the result
+ if ((exp & 1) == 1) { // exp & 1 checks if exp is odd
+ result = result * base % mod;
+ }
+ // Square the base and halve the exponent
+ base = base * base % mod; // base^2 % mod to avoid overflow
+ exp >>= 1; // Right shift exp to divide it by 2
+ }
+
+ return result;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/maths/FastExponentiationTest.java b/src/test/java/com/thealgorithms/maths/FastExponentiationTest.java
new file mode 100644
index 000000000000..f117f90233e3
--- /dev/null
+++ b/src/test/java/com/thealgorithms/maths/FastExponentiationTest.java
@@ -0,0 +1,67 @@
+package com.thealgorithms.maths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for the {@link FastExponentiation} class.
+ *
+ *
This class contains various test cases to verify the correctness of the fastExponentiation method.
+ * It covers basic functionality, edge cases, and exceptional cases.
+ */
+class FastExponentiationTest {
+
+ /**
+ * Tests fast exponentiation with small numbers.
+ */
+ @Test
+ void testSmallNumbers() {
+ assertEquals(1024, FastExponentiation.fastExponentiation(2, 10, 10000), "2^10 mod 10000 should be 1024");
+ assertEquals(81, FastExponentiation.fastExponentiation(3, 4, 1000), "3^4 mod 1000 should be 81");
+ }
+
+ /**
+ * Tests the behavior of the fast exponentiation method when using a modulus.
+ */
+ @Test
+ void testWithModulo() {
+ assertEquals(24, FastExponentiation.fastExponentiation(2, 10, 1000), "2^10 mod 1000 should be 24");
+ assertEquals(0, FastExponentiation.fastExponentiation(10, 5, 10), "10^5 mod 10 should be 0");
+ }
+
+ /**
+ * Tests the edge cases where base or exponent is 0.
+ */
+ @Test
+ void testBaseCases() {
+ assertEquals(1, FastExponentiation.fastExponentiation(2, 0, 1000), "Any number raised to the power 0 mod anything should be 1");
+ assertEquals(0, FastExponentiation.fastExponentiation(0, 10, 1000), "0 raised to any power should be 0");
+ assertEquals(1, FastExponentiation.fastExponentiation(0, 0, 1000), "0^0 is considered 0 in modular arithmetic.");
+ }
+
+ /**
+ * Tests fast exponentiation with a negative base to ensure correctness under modular arithmetic.
+ */
+ @Test
+ void testNegativeBase() {
+ assertEquals(9765625, FastExponentiation.fastExponentiation(-5, 10, 1000000007), "-5^10 mod 1000000007 should be 9765625");
+ }
+
+ /**
+ * Tests that a negative exponent throws an ArithmeticException.
+ */
+ @Test
+ void testNegativeExponent() {
+ assertThrows(ArithmeticException.class, () -> { FastExponentiation.fastExponentiation(2, -5, 1000); });
+ }
+
+ /**
+ * Tests that the method throws an IllegalArgumentException for invalid modulus values.
+ */
+ @Test
+ void testInvalidModulus() {
+ assertThrows(IllegalArgumentException.class, () -> { FastExponentiation.fastExponentiation(2, 5, 0); });
+ }
+}
From ac65af44c9365d42da42fb71c0b76115677fc673 Mon Sep 17 00:00:00 2001
From: Saahil Mahato <115351000+saahil-mahato@users.noreply.github.com>
Date: Sat, 12 Oct 2024 13:29:41 +0545
Subject: [PATCH 078/348] Add Johnson's algorithm (#5712)
---
.../graphs/JohnsonsAlgorithm.java | 203 ++++++++++++++++++
.../graphs/JohnsonsAlgorithmTest.java | 136 ++++++++++++
2 files changed, 339 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java
create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java
diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java
new file mode 100644
index 000000000000..76c11f782985
--- /dev/null
+++ b/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java
@@ -0,0 +1,203 @@
+package com.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class implements Johnson's algorithm for finding all-pairs shortest paths in a weighted,
+ * directed graph that may contain negative edge weights.
+ *
+ * Johnson's algorithm works by using the Bellman-Ford algorithm to compute a transformation of the
+ * input graph that removes all negative weights, allowing Dijkstra's algorithm to be used for
+ * efficient shortest path computations.
+ *
+ * Time Complexity: O(V^2 * log(V) + V*E)
+ * Space Complexity: O(V^2)
+ *
+ * Where V is the number of vertices and E is the number of edges in the graph.
+ *
+ * For more information, please visit {@link https://en.wikipedia.org/wiki/Johnson%27s_algorithm}
+ */
+public final class JohnsonsAlgorithm {
+
+ // Constant representing infinity
+ private static final double INF = Double.POSITIVE_INFINITY;
+
+ /**
+ * A private constructor to hide the implicit public one.
+ */
+ private JohnsonsAlgorithm() {
+ }
+
+ /**
+ * Executes Johnson's algorithm on the given graph.
+ *
+ * @param graph The input graph represented as an adjacency matrix.
+ * @return A 2D array representing the shortest distances between all pairs of vertices.
+ */
+ public static double[][] johnsonAlgorithm(double[][] graph) {
+ int numVertices = graph.length;
+ double[][] edges = convertToEdgeList(graph);
+
+ // Step 1: Add a new vertex and run Bellman-Ford
+ double[] modifiedWeights = bellmanFord(edges, numVertices);
+
+ // Step 2: Reweight the graph
+ double[][] reweightedGraph = reweightGraph(graph, modifiedWeights);
+
+ // Step 3: Run Dijkstra's algorithm for each vertex
+ double[][] shortestDistances = new double[numVertices][numVertices];
+ for (int source = 0; source < numVertices; source++) {
+ shortestDistances[source] = dijkstra(reweightedGraph, source, modifiedWeights);
+ }
+
+ return shortestDistances;
+ }
+
+ /**
+ * Converts the adjacency matrix representation of the graph to an edge list.
+ *
+ * @param graph The input graph as an adjacency matrix.
+ * @return An array of edges, where each edge is represented as [from, to, weight].
+ */
+ public static double[][] convertToEdgeList(double[][] graph) {
+ int numVertices = graph.length;
+ List edgeList = new ArrayList<>();
+
+ for (int i = 0; i < numVertices; i++) {
+ for (int j = 0; j < numVertices; j++) {
+ if (i != j && !Double.isInfinite(graph[i][j])) {
+ // Only add edges that are not self-loops and have a finite weight
+ edgeList.add(new double[] {i, j, graph[i][j]});
+ }
+ }
+ }
+
+ // Convert the List to a 2D array
+ return edgeList.toArray(new double[0][]);
+ }
+
+ /**
+ * Implements the Bellman-Ford algorithm to compute the shortest paths from a new vertex
+ * to all other vertices. This is used to calculate the weight function h(v) for reweighting.
+ *
+ * @param edges The edge list of the graph.
+ * @param numVertices The number of vertices in the original graph.
+ * @return An array of modified weights for each vertex.
+ */
+ private static double[] bellmanFord(double[][] edges, int numVertices) {
+ double[] dist = new double[numVertices + 1];
+ Arrays.fill(dist, INF);
+ dist[numVertices] = 0; // Distance to the new source vertex is 0
+
+ // Add edges from the new vertex to all original vertices
+ double[][] allEdges = Arrays.copyOf(edges, edges.length + numVertices);
+ for (int i = 0; i < numVertices; i++) {
+ allEdges[edges.length + i] = new double[] {numVertices, i, 0};
+ }
+
+ // Relax all edges V times
+ for (int i = 0; i < numVertices; i++) {
+ for (double[] edge : allEdges) {
+ int u = (int) edge[0];
+ int v = (int) edge[1];
+ double weight = edge[2];
+ if (dist[u] != INF && dist[u] + weight < dist[v]) {
+ dist[v] = dist[u] + weight;
+ }
+ }
+ }
+
+ // Check for negative weight cycles
+ for (double[] edge : allEdges) {
+ int u = (int) edge[0];
+ int v = (int) edge[1];
+ double weight = edge[2];
+ if (dist[u] + weight < dist[v]) {
+ throw new IllegalArgumentException("Graph contains a negative weight cycle");
+ }
+ }
+
+ return Arrays.copyOf(dist, numVertices);
+ }
+
+ /**
+ * Reweights the graph using the modified weights computed by Bellman-Ford.
+ *
+ * @param graph The original graph.
+ * @param modifiedWeights The modified weights from Bellman-Ford.
+ * @return The reweighted graph.
+ */
+ public static double[][] reweightGraph(double[][] graph, double[] modifiedWeights) {
+ int numVertices = graph.length;
+ double[][] reweightedGraph = new double[numVertices][numVertices];
+
+ for (int i = 0; i < numVertices; i++) {
+ for (int j = 0; j < numVertices; j++) {
+ if (graph[i][j] != 0) {
+ // New weight = original weight + h(u) - h(v)
+ reweightedGraph[i][j] = graph[i][j] + modifiedWeights[i] - modifiedWeights[j];
+ }
+ }
+ }
+
+ return reweightedGraph;
+ }
+
+ /**
+ * Implements Dijkstra's algorithm for finding shortest paths from a source vertex.
+ *
+ * @param reweightedGraph The reweighted graph to run Dijkstra's on.
+ * @param source The source vertex.
+ * @param modifiedWeights The modified weights from Bellman-Ford.
+ * @return An array of shortest distances from the source to all other vertices.
+ */
+ public static double[] dijkstra(double[][] reweightedGraph, int source, double[] modifiedWeights) {
+ int numVertices = reweightedGraph.length;
+ double[] dist = new double[numVertices];
+ boolean[] visited = new boolean[numVertices];
+ Arrays.fill(dist, INF);
+ dist[source] = 0;
+
+ for (int count = 0; count < numVertices - 1; count++) {
+ int u = minDistance(dist, visited);
+ visited[u] = true;
+
+ for (int v = 0; v < numVertices; v++) {
+ if (!visited[v] && reweightedGraph[u][v] != 0 && dist[u] != INF && dist[u] + reweightedGraph[u][v] < dist[v]) {
+ dist[v] = dist[u] + reweightedGraph[u][v];
+ }
+ }
+ }
+
+ // Adjust distances back to the original graph weights
+ for (int i = 0; i < numVertices; i++) {
+ if (dist[i] != INF) {
+ dist[i] = dist[i] - modifiedWeights[source] + modifiedWeights[i];
+ }
+ }
+
+ return dist;
+ }
+
+ /**
+ * Finds the vertex with the minimum distance value from the set of vertices
+ * not yet included in the shortest path tree.
+ *
+ * @param dist Array of distances.
+ * @param visited Array of visited vertices.
+ * @return The index of the vertex with minimum distance.
+ */
+ public static int minDistance(double[] dist, boolean[] visited) {
+ double min = INF;
+ int minIndex = -1;
+ for (int v = 0; v < dist.length; v++) {
+ if (!visited[v] && dist[v] <= min) {
+ min = dist[v];
+ minIndex = v;
+ }
+ }
+ return minIndex;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java
new file mode 100644
index 000000000000..0ae837cd944f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java
@@ -0,0 +1,136 @@
+package com.thealgorithms.datastructures.graphs;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link JohnsonsAlgorithm} class. This class
+ * contains test cases to verify the correct implementation of
+ * various methods used in Johnson's Algorithm such as shortest path
+ * calculations, graph reweighting, and more.
+ */
+class JohnsonsAlgorithmTest {
+
+ // Constant representing infinity
+ private static final double INF = Double.POSITIVE_INFINITY;
+
+ /**
+ * Tests the Johnson's Algorithm with a simple graph without negative edges.
+ * Verifies that the algorithm returns the correct shortest path distances.
+ */
+ @Test
+ void testSimpleGraph() {
+ // Test case for a simple graph without negative edges
+ double[][] graph = {{0, 4, INF, INF}, {INF, 0, 1, INF}, {INF, INF, 0, 2}, {INF, INF, INF, 0}};
+
+ double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
+
+ double[][] expected = {{0, 4, 5, 7}, {INF, 0, 1, 3}, {INF, INF, 0, 2}, {INF, INF, INF, 0}};
+
+ assertArrayEquals(expected, result);
+ }
+
+ /**
+ * Tests Johnson's Algorithm on a graph with negative edges but no
+ * negative weight cycles. Verifies the algorithm handles negative
+ * edge weights correctly.
+ */
+ @Test
+ void testGraphWithNegativeEdges() {
+ // Graph with negative edges but no negative weight cycles
+ double[][] graph = {{0, -1, 4}, {INF, 0, 3}, {INF, INF, 0}};
+
+ double[][] result = JohnsonsAlgorithm.johnsonAlgorithm(graph);
+
+ double[][] expected = {{0, INF, 4}, {INF, 0, 3}, {INF, INF, 0}};
+
+ assertArrayEquals(expected, result);
+ }
+
+ /**
+ * Tests the behavior of Johnson's Algorithm on a graph with a negative
+ * weight cycle. Expects an IllegalArgumentException to be thrown
+ * due to the presence of the cycle.
+ */
+ @Test
+ void testNegativeWeightCycle() {
+ // Graph with a negative weight cycle
+ double[][] graph = {{0, 1, INF}, {INF, 0, -1}, {-1, INF, 0}};
+
+ // Johnson's algorithm should throw an exception when a negative cycle is detected
+ assertThrows(IllegalArgumentException.class, () -> { JohnsonsAlgorithm.johnsonAlgorithm(graph); });
+ }
+
+ /**
+ * Tests Dijkstra's algorithm as a part of Johnson's algorithm implementation
+ * on a small graph. Verifies that the shortest path is correctly calculated.
+ */
+ @Test
+ void testDijkstra() {
+ // Testing Dijkstra's algorithm with a small graph
+ double[][] graph = {{0, 1, 2}, {INF, 0, 3}, {INF, INF, 0}};
+
+ double[] modifiedWeights = {0, 0, 0}; // No reweighting in this simple case
+
+ double[] result = JohnsonsAlgorithm.dijkstra(graph, 0, modifiedWeights);
+ double[] expected = {0, 1, 2};
+
+ assertArrayEquals(expected, result);
+ }
+
+ /**
+ * Tests the conversion of an adjacency matrix to an edge list.
+ * Verifies that the conversion process generates the correct edge list.
+ */
+ @Test
+ void testEdgeListConversion() {
+ // Test the conversion of adjacency matrix to edge list
+ double[][] graph = {{0, 5, INF}, {INF, 0, 2}, {INF, INF, 0}};
+
+ // Running convertToEdgeList
+ double[][] edges = JohnsonsAlgorithm.convertToEdgeList(graph);
+
+ // Expected edge list: (0 -> 1, weight 5), (1 -> 2, weight 2)
+ double[][] expected = {{0, 1, 5}, {1, 2, 2}};
+
+ // Verify the edge list matches the expected values
+ assertArrayEquals(expected, edges);
+ }
+
+ /**
+ * Tests the reweighting of a graph as a part of Johnson's Algorithm.
+ * Verifies that the reweighted graph produces correct results.
+ */
+ @Test
+ void testReweightGraph() {
+ // Test reweighting of the graph
+ double[][] graph = {{0, 2, 9}, {INF, 0, 1}, {INF, INF, 0}};
+ double[] modifiedWeights = {1, 2, 3}; // Arbitrary weight function
+
+ double[][] reweightedGraph = JohnsonsAlgorithm.reweightGraph(graph, modifiedWeights);
+
+ // Expected reweighted graph:
+ double[][] expected = {{0, 1, 7}, {INF, 0, 0}, {INF, INF, 0}};
+
+ assertArrayEquals(expected, reweightedGraph);
+ }
+
+ /**
+ * Tests the minDistance method used in Dijkstra's algorithm to find
+ * the vertex with the minimum distance that has not yet been visited.
+ */
+ @Test
+ void testMinDistance() {
+ // Test minDistance method
+ double[] dist = {INF, 3, 1, INF};
+ boolean[] visited = {false, false, false, false};
+
+ int minIndex = JohnsonsAlgorithm.minDistance(dist, visited);
+
+ // The vertex with minimum distance is vertex 2 with a distance of 1
+ assertEquals(2, minIndex);
+ }
+}
From 1617ed1368eb303a3b77d948f74225267c4bf235 Mon Sep 17 00:00:00 2001
From: Tuhinm2002 <75078694+Tuhinm2002@users.noreply.github.com>
Date: Sun, 13 Oct 2024 00:17:42 +0530
Subject: [PATCH 079/348] feat : new bit manipulation algo `FindNthBit` of a
number (#5731)
* feat : new algo uniquesubseqcount
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCountTest.java
* Update UniqueSubsequencesCount.java
* feat : new bitmanipulation algo
* feat : new bit algo
* Update FindNthBitTest.java
* Update FindNthBit.java
---------
Co-authored-by: Alex Klymenko
---
.../bitmanipulation/FindNthBit.java | 46 +++++++++++++++++++
.../bitmanipulation/FindNthBitTest.java | 39 ++++++++++++++++
2 files changed, 85 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
new file mode 100644
index 000000000000..7a35fc3feebf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to find the Nth bit of a given number.
+ *
+ *
This class provides a method to extract the value of the Nth bit (either 0 or 1)
+ * from the binary representation of a given integer.
+ *
+ *
Example:
+ *
{@code
+ * int result = FindNthBit.findNthBit(5, 2); // returns 0 as the 2nd bit of 5 (binary 101) is 0.
+ * }
+ *
+ *
Author: Tuhinm2002
+ */
+public final class FindNthBit {
+
+ /**
+ * Private constructor to prevent instantiation.
+ *
+ *
This is a utility class, and it should not be instantiated.
+ * Attempting to instantiate this class will throw an UnsupportedOperationException.
+ */
+ private FindNthBit() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Finds the value of the Nth bit of the given number.
+ *
+ *
This method uses bitwise operations to extract the Nth bit from the
+ * binary representation of the given integer.
+ *
+ * @param num the integer number whose Nth bit is to be found
+ * @param n the bit position (1-based) to retrieve
+ * @return the value of the Nth bit (0 or 1)
+ * @throws IllegalArgumentException if the bit position is less than 1
+ */
+ public static int findNthBit(int num, int n) {
+ if (n < 1) {
+ throw new IllegalArgumentException("Bit position must be greater than or equal to 1.");
+ }
+ // Shifting the number to the right by (n - 1) positions and checking the last bit
+ return (num & (1 << (n - 1))) >> (n - 1);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java b/src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java
new file mode 100644
index 000000000000..978003d21358
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+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 final class FindNthBitTest {
+
+ /**
+ * A parameterized test that checks the value of the Nth bit for different inputs.
+ *
+ * @param num the number whose Nth bit is being tested
+ * @param n the bit position
+ * @param expected the expected value of the Nth bit (0 or 1)
+ */
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void findNthBitParameterizedTest(int num, int n, int expected) {
+ assertEquals(expected, FindNthBit.findNthBit(num, n));
+ }
+
+ /**
+ * Provides the test cases as a stream of arguments for the parameterized test.
+ *
+ * @return a stream of test cases where each case consists of a number, the bit position,
+ * and the expected result.
+ */
+ private static Stream provideTestCases() {
+ return Stream.of(Arguments.of(13, 2, 0), // binary: 1101, 2nd bit is 0
+ Arguments.of(13, 3, 1), // binary: 1101, 3rd bit is 1
+ Arguments.of(4, 2, 0), // binary: 100, 2nd bit is 0
+ Arguments.of(4, 3, 1), // binary: 100, 3rd bit is 1
+ Arguments.of(1, 1, 1) // binary: 1, 1st bit is 1
+ );
+ }
+}
From 4a03f420616a6773e9a5cdc304b1681e96d945bd Mon Sep 17 00:00:00 2001
From: vansh kabra <134841334+VANSH3104@users.noreply.github.com>
Date: Sun, 13 Oct 2024 00:28:52 +0530
Subject: [PATCH 080/348] Add algo for BooleanGateslogic (#5717)
---
.../bitmanipulation/BooleanAlgebraGates.java | 111 ++++++++++++++++++
.../BooleanAlgebraGatesTest.java | 101 ++++++++++++++++
2 files changed, 212 insertions(+)
create mode 100644 src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
create mode 100644 src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
new file mode 100644
index 000000000000..869466320831
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
@@ -0,0 +1,111 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.List;
+
+/**
+ * Implements various Boolean algebra gates (AND, OR, NOT, XOR, NAND, NOR)
+ */
+public final class BooleanAlgebraGates {
+
+ private BooleanAlgebraGates() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Represents a Boolean gate that takes multiple inputs and returns a result.
+ */
+ interface BooleanGate {
+ /**
+ * Evaluates the gate with the given inputs.
+ *
+ * @param inputs The input values for the gate.
+ * @return The result of the evaluation.
+ */
+ boolean evaluate(List inputs);
+ }
+
+ /**
+ * AND Gate implementation.
+ * Returns true if all inputs are true; otherwise, false.
+ */
+ static class ANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (!input) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * OR Gate implementation.
+ * Returns true if at least one input is true; otherwise, false.
+ */
+ static class ORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (input) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * NOT Gate implementation (Unary operation).
+ * Negates a single input value.
+ */
+ static class NOTGate {
+ /**
+ * Evaluates the negation of the input.
+ *
+ * @param input The input value to be negated.
+ * @return The negated value.
+ */
+ public boolean evaluate(boolean input) {
+ return !input;
+ }
+ }
+
+ /**
+ * XOR Gate implementation.
+ * Returns true if an odd number of inputs are true; otherwise, false.
+ */
+ static class XORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ boolean result = false;
+ for (boolean input : inputs) {
+ result ^= input;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * NAND Gate implementation.
+ * Returns true if at least one input is false; otherwise, false.
+ */
+ static class NANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ANDGate().evaluate(inputs); // Equivalent to negation of AND
+ }
+ }
+
+ /**
+ * NOR Gate implementation.
+ * Returns true if all inputs are false; otherwise, false.
+ */
+ static class NORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ORGate().evaluate(inputs); // Equivalent to negation of OR
+ }
+ }
+}
diff --git a/src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java b/src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java
new file mode 100644
index 000000000000..8737d05ec459
--- /dev/null
+++ b/src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.bitmanipulation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.ANDGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.BooleanGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.NANDGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.NORGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.NOTGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.ORGate;
+import com.thealgorithms.bitmanipulation.BooleanAlgebraGates.XORGate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class BooleanAlgebraGatesTest {
+
+ @ParameterizedTest(name = "ANDGate Test Case {index}: inputs={0} -> expected={1}")
+ @MethodSource("provideAndGateTestCases")
+ void testANDGate(List inputs, boolean expected) {
+ BooleanGate gate = new ANDGate();
+ assertEquals(expected, gate.evaluate(inputs));
+ }
+
+ @ParameterizedTest(name = "ORGate Test Case {index}: inputs={0} -> expected={1}")
+ @MethodSource("provideOrGateTestCases")
+ void testORGate(List inputs, boolean expected) {
+ BooleanGate gate = new ORGate();
+ assertEquals(expected, gate.evaluate(inputs));
+ }
+
+ @ParameterizedTest(name = "NOTGate Test Case {index}: input={0} -> expected={1}")
+ @CsvSource({"true, false", "false, true"})
+ void testNOTGate(boolean input, boolean expected) {
+ NOTGate gate = new NOTGate();
+ assertEquals(expected, gate.evaluate(input));
+ }
+
+ @ParameterizedTest(name = "XORGate Test Case {index}: inputs={0} -> expected={1}")
+ @MethodSource("provideXorGateTestCases")
+ void testXORGate(List inputs, boolean expected) {
+ BooleanGate gate = new XORGate();
+ assertEquals(expected, gate.evaluate(inputs));
+ }
+
+ @ParameterizedTest(name = "NANDGate Test Case {index}: inputs={0} -> expected={1}")
+ @MethodSource("provideNandGateTestCases")
+ void testNANDGate(List inputs, boolean expected) {
+ BooleanGate gate = new NANDGate();
+ assertEquals(expected, gate.evaluate(inputs));
+ }
+
+ @ParameterizedTest(name = "NORGate Test Case {index}: inputs={0} -> expected={1}")
+ @MethodSource("provideNorGateTestCases")
+ void testNORGate(List inputs, boolean expected) {
+ BooleanGate gate = new NORGate();
+ assertEquals(expected, gate.evaluate(inputs));
+ }
+
+ // Helper methods to provide test data for each gate
+
+ static Stream