diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortBFS.java b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortBFS.java new file mode 100644 index 000000000000..b8ba3523abc4 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortBFS.java @@ -0,0 +1,86 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.*; + +/** + * This class provides an implementation of Topological Sort using BFS (Kahn's + * Algorithm) + * for the Course Schedule problem (LeetCode 207). + * + * @author Lochan Paudel + */ +public class TopologicalSortBFS { + + /** + * This method performs topological sort using BFS to determine if all courses + * can be completed. + * + * @param numCourses Total number of courses + * @param prerequisites A 2D array where prerequisites[i] = [a, b] indicates + * that course b must be taken before course a + * @return true if all courses can be finished, false otherwise + */ + public boolean canFinish(int numCourses, int[][] prerequisites) { + // Edge Case: No courses or no prerequisites + if (numCourses == 0 || prerequisites == null) { + return true; + } + + // Initialize graph and in-degree array + List> graph = new ArrayList<>(); + int[] inDegree = new int[numCourses]; + + // Build the graph (adjacency list) and fill in-degree array + for (int i = 0; i < numCourses; i++) { + graph.add(new ArrayList<>()); + } + + for (int[] pre : prerequisites) { + int course = pre[0]; + int prerequisite = pre[1]; + graph.get(prerequisite).add(course); + inDegree[course]++; + } + + // Initialize queue for BFS + Queue queue = new LinkedList<>(); + + // Add courses with no prerequisites (in-degree 0) to the queue + for (int i = 0; i < numCourses; i++) { + if (inDegree[i] == 0) { + queue.add(i); + } + } + + // Number of courses processed + int processedCourses = 0; + + // Process courses in BFS order + while (!queue.isEmpty()) { + int course = queue.poll(); + processedCourses++; + + for (int neighbor : graph.get(course)) { + inDegree[neighbor]--; + if (inDegree[neighbor] == 0) { + queue.add(neighbor); + } + } + } + + // If we've processed all courses, return true, otherwise return false (cycle + // detected) + return processedCourses == numCourses; + } + + /** + * Main method for testing the Topological Sort BFS solution. + */ + public static void main(String[] args) { + TopologicalSortBFS ts = new TopologicalSortBFS(); + + // Test cases + System.out.println(ts.canFinish(2, new int[][] { { 1, 0 } })); // true + System.out.println(ts.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); // false + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java new file mode 100644 index 000000000000..6d27be6a7163 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/TopologicalSortDFS.java @@ -0,0 +1,93 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.*; + +/** + * This class provides an implementation of Topological Sort using DFS + * for the Course Schedule problem (LeetCode 207). + * + * @author Lochan Paudel + */ +public class TopologicalSortDFS { + + /** + * This method performs topological sort using DFS to determine if all courses + * can be completed. + * + * @param numCourses Total number of courses + * @param prerequisites A 2D array where prerequisites[i] = [a, b] indicates + * that course b must be taken before course a + * @return true if all courses can be finished, false otherwise + */ + public boolean canFinish(int numCourses, int[][] prerequisites) { + // Edge Case: No courses or no prerequisites + if (numCourses == 0 || prerequisites == null) { + return true; + } + + // Initialize graph + List> graph = new ArrayList<>(); + for (int i = 0; i < numCourses; i++) { + graph.add(new ArrayList<>()); + } + + // Build the graph (adjacency list) + for (int[] pre : prerequisites) { + int course = pre[0]; + int prerequisite = pre[1]; + graph.get(prerequisite).add(course); + } + + // Array to track visiting and visited nodes + int[] visited = new int[numCourses]; + + // Perform DFS for all courses + for (int i = 0; i < numCourses; i++) { + if (!dfs(i, graph, visited)) { + return false; // If a cycle is found, return false + } + } + + return true; // No cycle found, return true + } + + /** + * Helper method to perform DFS and detect cycles. + * + * @param course The current course + * @param graph The adjacency list of the graph + * @param visited Array to keep track of visit status (0 = unvisited, 1 = + * visiting, 2 = visited) + * @return true if no cycle is detected, otherwise false + */ + private boolean dfs(int course, List> graph, int[] visited) { + if (visited[course] == 1) { + return false; // Cycle detected (back edge) + } + if (visited[course] == 2) { + return true; // Already visited, no cycle here + } + + visited[course] = 1; // Mark course as visiting + + for (int neighbor : graph.get(course)) { + if (!dfs(neighbor, graph, visited)) { + return false; + } + } + + visited[course] = 2; // Mark course as fully visited + return true; + } + + /** + * Main method for testing the Topological Sort DFS solution. + */ + public static void main(String[] args) { + TopologicalSortDFS ts = new TopologicalSortDFS(); + + // Test cases + System.out.println(ts.canFinish(2, new int[][] { { 1, 0 } })); // true + System.out.println(ts.canFinish(2, new int[][] { { 1, 0 }, { 0, 1 } })); // false + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/LinkedListCycleDetection.java b/src/main/java/com/thealgorithms/datastructures/lists/LinkedListCycleDetection.java new file mode 100644 index 000000000000..74818530791b --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/LinkedListCycleDetection.java @@ -0,0 +1,90 @@ +package com.thealgorithms.datastructures.lists; + +/** + * This class provides an implementation of cycle detection in a linked list + * using Floyd's Cycle Detection Algorithm (Tortoise and Hare Algorithm). + * + * The algorithm uses two pointers: slow and fast. The slow pointer moves + * one step at a time, while the fast pointer moves two steps. If there is a + * cycle in the linked list, the two pointers will meet; otherwise, the fast + * pointer will reach the end of the list. + * + * @author Lochan Paudel + */ +class ListNode { + int val; + ListNode next; + + ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class LinkedListCycleDetection { + + /** + * Function to detect a cycle in the linked list using Floyd's Cycle Detection + * Algorithm. + * + * @param head The head of the linked list + * @return true if a cycle is detected, otherwise false + */ + public static boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; // Edge Case 1: List is empty or contains only one node (no cycle possible) + } + + ListNode slow = head; + ListNode fast = head; + + // Traverse the list with two pointers + while (fast != null && fast.next != null) { + slow = slow.next; // Move slow pointer by one step + fast = fast.next.next; // Move fast pointer by two steps + + if (slow == fast) { // If the pointers meet, a cycle is detected + return true; + } + } + + return false; // No cycle detected + } + + /** + * Main method to run test cases + * + * Test cases include: + * 1. Empty list + * 2. Single node with no cycle + * 3. Multiple nodes with no cycle + * 4. Multiple nodes with a cycle + */ + public static void main(String[] args) { + // Test Case 1: Empty List (Edge Case) + ListNode head1 = null; + System.out.println("Test Case 1 (Empty List): " + (hasCycle(head1) ? "Cycle Detected" : "No Cycle")); + + // Test Case 2: Single node, no cycle (Edge Case) + ListNode head2 = new ListNode(1); + System.out.println("Test Case 2 (Single Node, No Cycle): " + (hasCycle(head2) ? "Cycle Detected" : "No Cycle")); + + // Test Case 3: Multiple nodes, no cycle + ListNode head3 = new ListNode(1); + head3.next = new ListNode(2); + head3.next.next = new ListNode(3); + System.out.println( + "Test Case 3 (Multiple Nodes, No Cycle): " + (hasCycle(head3) ? "Cycle Detected" : "No Cycle")); + + // Test Case 4: Multiple nodes, with cycle + ListNode head4 = new ListNode(1); + ListNode second = new ListNode(2); + ListNode third = new ListNode(3); + ListNode fourth = new ListNode(4); + head4.next = second; + second.next = third; + third.next = fourth; + fourth.next = second; // Creates a cycle + System.out.println("Test Case 4 (Multiple Nodes, Cycle): " + (hasCycle(head4) ? "Cycle Detected" : "No Cycle")); + } +}