diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ff949966 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.exe +".DS_Store" +.DS_Store +.DS_Store +.DS_Store diff --git a/.history/java/Chatbot_20251011133817.java b/.history/java/Chatbot_20251011133817.java new file mode 100644 index 00000000..26d7b837 --- /dev/null +++ b/.history/java/Chatbot_20251011133817.java @@ -0,0 +1,48 @@ +import java.util.HashMap; +import java.util.Scanner; +import java.util.Set; + +public class Chatbot { + + private static final HashMap Siri=new HashMap<>(); + static { + Siri.put("good evening", "good evening , Hope all is well!!"); + Siri.put("hello", "Hello! I am a simple rule-based bot. How can I help you today?"); + Siri.put("hi", "Hello there! Ask me about our operating hours or services."); + Siri.put("hours", "Our operating hours are Monday to Friday, 9:00 AM to 5:00 PM."); + Siri.put("service", "We offer customer support, technical assistance, and product demos."); + Siri.put("bye", "Goodbye! Have a great day."); + Siri.put("thank", "You're welcome! Feel free to ask anything else."); + } + private static String preprocessInput(String In) { + return In.toLowerCase().trim(); + } + private static String getResponse(String Cli) { + Set key=Siri.keySet(); + for(String keys: key) { + if(Cli.contains(keys)) { + return Siri.get(keys); + } + } + return "I'm sorry, I don't understand that. Could you please rephrase your question?"; + } + public static void main(String[] args) { + System.out.println("Siri Initialized"); + Scanner sc=new Scanner(System.in); + String UsI; + while(true) { + System.out.print("You : "); + UsI = sc.nextLine(); + if(UsI.equalsIgnoreCase("bye")) { + String farewell= getResponse(preprocessInput(UsI)); + System.out.println("Bot: "+ farewell); + break; + } + String cleanedInput=preprocessInput(UsI); + String botResponse=getResponse(cleanedInput); + System.out.println("Bot: " + botResponse); + } + sc.close(); + System.out.println("Siri session ended."); + } +} diff --git a/.history/java/Chatbot_20251011135524.java b/.history/java/Chatbot_20251011135524.java new file mode 100644 index 00000000..6482f91e --- /dev/null +++ b/.history/java/Chatbot_20251011135524.java @@ -0,0 +1,51 @@ +import java.util.HashMap; +import java.util.Scanner; +import java.util.Set; + +public class Chatbot { + + private static final HashMap Siri = new HashMap<>(); + static { + Siri.put("good evening", "good evening , Hope all is well!!"); + Siri.put("hello", "Hello! I am a simple rule-based bot. How can I help you today?"); + Siri.put("hi", "Hello there! Ask me about our operating hours or services."); + Siri.put("hours", "Our operating hours are Monday to Friday, 9:00 AM to 5:00 PM."); + Siri.put("service", "We offer customer support, technical assistance, and product demos."); + Siri.put("bye", "Goodbye! Have a great day."); + Siri.put("thank", "You're welcome! Feel free to ask anything else."); + } + + private static String preprocessInput(String In) { + return In.toLowerCase().trim(); + } + + private static String getResponse(String Cli) { + Set key = Siri.keySet(); + for (String keys : key) { + if (Cli.contains(keys)) { + return Siri.get(keys); + } + } + return "I'm sorry, I don't understand that. Could you please rephrase your question?"; + } + + public static void main(String[] args) { + System.out.println("Siri Initialized"); + Scanner sc = new Scanner(System.in); + String UsI; + while (true) { + System.out.print("You : "); + UsI = sc.nextLine(); + if (UsI.equalsIgnoreCase("bye")) { + String farewell = getResponse(preprocessInput(UsI)); + System.out.println("Bot: " + farewell); + break; + } + String cleanedInput = preprocessInput(UsI); + String botResponse = getResponse(cleanedInput); + System.out.println("Bot: " + botResponse); + } + sc.close(); + System.out.println("Siri session ended."); + } +} diff --git a/.history/java/HeapSort_20251011141215.java b/.history/java/HeapSort_20251011141215.java new file mode 100644 index 00000000..e69de29b diff --git a/.history/java/HeapSort_20251011141222.java b/.history/java/HeapSort_20251011141222.java new file mode 100644 index 00000000..67700708 --- /dev/null +++ b/.history/java/HeapSort_20251011141222.java @@ -0,0 +1,3 @@ +public class HeapSort { + +} diff --git a/.history/java/HeapSort_20251011141235.java b/.history/java/HeapSort_20251011141235.java new file mode 100644 index 00000000..466984f8 --- /dev/null +++ b/.history/java/HeapSort_20251011141235.java @@ -0,0 +1,65 @@ +public class HeapSort { + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/LeadersInArr_20251011135825.java b/.history/java/LeadersInArr_20251011135825.java new file mode 100644 index 00000000..e69de29b diff --git a/.history/java/LeadersInArr_20251011135904.java b/.history/java/LeadersInArr_20251011135904.java new file mode 100644 index 00000000..ffea86c6 --- /dev/null +++ b/.history/java/LeadersInArr_20251011135904.java @@ -0,0 +1,24 @@ +import java.util.*; + +public class LeadersInArr { + + public static void main(String[] args) { + int[] arr = { 16, 17, 4, 3, 5, 2 }; + int n = arr.length; + List leaders = new ArrayList<>(); + + int maxFromRight = arr[n - 1]; + leaders.add(maxFromRight); + + for (int i = n - 2; i >= 0; i--) { + if (arr[i] >= maxFromRight) { + maxFromRight = arr[i]; + leaders.add(maxFromRight); + } + } + + // Reverse to get leaders in correct order + Collections.reverse(leaders); + System.out.println(leaders); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140107.java b/.history/java/Sorting/HeapSort_20251011140107.java new file mode 100644 index 00000000..e69de29b diff --git a/.history/java/Sorting/HeapSort_20251011140130.java b/.history/java/Sorting/HeapSort_20251011140130.java new file mode 100644 index 00000000..e12bba85 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140130.java @@ -0,0 +1,68 @@ +package Sorting; + +public class HeapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140206.java b/.history/java/Sorting/HeapSort_20251011140206.java new file mode 100644 index 00000000..e95655d5 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140206.java @@ -0,0 +1,68 @@ +package Sorting; + +public class HeapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void HeapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140225.java b/.history/java/Sorting/HeapSort_20251011140225.java new file mode 100644 index 00000000..171d6a58 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140225.java @@ -0,0 +1,68 @@ +package Sorting; + +public class HeapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void HeapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + HeapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140327.java b/.history/java/Sorting/HeapSort_20251011140327.java new file mode 100644 index 00000000..7b361a0d --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140327.java @@ -0,0 +1,67 @@ +package Sorting; + +public class HeapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140402.java b/.history/java/Sorting/HeapSort_20251011140402.java new file mode 100644 index 00000000..bfc8c27a --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140402.java @@ -0,0 +1,67 @@ +package Sorting; + +public class heapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140409.java b/.history/java/Sorting/HeapSort_20251011140409.java new file mode 100644 index 00000000..bfc8c27a --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140409.java @@ -0,0 +1,67 @@ +package Sorting; + +public class heapSort { + + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140505.java b/.history/java/Sorting/HeapSort_20251011140505.java new file mode 100644 index 00000000..74c0a4b6 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140505.java @@ -0,0 +1,5 @@ +package Sorting; + +public class HeapSort { + +} diff --git a/.history/java/Sorting/HeapSort_20251011140530.java b/.history/java/Sorting/HeapSort_20251011140530.java new file mode 100644 index 00000000..245d6eed --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140530.java @@ -0,0 +1,5 @@ +package Sorting; + +public class heapSort { + +} diff --git a/.history/java/Sorting/HeapSort_20251011140554.java b/.history/java/Sorting/HeapSort_20251011140554.java new file mode 100644 index 00000000..9780ed92 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140554.java @@ -0,0 +1,67 @@ +package Sorting; + +public class heapSort { + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140931.java b/.history/java/Sorting/HeapSort_20251011140931.java new file mode 100644 index 00000000..20ce7664 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140931.java @@ -0,0 +1,67 @@ +package Sorting; + +public class HeapSort { + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.history/java/Sorting/HeapSort_20251011140956.java b/.history/java/Sorting/HeapSort_20251011140956.java new file mode 100644 index 00000000..20ce7664 --- /dev/null +++ b/.history/java/Sorting/HeapSort_20251011140956.java @@ -0,0 +1,67 @@ +package Sorting; + +public class HeapSort { + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..9874d5a6 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,6 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +.DS_Store \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..a9182a4b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..48cf27df --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 6518751f..761fe0a0 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,20 +1,20 @@ { - "configurations": [ - { - "name": "Win32", - "includePath": [ - "${workspaceFolder}/**" - ], - "defines": [ - "_DEBUG", - "UNICODE", - "_UNICODE" - ], - "compilerPath": "cl.exe", - "cStandard": "c17", - "cppStandard": "c++17", - "intelliSenseMode": "windows-msvc-x64" - } - ], - "version": 4 + "configurations": [ + { + "name": "windows-gcc-x64", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "compilerPath": "C:/MinGW/mingw32/bin/gcc.exe", + "cStandard": "${default}", + "cppStandard": "${default}", + "intelliSenseMode": "windows-gcc-x64" + } + ], + "version": 4 } \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..9c6e62fc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,138 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "java", + "name": "JobScheduling1", + "request": "launch", + "mainClass": "JobScheduling1", + "projectName": "dsa-code_163e7579" + }, + { + "type": "java", + "name": "JobScheduling", + "request": "launch", + "mainClass": "JobScheduling", + "projectName": "dsa-code_163e7579" + "name": "CountVowels", + "request": "launch", + "mainClass": "CountVowels", + "projectName": "dsa-code_26e89efe" + }, + { + "type": "java", + "name": "Permutations", + "request": "launch", + "mainClass": "Permutations", + "projectName": "dsa-code_26e89efe" + }, + { + "type": "java", + "name": "LongestSubstring", + "request": "launch", + "mainClass": "LongestSubstring", + "projectName": "dsa-code_26e89efe" + }, + { + "type": "java", + "name": "MaximumSubarray", + "request": "launch", + "mainClass": "MaximumSubarray", + "projectName": "dsa-code_26e89efe" + }, + { + "type": "java", + "name": "mergeTwoLists", + "request": "launch", + "mainClass": "mergeTwoLists", + "projectName": "dsa-code_26e89efe" + }, + { + "type": "java", + "name": "Main", + "request": "launch", + "mainClass": "Main", + "projectName": "dsa-code_26e89efe" + }, + { + "name": "Java", + "type": "java", + "request": "launch", + "stopOnEntry": true, + "jdkPath": "${env:JAVA_HOME}/bin", + "cwd": "${fileDirname}", + "startupClass": "${fileBasenameNoExtension}", + "classpath": [ + ".", + "${fileDirname}" + ] + }, + { + "name": "Java Console App", + "type": "java", + "request": "launch", + "stopOnEntry": true, + "jdkPath": "${env:JAVA_HOME}/bin", + "cwd": "${fileDirname}", + "startupClass": "${fileBasenameNoExtension}", + "classpath": [ + ".", + "${fileDirname}" + ], + "externalConsole": true + }, + { + "type": "java", + "name": "Current File", + "request": "launch", + "mainClass": "${file}" + }, + { + "type": "java", + "name": "RotateImage", + "request": "launch", + "mainClass": "RotateImage", + "projectName": "dsa-code_cb401e8" + }, + { + "type": "java", + "name": "Secondlargest", + "request": "launch", + "mainClass": "Secondlargest", + "projectName": "dsa-code_cb401e8" + }, + { + "type": "java", + "name": "Sort_Ascending_Order", + "request": "launch", + "mainClass": "Sort_Ascending_Order", + "projectName": "dsa-code_cb401e8" + }, + { + "type": "java", + "name": "hellowordl", + "request": "launch", + "mainClass": "hellowordl", + "projectName": "dsa-code_cb401e8" + }, + { + "name": "C/C++ Runner: Debug Session", + "type": "cppdbg", + "request": "launch", + "args": [], + "stopAtEntry": false, + "externalConsole": true, + "cwd": "c:/Users/ujesh/OneDrive/Documents/blockparty/dsa-code", + "program": "c:/Users/ujesh/OneDrive/Documents/blockparty/dsa-code/build/Debug/outDebug", + "MIMode": "gdb", + "miDebuggerPath": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 70e34ecb..fcdea0f5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,61 @@ { - "C_Cpp.errorSquiggles": "disabled" -} \ No newline at end of file + "C_Cpp.errorSquiggles": "disabled", + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.cStandard": "", + "C_Cpp_Runner.cppStandard": "", + "C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": ["*", "**/*"], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false, + "java.debug.settings.onBuildFailureProceed": true, + "files.associations": { + "ostream": "cpp" + } +} diff --git a/75-Dsa-Problems/Binary-Search/Arranging_coins.cpp b/75-Dsa-Problems/Binary-Search/Arranging_coins.cpp new file mode 100644 index 00000000..f30f65ec --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/Arranging_coins.cpp @@ -0,0 +1,11 @@ +class Solution { + public int arrangeCoins(int n) { + int level = 0, coin = 1; + while (n >= coin) { + n -= coin; + coin++; + level++; + } + return level; + } +} \ No newline at end of file diff --git a/75-Dsa-Problems/Binary-Search/FindMinRotatedArray.cpp b/75-Dsa-Problems/Binary-Search/FindMinRotatedArray.cpp new file mode 100644 index 00000000..e43d0c73 --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/FindMinRotatedArray.cpp @@ -0,0 +1,59 @@ +// 153. Find Minimum in Rotated Sorted Array -- leetcode + +#include +using namespace std; + +class Solution +{ +public: + int findPivot(vector &nums, int l, int r) + { + while (l < r && nums[l] == nums[l + 1]) + l++; + while (l < r && nums[r] == nums[r - 1]) + r--; + while (l < r) + { + int mid = l + (r - l) / 2; + if (nums[mid] > nums[r]) + l = mid + 1; + else + r = mid; + } + return l; + } + + bool binarySearch(vector &nums, int l, int r, int target) + { + while (l <= r) + { + int mid = l + (r - l) / 2; + if (nums[mid] == target) + return true; + else if (nums[mid] < target) + l = mid + 1; + else + r = mid - 1; + } + return false; + } + + bool search(vector &nums, int target) + { + int n = nums.size(); + if (n == 0) + return false; + int pivot = findPivot(nums, 0, n - 1); + if (binarySearch(nums, 0, pivot - 1, target)) + return true; + return binarySearch(nums, pivot, n - 1, target); + } +}; + +int main() +{ + Solution s; + vector nums = {4, 5, 6, 7, 0, 1, 2}; + int target = 0; + cout << (s.search(nums, target) ? "Found" : "Not Found") << endl; +} diff --git a/75-Dsa-Problems/Binary-Search/FindPeak.cpp b/75-Dsa-Problems/Binary-Search/FindPeak.cpp new file mode 100644 index 00000000..d4a83bbc --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/FindPeak.cpp @@ -0,0 +1,34 @@ +// 162. Find Peak Element -- leetcode + +#include +using namespace std; + +class Solution +{ +public: + int findPeakElement(vector &nums) + { + int l = 0; + int r = nums.size() - 1; + while (l < r) + { + int mid = (l + r) / 2; + if (nums[mid] < nums[mid + 1]) + { + l = mid + 1; + } + else + { + r = mid; + } + } + return r; + } +}; + +int main() +{ + Solution s; + vector nums = {1, 2, 3, 1}; + cout << "Peak element index: " << s.findPeakElement(nums) << endl; +} diff --git a/75-Dsa-Problems/Binary-Search/graph/NumberOfIslands.cpp b/75-Dsa-Problems/Binary-Search/graph/NumberOfIslands.cpp new file mode 100644 index 00000000..5777d2b9 --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/graph/NumberOfIslands.cpp @@ -0,0 +1,93 @@ +// LeetCode 200: Number of Islands +// Issue #1063 +// Solved using Depth First Search (DFS) +// Time Complexity: O(m * n) + +#include +#include + +using namespace std; + +class Solution { +private: + /** + * @brief Helper function to perform DFS on the grid. + * This function will "sink" an island by turning all '1's to '0's. + * @param grid The 2D grid of land and water. + * @param r The current row index. + * @param c The current column index. + */ + void dfs(vector>& grid, int r, int c) { + int numRows = grid.size(); + int numCols = grid[0].size(); + + // Base cases (check for out-of-bounds or if it's water) + if (r < 0 || c < 0 || r >= numRows || c >= numCols || grid[r][c] == '0') { + return; + } + + // Mark the current cell as visited (sink it) + grid[r][c] = '0'; + + // Recursively call DFS on all 4 neighbors + dfs(grid, r + 1, c); // down + dfs(grid, r - 1, c); // up + dfs(grid, r, c + 1); // right + dfs(grid, r, c - 1); // left + } + +public: + /** + * @brief Counts the number of islands in a 2D grid. + * @param grid The 2D grid of '1's (land) and '0's (water). + * @return The total number of islands. + */ + int numIslands(vector>& grid) { + if (grid.empty() || grid[0].empty()) { + return 0; + } + + int numRows = grid.size(); + int numCols = grid[0].size(); + int islandCount = 0; + + // Iterate through every cell in the grid + for (int i = 0; i < numRows; ++i) { + for (int j = 0; j < numCols; ++j) { + // If we find land ('1'), it's a new island + if (grid[i][j] == '1') { + islandCount++; + // Use DFS to sink the entire island so we don't count it again + dfs(grid, i, j); + } + } + } + + return islandCount; + } +}; + +// Main function to test the code +int main() { + Solution sol; + + // Test Case 1 + vector> grid1 = { + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'} + }; + cout << "Test Case 1: Number of Islands = " << sol.numIslands(grid1) << endl; // Expected: 1 + + // Test Case 2 (Create a copy as numIslands modifies the grid) + vector> grid2 = { + {'1', '1', '0', '0', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '1', '0', '0'}, + {'0', '0', '0', '1', '1'} + }; + cout << "Test Case 2: Number of Islands = " << sol.numIslands(grid2) << endl; // Expected: 3 + + return 0; +} \ No newline at end of file diff --git a/75-Dsa-Problems/Binary-Search/kokoEating.cpp b/75-Dsa-Problems/Binary-Search/kokoEating.cpp new file mode 100644 index 00000000..6369b79a --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/kokoEating.cpp @@ -0,0 +1,49 @@ +// 875. Koko Eating Bananas + +#include +using namespace std; + +class Solution +{ +public: + bool canEatAll(vector &piles, int mid, int h) + { + long long totalHours = 0; + for (int x : piles) + { + totalHours += x / mid; + if (x % mid != 0) + totalHours++; + } + return totalHours <= h; + } + + int minEatingSpeed(vector &piles, int h) + { + int l = 1; + int r = *max_element(piles.begin(), piles.end()); + + while (l < r) + { + int mid = l + (r - l) / 2; + if (canEatAll(piles, mid, h)) + { + r = mid; + } + else + { + l = mid + 1; + } + } + return l; + } +}; + +int main() +{ + Solution s; + vector piles = {3, 6, 7, 11}; + int h = 8; + + cout << "Minimum eating speed: " << s.minEatingSpeed(piles, h) << endl; +} diff --git a/75-Dsa-Problems/Binary-Search/searchRotatedArray.cpp b/75-Dsa-Problems/Binary-Search/searchRotatedArray.cpp new file mode 100644 index 00000000..0afb4a98 --- /dev/null +++ b/75-Dsa-Problems/Binary-Search/searchRotatedArray.cpp @@ -0,0 +1,73 @@ +// 81. Search in Rotated Sorted Array II -- leetcode + +#include +using namespace std; + +class Solution +{ +public: + + int findPivot(vector &nums, int l, int r) + { + + while (l < r && nums[l] == nums[l + 1]) + l++; + while (l < r && nums[r] == nums[r - 1]) + r--; + + + while (l < r) + { + int mid = l + (r - l) / 2; + if (nums[mid] > nums[r]) + { + l = mid + 1; + } + else + { + r = mid; + } + } + return l; + } + + + bool binarySearch(vector &nums, int l, int r, int target) + { + while (l <= r) + { + int mid = l + (r - l) / 2; + if (nums[mid] == target) + return true; + else if (nums[mid] < target) + l = mid + 1; + else + r = mid - 1; + } + return false; + } + + + bool search(vector &nums, int target) + { + int n = nums.size(); + if (n == 0) + return false; + + int pivot = findPivot(nums, 0, n - 1); + + + if (binarySearch(nums, 0, pivot - 1, target)) + return true; + return binarySearch(nums, pivot, n - 1, target); + } +}; + +int main() +{ + Solution s; + vector nums = {4, 5, 6, 7, 0, 1, 2}; + int target = 0; + + cout << (s.search(nums, target) ? "Found" : "Not Found") << endl; +} diff --git a/Add Code Here/.DS_Store b/Add Code Here/.DS_Store new file mode 100644 index 00000000..c864ab62 Binary files /dev/null and b/Add Code Here/.DS_Store differ diff --git a/Add Code Here/JAVA/AnagramChecker.java b/Add Code Here/JAVA/AnagramChecker.java new file mode 100644 index 00000000..4256fce7 --- /dev/null +++ b/Add Code Here/JAVA/AnagramChecker.java @@ -0,0 +1,209 @@ +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * Anagram Checker - Multiple approaches to verify if two strings are anagrams + * + * An anagram is a word formed by rearranging letters of another word, + * using all original letters exactly once. + * + * Example: "listen" and "silent" are anagrams + * + * @author Prince Yadav + * @version 2.0 + * @since October 2025 + */ +public class AnagramChecker { + + /** + * Checks if two strings are anagrams using HashMap (case-insensitive) + * Ignores non-alphabetic characters and whitespace + * + * Time Complexity: O(n + m) where n, m are lengths of strings + * Space Complexity: O(k) where k is number of unique characters + * + * @param word1 First string to compare + * @param word2 Second string to compare + * @return true if strings are anagrams, false otherwise + */ + public static boolean isAnagram(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + // Remove non-alpha characters and convert to lowercase + word1 = word1.replaceAll("[^a-zA-Z]", "").toLowerCase(); + word2 = word2.replaceAll("[^a-zA-Z]", "").toLowerCase(); + + // Quick length check + if (word1.length() != word2.length()) { + return false; + } + + // Count character frequencies + Map charCount = new HashMap<>(); + + for (char c : word1.toCharArray()) { + charCount.put(c, charCount.getOrDefault(c, 0) + 1); + } + + for (char c : word2.toCharArray()) { + if (!charCount.containsKey(c)) { + return false; + } + + int count = charCount.get(c) - 1; + if (count == 0) { + charCount.remove(c); + } else { + charCount.put(c, count); + } + } + + return charCount.isEmpty(); + } + + /** + * Alternative approach using sorting (simpler but slightly less efficient) + * + * Time Complexity: O(n log n) + * Space Complexity: O(n) for character arrays + * + * @param word1 First string + * @param word2 Second string + * @return true if anagrams + */ + public static boolean isAnagramSorting(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + word1 = word1.replaceAll("[^a-zA-Z]", "").toLowerCase(); + word2 = word2.replaceAll("[^a-zA-Z]", "").toLowerCase(); + + if (word1.length() != word2.length()) { + return false; + } + + char[] arr1 = word1.toCharArray(); + char[] arr2 = word2.toCharArray(); + + Arrays.sort(arr1); + Arrays.sort(arr2); + + return Arrays.equals(arr1, arr2); + } + + /** + * Optimized approach using character frequency array (for lowercase letters only) + * Most efficient for simple anagram checking + * + * Time Complexity: O(n) + * Space Complexity: O(1) - fixed 26 character array + * + * @param word1 First string + * @param word2 Second string + * @return true if anagrams + */ + public static boolean isAnagramOptimized(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + word1 = word1.replaceAll("[^a-zA-Z]", "").toLowerCase(); + word2 = word2.replaceAll("[^a-zA-Z]", "").toLowerCase(); + + if (word1.length() != word2.length()) { + return false; + } + + int[] charFreq = new int[26]; // For 'a' to 'z' + + for (int i = 0; i < word1.length(); i++) { + charFreq[word1.charAt(i) - 'a']++; + charFreq[word2.charAt(i) - 'a']--; + } + + for (int count : charFreq) { + if (count != 0) { + return false; + } + } + + return true; + } + + /** + * Prints test result in formatted manner + */ + private static void testAnagram(String word1, String word2) { + boolean result1 = isAnagram(word1, word2); + boolean result2 = isAnagramSorting(word1, word2); + boolean result3 = isAnagramOptimized(word1, word2); + + System.out.printf("%-20s | %-20s | HashMap: %-5s | Sorting: %-5s | Optimized: %-5s%n", + "\"" + word1 + "\"", "\"" + word2 + "\"", + result1, result2, result3); + } + + public static void main(String[] args) { + System.out.println("=== Anagram Checker Test Cases ===\n"); + System.out.printf("%-20s | %-20s | %-14s | %-14s | %-14s%n", + "Word 1", "Word 2", "HashMap", "Sorting", "Optimized"); + System.out.println("-".repeat(95)); + + // Basic anagrams + testAnagram("evil", "vile"); + testAnagram("angel", "glean"); + testAnagram("listen", "silent"); + + // With spaces and punctuation + testAnagram("school master", "the classroom"); + testAnagram("conversation", "voices rant on"); + + // Not anagrams + testAnagram("listen", "hearing"); + testAnagram("hello", "world"); + + // Edge cases + testAnagram("", ""); + testAnagram("a", "a"); + testAnagram("abc", "def"); + + System.out.println("\n=== Performance Comparison ===\n"); + + String str1 = "astronomer"; + String str2 = "moon starer"; + + // Benchmark HashMap approach + long start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagram(str1, str2); + } + long hashMapTime = System.nanoTime() - start; + + // Benchmark Sorting approach + start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagramSorting(str1, str2); + } + long sortingTime = System.nanoTime() - start; + + // Benchmark Optimized approach + start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagramOptimized(str1, str2); + } + long optimizedTime = System.nanoTime() - start; + + System.out.printf("HashMap approach: %d ms%n", hashMapTime / 1_000_000); + System.out.printf("Sorting approach: %d ms%n", sortingTime / 1_000_000); + System.out.printf("Optimized approach: %d ms%n", optimizedTime / 1_000_000); + + System.out.println("\nRecommendation:"); + System.out.println("- Use Optimized (array) for simple lowercase anagrams"); + System.out.println("- Use HashMap for Unicode/multilingual support"); + System.out.println("- Use Sorting for simplicity and readability"); + } +} \ No newline at end of file diff --git a/Add Code Here/JAVA/BinarySearch.java b/Add Code Here/JAVA/BinarySearch.java new file mode 100644 index 00000000..d0dd5b03 --- /dev/null +++ b/Add Code Here/JAVA/BinarySearch.java @@ -0,0 +1,70 @@ +// Program: Binary Search in Java +// Purpose: To find whether a given number exists in a sorted array using Binary Search technique + +import java.util.Scanner; // Import Scanner class for user input + +public class Binary_Search +{ + public static void main(String args[]) + { + Scanner sc = new Scanner(System.in); // Create a Scanner object for input + + int i = 0, flag = 0; // 'flag' variable will be used to indicate if element is found or not + + // Step 1: Initialize a sorted array (Binary Search works only on sorted arrays) + int a[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; + + // Step 2: Display the array elements + System.out.println("Array elements are:"); + for(i = 0; i < 10; i++) + { + System.out.println(a[i]); + } + + // Step 3: Ask the user to enter the number to search + System.out.println("Enter a number to search:"); + int num = sc.nextInt(); + + // Step 4: Initialize variables for binary search + int f = 0; // 'f' represents the first index + int l = 9; // 'l' represents the last index + int m = 0; // 'm' represents the middle index + + // Step 5: Perform Binary Search using while loop + while(f <= l) + { + m = (f + l) / 2; // Calculate middle index + + // Case 1: Element found at mid position + if(num == a[m]) + { + flag = 1; // Mark flag as found + break; // Exit loop + } + + // Case 2: If element is smaller than middle value, search in left half + else if(num < a[m]) + { + l = m - 1; + } + + // Case 3: If element is greater than middle value, search in right half + else + { + f = m + 1; + } + } + + // Step 6: Display result based on flag value + if(flag == 0) + { + System.out.println("Search element not found"); + } + else + { + System.out.println("Search element found at cell number " + (m + 1)); + } + + sc.close(); // Close Scanner object to prevent memory leak + } +} diff --git a/Add Code Here/JAVA/BubbleSort_ascending.java b/Add Code Here/JAVA/BubbleSort_ascending.java new file mode 100644 index 00000000..591bc9b7 --- /dev/null +++ b/Add Code Here/JAVA/BubbleSort_ascending.java @@ -0,0 +1,24 @@ +import java.util.Scanner; + +public class BubbleSort_ascending +{ + public static void main(String args[]) + { + + Scanner sc = new Scanner(System.in); // Create Scanner object for user input + int i = 0, j = 0, temp = 0; // Declare loop variables and temporary variable for swapping + int a[] = new int[5]; // Declare an integer array of size 5 + + // Take input from the user + System.out.println("Enter 5 numbers: "); + for(i = 0; i < 5; i++) + { + a[i] = sc.nextInt(); // Read each number and store in array + } + + // Display array before sorting + System.out.println("Array before sorting: "); + for(i = 0; i < 5; i++) + { + System.out.print(a[i] + ","); // Print each element separated by a comma + } diff --git a/Add Code Here/JAVA/CycleSort.class b/Add Code Here/JAVA/CycleSort.class new file mode 100644 index 00000000..303a4967 Binary files /dev/null and b/Add Code Here/JAVA/CycleSort.class differ diff --git a/Add Code Here/JAVA/CycleSort.java b/Add Code Here/JAVA/CycleSort.java new file mode 100644 index 00000000..cda7f6c2 --- /dev/null +++ b/Add Code Here/JAVA/CycleSort.java @@ -0,0 +1,82 @@ +import java.util.Scanner; +import java.util.Arrays; + +/** + * 🚀 Cycle Sort Implementation + * + * Sorts an array of distinct integers (1 to n) using Cycle Sort. + * Validates input and handles errors gracefully. + * + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * Example: + * Input: 3 1 5 4 2 + * Output: 1 2 3 4 5 + * + * Author: Prince Yadav + * Version: 2.0 + */ +public class CycleSort { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + System.out.println("Enter number of elements (distinct numbers 1 to n):"); + int n = sc.nextInt(); + if (n <= 0) { + System.out.println("Error: Number of elements must be positive."); + sc.close(); + return; + } + + int[] arr = new int[n]; + System.out.println("Enter elements in the array:"); + for (int i = 0; i < n; i++) { + arr[i] = sc.nextInt(); + if (arr[i] < 1 || arr[i] > n) { + System.out.println("Error: Elements must be distinct numbers from 1 to " + n); + sc.close(); + return; + } + } + + cycleSort(arr); + + System.out.println("Sorted array:"); + for (int num : arr) { + System.out.print(num + " "); + } + System.out.println(); + + sc.close(); + } + + /** + * Cycle Sort algorithm + * Sorts an array of distinct integers 1 to n + * @param arr Input array + */ + public static void cycleSort(int[] arr) { + for (int i = 0; i < arr.length; i++) { + while (arr[i] != i + 1) { + int correct = arr[i] - 1; + if (arr[correct] == arr[i]) break; // Prevent infinite loop + int temp = arr[i]; + arr[i] = arr[correct]; + arr[correct] = temp; + } + } + } + + /** + * Utility method for testing + * @param arr input array + * @return sorted array (copy) + */ + public static int[] sortArray(int[] arr) { + int[] copy = Arrays.copyOf(arr, arr.length); + cycleSort(copy); + return copy; + } +} diff --git a/Add Code Here/JAVA/EvenOddChecker.java b/Add Code Here/JAVA/EvenOddChecker.java new file mode 100644 index 00000000..ece1c0a5 --- /dev/null +++ b/Add Code Here/JAVA/EvenOddChecker.java @@ -0,0 +1,31 @@ +/* + * Program: Even or Odd Checker + * Author: Akshat Patil + * Date: October 27, 2025 + * Description: + * This program takes an integer input from the user + * and checks whether it is even or odd using the modulus operator. + */ + +import java.util.Scanner; + +public class EvenOddChecker { + public static void main(String[] args) { + + // Create Scanner object to take input from user + Scanner scanner = new Scanner(System.in); + + System.out.print("Enter a number: "); + int number = scanner.nextInt(); // Input from user + + // Check whether the number is even or odd + if (number % 2 == 0) { + System.out.println(number + " is an Even number."); + } else { + System.out.println(number + " is an Odd number."); + } + + // Close the scanner to prevent resource leaks + scanner.close(); + } +} diff --git a/Add Code Here/JAVA/FibonacciMemoization.java b/Add Code Here/JAVA/FibonacciMemoization.java new file mode 100644 index 00000000..3adb0b24 --- /dev/null +++ b/Add Code Here/JAVA/FibonacciMemoization.java @@ -0,0 +1,146 @@ +/** + * Fibonacci Number Calculator using Dynamic Programming (Memoization) + * + * Problem: Calculate nth Fibonacci number efficiently + * Approach: Top-down DP with memoization to avoid recalculation + * + * Time Complexity: O(n) + * Space Complexity: O(n) + * + * @author Prince Yadav + * @version 1.0 + * @since October 2025 + */ +public class FibonacciMemoization { + + // Cache array to store computed Fibonacci numbers + private static long[] memo; + + /** + * Calculates nth Fibonacci number using memoization + * Formula: F(n) = F(n-1) + F(n-2) + * Base cases: F(0) = 0, F(1) = 1 + * + * @param n The position in Fibonacci sequence (0-indexed) + * @return The nth Fibonacci number + * @throws IllegalArgumentException if n is negative + */ + public static long fibonacci(int n) { + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative"); + } + + // Base cases + if (n <= 1) { + return n; + } + + // Return cached value if already computed + if (memo[n] != 0) { + return memo[n]; + } + + // Compute and cache the result + long fibNumber = fibonacci(n - 1) + fibonacci(n - 2); + memo[n] = fibNumber; + + return fibNumber; + } + + /** + * Alternative iterative approach (more efficient) + * Time: O(n), Space: O(1) + * + * @param n Position in sequence + * @return nth Fibonacci number + */ + public static long fibonacciIterative(int n) { + if (n < 0) { + throw new IllegalArgumentException("n must be non-negative"); + } + + if (n <= 1) { + return n; + } + + long prev2 = 0; + long prev1 = 1; + long current = 0; + + for (int i = 2; i <= n; i++) { + current = prev1 + prev2; + prev2 = prev1; + prev1 = current; + } + + return current; + } + + /** + * Initializes memoization array + * + * @param size Size of memo array (n+1) + */ + private static void initializeMemo(int size) { + memo = new long[size + 1]; + } + + /** + * Prints the entire Fibonacci sequence up to n + * + * @param n Upper limit + */ + public static void printFibonacciSequence(int n) { + System.out.println("Fibonacci Sequence up to F(" + n + "):"); + for (int i = 0; i <= n; i++) { + System.out.printf("F(%d) = %d%n", i, memo[i]); + } + } + + /** + * Main method demonstrating usage with multiple test cases + */ + public static void main(String[] args) { + // Test Case 1: Basic calculation + System.out.println("=== Test Case 1: Calculate F(50) ==="); + int n = 50; + initializeMemo(n); + + long result = fibonacci(n); + System.out.println("F(" + n + ") = " + result); + System.out.println(); + + // Test Case 2: Print first 15 Fibonacci numbers + System.out.println("=== Test Case 2: First 15 Numbers ==="); + initializeMemo(15); + for (int i = 0; i <= 15; i++) { + System.out.printf("F(%2d) = %d%n", i, fibonacci(i)); + } + System.out.println(); + + // Test Case 3: Compare both approaches + System.out.println("=== Test Case 3: Compare Approaches ==="); + int testN = 40; + initializeMemo(testN); + + long startTime = System.nanoTime(); + long memoResult = fibonacci(testN); + long memoTime = System.nanoTime() - startTime; + + startTime = System.nanoTime(); + long iterResult = fibonacciIterative(testN); + long iterTime = System.nanoTime() - startTime; + + System.out.println("Memoization: F(" + testN + ") = " + memoResult + + " (Time: " + memoTime/1000 + " μs)"); + System.out.println("Iterative: F(" + testN + ") = " + iterResult + + " (Time: " + iterTime/1000 + " μs)"); + System.out.println(); + + // Test Case 4: Edge cases + System.out.println("=== Test Case 4: Edge Cases ==="); + System.out.println("F(0) = " + fibonacciIterative(0)); // Expected: 0 + System.out.println("F(1) = " + fibonacciIterative(1)); // Expected: 1 + System.out.println("F(2) = " + fibonacciIterative(2)); // Expected: 1 + } +} \ No newline at end of file diff --git a/Add Code Here/JAVA/MergeSort.class b/Add Code Here/JAVA/MergeSort.class new file mode 100644 index 00000000..3a8a0fd2 Binary files /dev/null and b/Add Code Here/JAVA/MergeSort.class differ diff --git a/Add Code Here/JAVA/MergeSort.java b/Add Code Here/JAVA/MergeSort.java new file mode 100644 index 00000000..f1174148 --- /dev/null +++ b/Add Code Here/JAVA/MergeSort.java @@ -0,0 +1,48 @@ +public class MergeSort { + + public static void mergeInPlace(int arr[], int start, int mid, int end) { + int start2 = mid + 1; + if (arr[mid] <= arr[start2]) return; + + while (start <= mid && start2 <= end) { + if (arr[start] <= arr[start2]) { + start++; + } else { + int value = arr[start2]; + int index = start2; + + while (index != start) { + arr[index] = arr[index - 1]; + index--; + } + arr[start] = value; + + start++; + mid++; + start2++; + } + } + } + + public static void mergeSort(int arr[], int l, int r) { + if (l >= r) return; + + int m = l + (r - l) / 2; + mergeSort(arr, l, m); + mergeSort(arr, m + 1, r); + mergeInPlace(arr, l, m, r); + } + + public static void main(String[] args) { + int arr[] = {6, 3, 9, 5, 2, 8}; + int n = arr.length; + + mergeSort(arr, 0, n - 1); + + System.out.println("Sorted array:"); + for (int num : arr) { + System.out.print(num + " "); + } + System.out.println(); + } +} diff --git a/Add Code Here/JAVA/ReverseArray.java b/Add Code Here/JAVA/ReverseArray.java new file mode 100644 index 00000000..c5dd06e6 --- /dev/null +++ b/Add Code Here/JAVA/ReverseArray.java @@ -0,0 +1,20 @@ +// Author: Sohum Seth +// Problem: Reverse an Array +// Language: Java + +import java.util.*; + +public class ReverseArray { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter number of elements: "); + int n = sc.nextInt(); + int[] arr = new int[n]; + + System.out.println("Enter elements:"); + for (int i = 0; i < n; i++) arr[i] = sc.nextInt(); + + System.out.print("Reversed array: "); + for (int i = n - 1; i >= 0; i--) System.out.print(arr[i] + " "); + } +} diff --git a/Algorithms/dijkstra.py b/Algorithms/dijkstra.py new file mode 100644 index 00000000..08d0a47f --- /dev/null +++ b/Algorithms/dijkstra.py @@ -0,0 +1,44 @@ +import heapq + +def dijkstra(graph, start): + """ + Dijkstra's algorithm to find shortest paths from start node to all other nodes. + + Parameters: + graph : dict - adjacency list {node: [(neighbor, weight), ...]} + start : starting node + + Returns: + distances : dict - shortest distance from start to each node + """ + + distances = {node: float('inf') for node in graph} + distances[start] = 0 + + priority_queue = [(0, start)] # (distance, node) + + while priority_queue: + current_distance, current_node = heapq.heappop(priority_queue) + + if current_distance > distances[current_node]: + continue + + for neighbor, weight in graph[current_node]: + distance = current_distance + weight + + if distance < distances[neighbor]: + distances[neighbor] = distance + heapq.heappush(priority_queue, (distance, neighbor)) + + return distances + +# Example usage: +if __name__ == "__main__": + graph = { + 'A': [('B', 1), ('C', 4)], + 'B': [('A', 1), ('C', 2), ('D', 5)], + 'C': [('A', 4), ('B', 2), ('D', 1)], + 'D': [('B', 5), ('C', 1)] + } + start_node = 'A' + print("Shortest distances:", dijkstra(graph, start_node)) diff --git a/AreaCalculator.class b/AreaCalculator.class new file mode 100644 index 00000000..150201d4 Binary files /dev/null and b/AreaCalculator.class differ diff --git a/AreaCalculator.java b/AreaCalculator.java new file mode 100644 index 00000000..48cf5226 --- /dev/null +++ b/AreaCalculator.java @@ -0,0 +1,55 @@ +import java.util.Scanner; + +public class AreaCalculator { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int choice; + + do { + System.out.println("\n--- Area Calculator ---"); + System.out.println("1. Circle"); + System.out.println("2. Rectangle"); + System.out.println("3. Triangle"); + System.out.println("4. Exit"); + System.out.print("Enter your choice: "); + choice = sc.nextInt(); + + switch (choice) { + case 1: + System.out.print("Enter radius of circle: "); + double radius = sc.nextDouble(); + double circleArea = 3.14159 * radius * radius; + System.out.println("Area of Circle = " + circleArea); + break; + + case 2: + System.out.print("Enter length of rectangle: "); + double length = sc.nextDouble(); + System.out.print("Enter width of rectangle: "); + double width = sc.nextDouble(); + double rectArea = length * width; + System.out.println("Area of Rectangle = " + rectArea); + break; + + case 3: + System.out.print("Enter base of triangle: "); + double base = sc.nextDouble(); + System.out.print("Enter height of triangle: "); + double height = sc.nextDouble(); + double triArea = 0.5 * base * height; + System.out.println("Area of Triangle = " + triArea); + break; + + case 4: + System.out.println("Exiting program. Goodbye!"); + break; + + default: + System.out.println("Invalid choice! Please try again."); + } + + } while (choice != 4); + + sc.close(); + } +} diff --git a/Best Time to Buy and Sell Stock.cpp b/Best Time to Buy and Sell Stock.cpp new file mode 100644 index 00000000..635de3a8 --- /dev/null +++ b/Best Time to Buy and Sell Stock.cpp @@ -0,0 +1,13 @@ + class Solution { +public: + int maxProfit(vector& prices) { + if(prices.empty()) return 0; + int minPrice = prices[0]; + int maxProfit = 0; + for(int i=1; i current_node.value: + # --- Go Right --- + if current_node.right is None: + # If there's no right child, insert here + current_node.right = Node(value) + else: + # Otherwise, keep going down the right subtree + self._insert_recursive(current_node.right, value) + + # else: value == current_node.value + # This implementation ignores duplicates. You could also + # choose to place them on the right. + + def search(self, value): + """ + Public method to search for a value. Returns True or False. + """ + return self._search_recursive(self.root, value) + + def _search_recursive(self, current_node, value): + """ + Private recursive helper method to find a value. + """ + # Base Cases: + # 1. We reached the end of a branch (node is None) + # 2. We found the value + if current_node is None: + return False + if current_node.value == value: + return True + + # Recursive Steps: + if value < current_node.value: + # Search the left subtree + return self._search_recursive(current_node.left, value) + else: # value > current_node.value + # Search the right subtree + return self._search_recursive(current_node.right, value) + + def inorder_traversal(self): + """ + Prints the tree's values in sorted order (Left, Root, Right). + """ + print("In-order traversal:") + self._inorder_helper(self.root) + print() # Add a newline at the end + + def _inorder_helper(self, node): + """ + Private recursive helper for in-order traversal. + """ + if node: + self._inorder_helper(node.left) + print(node.value, end=' ') + self._inorder_helper(node.right) + + +# --- Example Usage --- +if __name__ == "__main__": + + # 1. Create a new BST + bst = BinarySearchTree() + + # 2. Insert values + # The root will be 50 + values = [50, 30, 70, 20, 40, 60, 80] + for val in values: + bst.insert(val) + + # 3. Print the sorted values + # An in-order traversal of a BST always yields a sorted list. + bst.inorder_traversal() + + # 4. Search for values + print("Is 40 in the tree?", bst.search(40)) + print("Is 99 in the tree?", bst.search(99)) diff --git a/C/1d_array_sum.c b/C/1d_array_sum.c new file mode 100644 index 00000000..d8fe7d1c --- /dev/null +++ b/C/1d_array_sum.c @@ -0,0 +1,23 @@ +#include + +int main() { + int n, sum = 0; + + // Ask user for number of elements + printf("Enter the number of elements in the array: "); + scanf("%d", &n); + + int arr[n]; // Declare array of size n + + // Input array elements + printf("Enter the elements of the array:\n"); + for (int i = 0; i < n; i++) { + scanf("%d", &arr[i]); + sum += arr[i]; // Add each element to sum + } + + // Display the sum + printf("The sum of the elements is: %d\n", sum); + + return 0; +} diff --git a/C/Binary_Search_Tree.c b/C/Binary_Search_Tree.c new file mode 100644 index 00000000..f9854f8a --- /dev/null +++ b/C/Binary_Search_Tree.c @@ -0,0 +1,48 @@ +#include +#include + +typedef struct Node { + int data; + struct Node* left; + struct Node* right; +} Node; + +// Create a new node +Node* createNode(int data) { + Node* node = (Node*)malloc(sizeof(Node)); + node->data = data; + node->left = node->right = NULL; + return node; +} + +// Insert a node +Node* insert(Node* root, int data) { + if (root == NULL) return createNode(data); + if (data < root->data) root->left = insert(root->left, data); + else if (data > root->data) root->right = insert(root->right, data); + return root; +} + +// Inorder traversal +void inorder(Node* root) { + if (root) { + inorder(root->left); + printf("%d ", root->data); + inorder(root->right); + } +} + +int main() { + Node* root = NULL; + root = insert(root, 50); + insert(root, 30); + insert(root, 70); + insert(root, 20); + insert(root, 40); + insert(root, 60); + insert(root, 80); + + printf("Inorder traversal: "); + inorder(root); + return 0; +} diff --git a/C/Bubble Sort - C b/C/Bubble Sort - C new file mode 100644 index 00000000..87de3190 --- /dev/null +++ b/C/Bubble Sort - C @@ -0,0 +1,40 @@ +#include + +void bubbleSort(int arr[], int n) { + int i, j, temp; + int swapped; + + // Outer loop for passes + for (i = 0; i < n - 1; i++) { + swapped = 0; + + // Inner loop for comparisons + for (j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + // Swap the elements + temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + swapped = 1; + } + } + + // If no swaps happened, array is already sorted + if (swapped == 0) + break; + } +} + +int main() { + int arr[] = {5, 3, 8, 4, 2}; + int n = sizeof(arr) / sizeof(arr[0]); + + bubbleSort(arr, n); + + printf("Sorted array: "); + for (int i = 0; i < n; i++) { + printf("%d ", arr[i]); + } + + return 0; +} diff --git a/C/Bubble_Sort.c b/C/Bubble_Sort.c index 453916bc..593aa54e 100644 --- a/C/Bubble_Sort.c +++ b/C/Bubble_Sort.c @@ -1,10 +1,8 @@ #include -// Function to perform Bubble Sort void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { - // Swap if elements are out of order if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; @@ -16,7 +14,7 @@ void bubbleSort(int arr[], int n) { int main() { int arr[] = {64, 34, 25, 12, 22, 11, 90}; - int n = sizeof(arr) / sizeof(arr[0]); + int n = sizeof(arr)/sizeof(arr[0]); bubbleSort(arr, n); diff --git a/C/Climbing_Stairs.c b/C/Climbing_Stairs.c new file mode 100644 index 00000000..b09921e0 --- /dev/null +++ b/C/Climbing_Stairs.c @@ -0,0 +1,74 @@ +#include +#include + + +// -----------------------MEMORIZATION---------------------- +// int countWays(int n, int dp[]){ +// if(n == 0) return 1; // Fixed: == instead of = +// if(n == 1) return 1; +// if(dp[n] != -1) return dp[n]; +// return dp[n] = countWays(n-1, dp) + countWays(n-2, dp); +// } + +// int climbStairs(int n) { +// // Handle edge case +// if(n < 0) return 0; + +// int* dp = (int*) malloc((n+1) * sizeof(int)); +// if(dp == NULL) { +// printf("Memory allocation failed!\n"); +// return -1; +// } + +// for(int i = 0; i <= n; i++){ +// dp[i] = -1; +// } + +// int result = countWays(n, dp); +// free(dp); // Free allocated memory +// return result; +// } + +// -----------------------TABULATION---------------------- + +// int climbStairs(int n) { +// // Handle edge case +// if(n < 0) return 0; + +// int* dp = (int*) malloc((n+1) * sizeof(int)); + +// dp[0] = 1; +// dp[1] = 1; +// for(int i = 2; i= 0) { + printf("Number of ways to climb %d stairs: %d\n", n, ways); + } + + return 0; +} \ No newline at end of file diff --git a/C/FrogJump.c b/C/FrogJump.c new file mode 100644 index 00000000..82f3fac7 --- /dev/null +++ b/C/FrogJump.c @@ -0,0 +1,89 @@ +// Given an integer array height[] where height[i] represents the height of the i-th stair, +// a frog starts from the first stair and wants to reach the top. From any stair i, the frog has two options: +// it can either jump to the (i+1)th stair or the (i+2)th stair. The cost of a jump is the absolute difference in height between the two stairs. +// Determine the minimum total cost required for the frog to reach the top. + +// Example: + +// Input: heights[] = [20, 30, 40, 20] +// Output: 20 +// Explanation: Minimum cost is incurred when the frog jumps from stair 0 to 1 then 1 to 3: +// jump from stair 0 to 1: cost = |30 - 20| = 10 +// jump from stair 1 to 3: cost = |20-30| = 10 +// Total Cost = 10 + 10 = 20 +// Input: heights[] = [30, 20, 50, 10, 40] +// Output: 30 +// Explanation: Minimum cost will be incurred when frog jumps from stair 0 to 2 then 2 to 4: +// jump from stair 0 to 2: cost = |50 - 30| = 20 +// jump from stair 2 to 4: cost = |40-50| = 10 +// Total Cost = 20 + 10 = 30 +// Constraints: + +// 1 <= height.size() <= 105 +// 0 <= height[i]<=104 + + +#include +#include +int min(int a, int b){ + return a>b? b:a; +} +//-------------------------------------------------------MEMORIZATION +//int findMinCost(int heights[],int idx,int dp[]){ +// if(idx == 0) return 0; +// if(idx == 1) return abs(heights[1] - heights[0]); +// if(dp[idx] != -1) return dp[idx]; +// dp[idx] = min(findMinCost(heights,idx-1,dp) + abs(heights[idx] - heights[idx-1]), +// findMinCost(heights,idx-2,dp) + abs(heights[idx] - heights[idx-2])); +// return dp[idx]; +// } + + +// int minCost(int heights[],int size){ +// int *dp = (int*) malloc(size*sizeof(int)); +// for(int i=0; i 1) + dp[1] = abs(heights[1] - heights[0]); + + for(int i = 2; i 1) + prev1 = abs(heights[1] - heights[0]); + + // You need to implement the rest of the logic using prev1 and prev2, or remove this function if not needed. + // The current code below references 'dp', which is not declared in this function. + // For a space-optimized solution, you can use prev1 and prev2 as follows: + + for(int i = 2; i < size; i++){ + int curr = min(prev1 + abs(heights[i] - heights[i-1]), prev2 + abs(heights[i] - heights[i-2])); + prev2 = prev1; + prev1 = curr; + } + return (size == 1) ? 0 : prev1; +} + +int main(){ + int heights[] = {20,30,40,20}; + printf("Min Cost is %d\n",minCost(heights,4)); + +} \ No newline at end of file diff --git a/Insertion.c b/C/Insertion.c similarity index 100% rename from Insertion.c rename to C/Insertion.c diff --git a/C/List-Flattening.c b/C/List-Flattening.c new file mode 100644 index 00000000..270294cf --- /dev/null +++ b/C/List-Flattening.c @@ -0,0 +1,106 @@ +#include +#include + +typedef struct Node { + int data; + struct Node* next; + struct Node* prev; + struct Node* child; +} Node; + +void append(Node* child, Node** tail) { + Node* curNode; + + (*tail)->next = child; + child->prev = *tail; + + for (curNode = child; curNode->next != NULL; curNode = curNode->next) + ; + + *tail = curNode; +} + +void flattenList(Node* head, Node** tail) { + Node* curNode = head; + + while (curNode != NULL) { + if (curNode->child) { + append(curNode->child, tail); + + curNode->child = NULL; + } + curNode = curNode->next; + } +} + +Node* findTail(Node* head) { + Node* tail = head; + while (tail->next != NULL) { + tail = tail->next; + } + return tail; +} + +void printList(Node* head) { + Node* cur = head; + while (cur != NULL) { + printf("%d ", cur->data); + cur = cur->next; + } + printf("\n"); +} + +Node* createNode(int data) { + Node* newNode = (Node*)malloc(sizeof(Node)); + newNode->data = data; + newNode->next = NULL; + newNode->prev = NULL; + newNode->child = NULL; + return newNode; +} + +int main() { + Node* head = createNode(1); + head->next = createNode(2); + head->next->prev = head; + head->next->next = createNode(3); + head->next->next->prev = head->next; + + // Create child list for node 1 + head->child = createNode(4); + head->child->next = createNode(5); + head->child->next->prev = head->child; + + // Create child list for node 3 + head->next->next->child = createNode(6); + + // Create child list for node 4 + head->child->child = createNode(7); + + // Find initial tail of top level list + Node* tail = findTail(head); + + flattenList(head, &tail); + + printList(head); + + return 0; +} + +/* + +Input: + +1 <-> 2 <-> 3 +| | +4 <-> 5 6 +| +7 + + +Output : + +1 2 3 4 5 6 7 + +*/ + diff --git a/C/Merge_Sort.c b/C/Merge_Sort.c new file mode 100644 index 00000000..5b8d647d --- /dev/null +++ b/C/Merge_Sort.c @@ -0,0 +1,40 @@ +#include +#include + +void merge(int arr[], int l, int m, int r) { + int n1 = m - l + 1; + int n2 = r - m; + int L[n1], R[n2]; + + for (int i = 0; i < n1; i++) L[i] = arr[l + i]; + for (int j = 0; j < n2; j++) R[j] = arr[m + 1 + j]; + + int i = 0, j = 0, k = l; + while (i < n1 && j < n2) { + if (L[i] <= R[j]) arr[k++] = L[i++]; + else arr[k++] = R[j++]; + } + while (i < n1) arr[k++] = L[i++]; + while (j < n2) arr[k++] = R[j++]; +} + +void mergeSort(int arr[], int l, int r) { + if (l < r) { + int m = l + (r - l) / 2; + mergeSort(arr, l, m); + mergeSort(arr, m + 1, r); + merge(arr, l, m, r); + } +} + +int main() { + int arr[] = {12, 11, 13, 5, 6, 7}; + int n = sizeof(arr)/sizeof(arr[0]); + + mergeSort(arr, 0, n - 1); + + printf("Sorted array: "); + for (int i = 0; i < n; i++) + printf("%d ", arr[i]); + return 0; +} diff --git a/C/Queue.c b/C/Queue.c index 30c1c05a..5d2fa6f4 100644 --- a/C/Queue.c +++ b/C/Queue.c @@ -1,92 +1,49 @@ +//circular queue implementation in C using array #include -#include -#define Max 5 +#define MAX 100 -int que[Max]; -int f = -1; -int r = -1; +typedef struct Queue { + int arr[MAX]; + int front, rear; +} Queue; -void insert(); -void delete(); -void display(); +void initQueue(Queue* q) { q->front = q->rear = -1; } -void main() { - clrscr(); - int ch; - do { - printf("\n 1. Insert \n 2. Delete \n 3. Display \n 4. Stop\n"); - printf("\n Enter your choice : "); - scanf("%d", &ch); +int isEmpty(Queue* q) { return q->front == -1; } +int isFull(Queue* q) { return (q->rear + 1) % MAX == q->front; } - switch (ch) { - case 1: insert(); - break; - case 2: delete(); - break; - case 3: display(); - break; - case 4: printf("\n Bye Bye!!\n"); - break; - default: printf("\n Invalid Input!!\n"); - } - } while (ch != 4); - - getch(); -} - -void insert() { - int val; - if ((f == 0 && r == Max - 1) || (r == f - 1)) { - printf("\n Queue is Full\n"); - } else { - if (f == -1 && r == -1) { - f = 0; - r = 0; - } else if (r == Max - 1 && f != 0) { - r = 0; - } else { - r++; - } - printf("\n Enter an element: "); - scanf("%d", &val); - que[r] = val; +void enqueue(Queue* q, int val) { + if (isFull(q)) { + printf("Queue Overflow\n"); + return; } + if (isEmpty(q)) q->front = q->rear = 0; + else q->rear = (q->rear + 1) % MAX; + q->arr[q->rear] = val; } -void delete() { - if (f == -1 && r == -1) { - printf("\n Queue is Empty\n"); - } else { - printf("\n The Element deleted is %d", que[f]); - if (f == r) { - f = -1; - r = -1; - } else if (f == Max - 1) { - f = 0; - } else { - f++; - } +int dequeue(Queue* q) { + if (isEmpty(q)) { + printf("Queue Underflow\n"); + return -1; } + int val = q->arr[q->front]; + if (q->front == q->rear) q->front = q->rear = -1; + else q->front = (q->front + 1) % MAX; + return val; } -void display() { - int i; - if (f == -1 && r == -1) { - printf("\n Queue is Empty\n"); - } else { - printf("\n Queue elements are: "); - if (f <= r) { - for (i = f; i <= r; i++) { - printf("%d ", que[i]); - } - } else { - for (i = f; i < Max; i++) { - printf("%d ", que[i]); - } - for (i = 0; i <= r; i++) { - printf("%d ", que[i]); - } - } - } -} \ No newline at end of file +int main() { + Queue q; + initQueue(&q); + + enqueue(&q, 10); + enqueue(&q, 20); + enqueue(&q, 30); + + printf("Dequeued: %d\n", dequeue(&q)); + printf("Dequeued: %d\n", dequeue(&q)); + + return 0; +} diff --git a/C/Quick_Sort.c b/C/Quick_Sort.c new file mode 100644 index 00000000..342520e3 --- /dev/null +++ b/C/Quick_Sort.c @@ -0,0 +1,41 @@ +#include + +void swap(int* a, int* b) { + int t = *a; + *a = *b; + *b = t; +} + +int partition(int arr[], int low, int high) { + int pivot = arr[high]; // pivot + int i = low - 1; + + for (int j = low; j < high; j++) { + if (arr[j] <= pivot) { + i++; + swap(&arr[i], &arr[j]); + } + } + swap(&arr[i + 1], &arr[high]); + return i + 1; +} + +void quickSort(int arr[], int low, int high) { + if (low < high) { + int pi = partition(arr, low, high); + quickSort(arr, low, pi - 1); + quickSort(arr, pi + 1, high); + } +} + +int main() { + int arr[] = {10, 7, 8, 9, 1, 5}; + int n = sizeof(arr)/sizeof(arr[0]); + + quickSort(arr, 0, n - 1); + + printf("Sorted array: "); + for (int i = 0; i < n; i++) + printf("%d ", arr[i]); + return 0; +} diff --git a/C/Recursive_Quick_Sort.c b/C/Recursive_Quick_Sort.c new file mode 100644 index 00000000..30d634d1 --- /dev/null +++ b/C/Recursive_Quick_Sort.c @@ -0,0 +1,64 @@ + +#include +void swap(int* a, int* b) +{ + int temp = *a; + *a = *b; + *b = temp; +} +int partition(int arr[], int low, int high) +{ + int pivot = arr[low]; + int i = low; + int j = high; + while (i < j) + { + while (arr[i] <= pivot && i <= high - 1) + { + i++; + } + while (arr[j] > pivot && j >= low + 1) + { + j--; + } + if (i < j) + { + swap(&arr[i], &arr[j]); + } + } + swap(&arr[low], &arr[j]); + return j; +} +void quickSort(int arr[], int low, int high) +{ + int partitionIndex; + if (low < high) + { + partitionIndex = partition(arr, low, high); + quickSort(arr, low, partitionIndex - 1); + quickSort(arr, partitionIndex + 1, high); + } +} +int main() +{ + int arr[10],i,n; + printf("\nEnter How Many Elements You Want?\n"); + scanf("%d",&n); + printf("\nEnter Array Elements\n"); + for (i = 0; i < n; i++) + { + scanf("%d ", &arr[i]); + } + printf("Original array: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + quickSort(arr, 0, n - 1); + printf("\nSorted array: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + return 0; +} \ No newline at end of file diff --git a/C/Sieve_of_Eratosthene.c b/C/Sieve_of_Eratosthene.c new file mode 100644 index 00000000..5e83a3df --- /dev/null +++ b/C/Sieve_of_Eratosthene.c @@ -0,0 +1,45 @@ +#include +#include + +void sieveOfEratosthenes(int n) +{ + bool prime[n + 1]; // Create a boolean array to mark prime numbers + for (int i = 0; i <= n; i++) + { + prime[i] = true; // Initialize all entries as true + } + + // marking non-prime numbers from 2 to n + for (int p = 2; p * p <= n; p++) + { + if (prime[p] == true) + { // If prime[p] is still true, it's a prime number + for (int i = p * p; i <= n; i += p) + { + prime[i] = false; // Mark all multiples of p as non-prime + } + } + } + + // Print all prime numbers + printf("Prime numbers up to %d are: ", n); + for (int p = 2; p <= n; p++) + { + if (prime[p] == true) + { + printf("%d ", p); + } + } + printf("\n"); +} + +int main() +{ + int n; + printf("prime to the n: "); + scanf("%d", &n); + + sieveOfEratosthenes(n); + + return 0; +} \ No newline at end of file diff --git a/C/Singly_Linked_List.c b/C/Singly_Linked_List.c new file mode 100644 index 00000000..4ede9ced --- /dev/null +++ b/C/Singly_Linked_List.c @@ -0,0 +1,43 @@ +#include +#include + +typedef struct Node { + int data; + struct Node* next; +} Node; + +Node* createNode(int data) { + Node* node = (Node*)malloc(sizeof(Node)); + node->data = data; + node->next = NULL; + return node; +} + +void insertAtEnd(Node** head, int data) { + Node* node = createNode(data); + if (*head == NULL) { + *head = node; + return; + } + Node* temp = *head; + while (temp->next) temp = temp->next; + temp->next = node; +} + +void display(Node* head) { + while (head) { + printf("%d -> ", head->data); + head = head->next; + } + printf("NULL\n"); +} + +int main() { + Node* head = NULL; + insertAtEnd(&head, 10); + insertAtEnd(&head, 20); + insertAtEnd(&head, 30); + + display(head); + return 0; +} diff --git a/C/Stack.c b/C/Stack.c new file mode 100644 index 00000000..a2d7afe9 --- /dev/null +++ b/C/Stack.c @@ -0,0 +1,49 @@ +//stack implementation using array in C +#include +#define MAX 100 + +typedef struct Stack { + int arr[MAX]; + int top; +} Stack; + +void init(Stack* s) { s->top = -1; } + +int isEmpty(Stack* s) { return s->top == -1; } +int isFull(Stack* s) { return s->top == MAX - 1; } + +void push(Stack* s, int val) { + if (isFull(s)) { + printf("Stack Overflow\n"); + return; + } + s->arr[++s->top] = val; +} + +int pop(Stack* s) { + if (isEmpty(s)) { + printf("Stack Underflow\n"); + return -1; + } + return s->arr[s->top--]; +} + +int peek(Stack* s) { + if (!isEmpty(s)) return s->arr[s->top]; + return -1; +} + +int main() { + Stack s; + init(&s); + + push(&s, 10); + push(&s, 20); + push(&s, 30); + + printf("Top element: %d\n", peek(&s)); + printf("Popped: %d\n", pop(&s)); + printf("Popped: %d\n", pop(&s)); + + return 0; +} diff --git a/C/Two sum questions b/C/Two sum questions new file mode 100644 index 00000000..6c1a90e1 --- /dev/null +++ b/C/Two sum questions @@ -0,0 +1,22 @@ +#include + +void twoSum(int nums[], int n, int target) { + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i] + nums[j] == target) { + printf("Indices: [%d, %d]\n", i, j); + return; // Exit after finding the pair + } + } + } + printf("No solution found.\n"); +} + +int main() { + int nums[] = {2, 7, 11, 15}; + int target = 9; + int n = sizeof(nums) / sizeof(nums[0]); + + twoSum(nums, n, target); + return 0; +} diff --git a/C/array_deletion.c b/C/array_deletion.c new file mode 100644 index 00000000..981afd15 --- /dev/null +++ b/C/array_deletion.c @@ -0,0 +1,51 @@ +/* + * [Algorithm] : Array Deletion + * [Author] : tanshen-kun (Modified & documented by ChatGPT) + * + * Hacktoberfest2025 + */ + +#include + +// Function to delete element at given position +void array_delete(int arr[], int *size, int pos) { + // Shift elements left from the position + for (int i = pos; i < *size - 1; i++) { + arr[i] = arr[i + 1]; + } + (*size)--; // Decrease array size +} + +// Function to print the array +void printArray(int arr[], int size) { + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int arr[] = {1, 2, 3, 4, 4, 5, 6, 7}; + int size = sizeof(arr) / sizeof(arr[0]); + + printf("Original Array: "); + printArray(arr, size); + + int pos; + printf("Enter position to delete (0 - %d): ", size - 1); + scanf("%d", &pos); + + // Validate position + if (pos < 0 || pos >= size) { + printf("Invalid position! Please enter a value between 0 and %d.\n", size - 1); + return 1; // Exit program with error + } + + // Perform deletion + array_delete(arr, &size, pos); + + printf("Array After Deletion: "); + printArray(arr, size); + + return 0; +} diff --git a/C/array_insertion.c b/C/array_insertion.c new file mode 100644 index 00000000..f2478e30 --- /dev/null +++ b/C/array_insertion.c @@ -0,0 +1,57 @@ +/* + * + * [Algorithm] : Array Insertion + * [Author] : tanshen-kun (Improved and documented by ChatGPT) + * + * Hacktoberfest2025 + */ + +#include + +// Function to insert an element into the array +void array_insert(int arr[], int *size, int value, int pos) { + // Shift elements to the right + for (int i = *size; i > pos; i--) { + arr[i] = arr[i - 1]; + } + + arr[pos] = value; // Insert new element + (*size)++; // Increase size +} + +// Function to print array elements +void printArray(int arr[], int size) { + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int arr[50] = {1, 3, 4, 5, 6, 7, 8, 9}; // Initial array + int size = 8; + + printf("Original Array: "); + printArray(arr, size); + + int pos, value; + + printf("Enter the position to insert (0 to %d): ", size); + scanf("%d", &pos); + + // Validate position + if (pos < 0 || pos > size) { + printf("Invalid position! Please enter a value between 0 and %d.\n", size); + return 1; + } + + printf("Enter the value to insert: "); + scanf("%d", &value); + + array_insert(arr, &size, value, pos); + + printf("Array After Insertion: "); + printArray(arr, size); + + return 0; +} diff --git a/C/array_searching.c b/C/array_searching.c new file mode 100644 index 00000000..7de1b20d --- /dev/null +++ b/C/array_searching.c @@ -0,0 +1,46 @@ +/* + * + * [Algorithm]: Array Searching + * [author]: tanshen-kun + * + * Hacktoberfest2025 + */ +#include + +int array_search(int arr[], int size, int key) { + for (int i = 0; i < size; i++) { + if (arr[i] == key) { + return i; + } + } + // if not found + return -1; +} + +void printArray(int arr[], int size) { + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int arr[] = {12, 1, 42, 12, 34, 12, 56, 2, 1}; + int size = sizeof(arr) / sizeof(arr[0]); + + printf("Array : "); + printArray(arr, size); + + int key; + printf("Enter the key to search : "); + scanf("%d", &key); + + int index = array_search(arr, size, key); + if (index != -1) { + printf("Element found at index %d\n", index); + } else { + printf("Element not found!\n"); + } + + return 0; +} diff --git a/C/array_traversal.c b/C/array_traversal.c new file mode 100644 index 00000000..73b61296 --- /dev/null +++ b/C/array_traversal.c @@ -0,0 +1,25 @@ +/* + * + * [Algorithm]: Array Traversal + * [author]: tanshen-kun + * + * Hacktoberfest2025 + */ +#include + +void array_traversal(int arr[], int size) { + printf("Array Elements : "); + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + int size = sizeof(arr) / sizeof(arr[0]); + + array_traversal(arr, size); + + return 0; +} diff --git a/C/array_update.c b/C/array_update.c new file mode 100644 index 00000000..0a43e0dd --- /dev/null +++ b/C/array_update.c @@ -0,0 +1,40 @@ +/* + * [Algorithm]: Array Update + * [author]: tanshen-kun + * + * Hacktoberfest2025 + */ +#include + +void array_update(int arr[], int pos, int value) { + arr[pos] = value; +} + +void printArray(int arr[], int size) { + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int arr[] = {1, 2, 3, 4, 4, 6, 7, 8}; + int size = sizeof(arr) / sizeof(arr[0]); + + printArray(arr, size); + + int pos; + printf("Enter the postion to update(0-%d) : ", size - 1); + scanf("%d", &pos); + + int value; + printf("Enter the value to update : "); + scanf("%d", &value); + + array_update(arr, pos, value); + + printf("Array After update : "); + printArray(arr, size); + + return 0; +} diff --git a/C/binarysearch.c b/C/binarysearch.c new file mode 100644 index 00000000..b69df880 --- /dev/null +++ b/C/binarysearch.c @@ -0,0 +1,55 @@ +#include + +int binary(int low,int high,int target,int arr[]) +{ + int mid = (low+high)/2; + if (low>high) + return -1; + if (arr[mid]==target) + return mid; + else if (arr[mid]arr[j+1]) + { + int temp=arr[j]; + arr[j]=arr[j+1]; + arr[j+1]=temp; + } + } + } + + for (int i=0;i + +void bubbleSort(int arr[], int n) { + for (int i = 0; i < n - 1; i++) { + for (int j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } +} + +int main() { + int arr[] = {64, 34, 25, 12, 22, 11, 90}; + int n = sizeof(arr)/sizeof(arr[0]); + + bubbleSort(arr, n); + + printf("Sorted array: "); + for (int i = 0; i < n; i++) + printf("%d ", arr[i]); + return 0; +} diff --git a/C/circular_queue.c b/C/circular_queue.c new file mode 100644 index 00000000..e69de29b diff --git a/C/count_set_bits.c b/C/count_set_bits.c new file mode 100644 index 00000000..f617250c --- /dev/null +++ b/C/count_set_bits.c @@ -0,0 +1,17 @@ +// Count number of set bits in an integer - Nithin +#include + +int countSetBits(int n) { + int count = 0; + while (n) { + n &= (n - 1); // Removes the last set bit + count++; + } + return count; +} + +int main() { + int num = 29; // binary 11101 → 4 set bits + printf("Number of set bits in %d: %d\n", num, countSetBits(num)); + return 0; +} diff --git a/C/deadlock_avoidance.c b/C/deadlock_avoidance.c new file mode 100644 index 00000000..0ba2c2a8 --- /dev/null +++ b/C/deadlock_avoidance.c @@ -0,0 +1,72 @@ +#include +#include + +#define P 5 +#define R 3 + + +bool isSafe(int processes[], int avail[], int max[][R], int allot[][R]) { + int need[P][R]; + for (int i = 0; i < P; i++) + for (int j = 0; j < R; j++) + need[i][j] = max[i][j] - allot[i][j]; + + bool finish[P] = {0}; + int safeSeq[P]; + int work[R]; + for (int i = 0; i < R; i++) + work[i] = avail[i]; + + int count = 0; + while (count < P) { + bool found = false; + for (int p = 0; p < P; p++) { + if (!finish[p]) { + int j; + for (j = 0; j < R; j++) + if (need[p][j] > work[j]) + break; + + if (j == R) { + for (int k = 0; k < R; k++) + work[k] += allot[p][k]; + safeSeq[count++] = p; + finish[p] = true; + found = true; + } + } + } + if (!found) { + printf("System is not in safe state\n"); + return false; + } + } + printf("System is in safe state.\nSafe sequence is: "); + for (int i = 0; i < P; i++) + printf("%d ", safeSeq[i]); + printf("\n"); + return true; +} + + +int main() { + int processes[] = {0, 1, 2, 3, 4}; + + int avail[] = {3, 3, 2}; + + int max[][R] = {{7, 5, 3}, + {3, 2, 2}, + {9, 0, 2}, + {2, 2, 2}, + {4, 3, 3}}; + + int allot[][R] = {{0, 1, 0}, + {2, 0, 0}, + {3, 0, 2}, + {2, 1, 1}, + {0, 0, 2}}; + + isSafe(processes, avail, max, allot); + + return 0; +} diff --git a/C/fibonacci.c b/C/fibonacci.c new file mode 100644 index 00000000..af226233 --- /dev/null +++ b/C/fibonacci.c @@ -0,0 +1,16 @@ +#include + +int fib(int n) +{ + if (n <= 2) + return 1; + return fib(n-1)+fib(n-2); +} + +int main() +{ + int n; + printf ("Enter which term of fibonacci series\n"); + scanf("%d",&n); + printf("%d\n",fib (n)); +} \ No newline at end of file diff --git a/C/file_handling_with_linear_search.c b/C/file_handling_with_linear_search.c new file mode 100644 index 00000000..c61257a9 --- /dev/null +++ b/C/file_handling_with_linear_search.c @@ -0,0 +1,47 @@ +#include +#include +#include +typedef struct student +{ + char name[20]; + char class[10]; +}record; +record std[100]; +int read_file(record *a) +{ + int i=0; + FILE *fp; + if((fp=fopen("student.txt","r"))!=NULL) + { + while(!feof(fp)) + { + fscanf(fp,"%s%s",a[i].name,a[i].class); + i++; + } + } + return (i-1); +} +void l_search(record *a,int n,char name[20]) +{ + int i; + for(i=0;i + +int gcd(int a , int b) +{ + if (a%b==0) + return b; + else + return gcd(b,a%b); +} +int main() +{ + int a,b; + printf("Enter two numbers\n"); + scanf("%d %d",&a,&b); + if (b>a) + { + a=a+b; + b=a-b; + a=a-b; + } + printf("The gcd of %d and %d is %d\n",a,b,gcd(a,b)); +} \ No newline at end of file diff --git a/C/graphs/graph_bfs b/C/graphs/graph_bfs new file mode 100644 index 00000000..404ad71e Binary files /dev/null and b/C/graphs/graph_bfs differ diff --git a/C/graphs/graph_bfs.c b/C/graphs/graph_bfs.c new file mode 100644 index 00000000..1cebacb7 --- /dev/null +++ b/C/graphs/graph_bfs.c @@ -0,0 +1,68 @@ +#include +#define MAX 10 + +int queue[MAX], front = -1, rear = -1; +int visited[MAX]; + +// Enqueue function +void enqueue(int v) { + if (rear == MAX - 1) + printf("Queue overflow\n"); + else { + if (front == -1) + front = 0; + queue[++rear] = v; + } +} + +// Dequeue function +int dequeue() { + if (front == -1 || front > rear) + return -1; + return queue[front++]; +} + +// BFS function +void bfs(int adj[MAX][MAX], int n, int start) { + int i, node; + for (i = 0; i < n; i++) + visited[i] = 0; + + enqueue(start); + visited[start] = 1; + + printf("BFS Traversal: "); + + while ((node = dequeue()) != -1) { + printf("%d ", node); + + for (i = 0; i < n; i++) { + if (adj[node][i] == 1 && visited[i] == 0) { + enqueue(i); + visited[i] = 1; + } + } + } + printf("\n"); +} + +// Main function +int main() { + int n, i, j, start; + int adj[MAX][MAX]; + + printf("Enter number of vertices: "); + scanf("%d", &n); + + printf("Enter adjacency matrix:\n"); + for (i = 0; i < n; i++) + for (j = 0; j < n; j++) + scanf("%d", &adj[i][j]); + + printf("Enter starting vertex (0 - %d): ", n - 1); + scanf("%d", &start); + + bfs(adj, n, start); + + return 0; +} diff --git a/C/insertion_sort_using_rand_function.c b/C/insertion_sort_using_rand_function.c new file mode 100644 index 00000000..b35f81d6 --- /dev/null +++ b/C/insertion_sort_using_rand_function.c @@ -0,0 +1,48 @@ +#include +#include + +void generate(int a[], int n) +{ + int i; + for (i=0; i=0) + { + a[j+1]=a[j]; + j--; + } + a[j+1]=temp; + } +} +int main() +{ + int size, arr[10]; + printf("\nEnter How Many Elements You Want?\n"); + scanf("%d",&size); + generate(arr, size); + printf("\nGiven Array Before Sort\n"); + display(arr,size); + insertionsort(arr,size); + printf("\nGiven Array After Sort\n"); + display(arr,size); + return(0); +} \ No newline at end of file diff --git a/C/kadane.c b/C/kadane.c new file mode 100644 index 00000000..0e7780e0 --- /dev/null +++ b/C/kadane.c @@ -0,0 +1,39 @@ +/*Problem Statement: + We are given with an array and we need to find the largest contiguous subarray sum, + which can be done using Kadane’s algorithm efficiently. + +Key Points: + Kadane’s Algorithm works by iterating through the array once (O(n) time complexity), which makes it efficient. + The algorithm maintains a running sum (current_sum) and updates the maximum sum (max_sum) when a larger subarray sum is found. +*/ +#include +#include + +int main() +{ + int n; + scanf("%d", &n); + + int arr[n]; + + for (int i = 0; i < n; i++) + scanf("%d", &arr[i]); + + int max_sum = INT_MIN, current_sum = 0; + + for (int i = 0; i < n; i++) + { + + current_sum += arr[i]; + + if (max_sum < current_sum) + max_sum = current_sum; + + if (current_sum < 0) + current_sum = 0; + } + + printf("%d ", max_sum); + + return 0; +} \ No newline at end of file diff --git a/C/leastCommonSubsequence.c b/C/leastCommonSubsequence.c new file mode 100644 index 00000000..5aafc87d --- /dev/null +++ b/C/leastCommonSubsequence.c @@ -0,0 +1,116 @@ +#include +#include +#include +int max(int a, int b){ + return a > b ? a : b ; +} +/* +int findLCS(char *s1, char *s2, int i, int j){ + if(i <0 || j <0) return 0; + + if(s1[i] == s2[j]){ + return 1 + findLCS(s1,s2,i-1,j-1); + } + return max(findLCS(s1,s2,i-1,j),findLCS(s1,s2,i,j-1)); +} + +int longestCommonSubsequence(char* text1, char* text2) { + int i = strlen(text1); + int j = strlen(text2); + + return findLCS(text1,text2,i-1,j-1); +} +*/ + + +/*-------------MEMOIZATION----------------*/ +/* +int findLCS(char*s1,char*s2,int i,int j,int**dp){ + if(i < 0 || j < 0) return 0; + if(dp[i][j] != -1) return dp[i][j]; + + if(s1[i] == s2[i]){ + return dp[i][j] = 1 + findLCS(s1,s2,i-1,j-1,dp); + } + return dp[i][j] = max(findLCS(s1,s2,i-1,j,dp),findLCS(s1,s2,i,j-1,dp)); +} + +int longestCommonSubsequence(char* text1, char* text2){ + int m = strlen(text1); + int n = strlen(text2); + + int **dp = (int**) malloc(m*sizeof(int*)); + + for(int i = 0; i +#include +void generate(int *a, int n) +{ + int i; + for (i=0; i +#include +int length(char str[]) +{ + int maxlen=0; + int curr=0; + + int len = strlen(str); + if (str[len-1] == '\n') + str[len-1] = '\0'; + + for (int i=0;str[i]!='\0';i++) + { + if (str[i]!=' ') + curr++; + else + { + if(curr>maxlen) + maxlen=curr; + curr=0; + } + if (curr > maxlen) + maxlen = curr; + } + return maxlen; +} + +int main() +{ + char str[100]; + printf("Enter the string\n"); + fgets(str,sizeof(str),stdin); + printf("%d\n",length(str)); +} \ No newline at end of file diff --git a/C/majority_element.c b/C/majority_element.c new file mode 100644 index 00000000..0df27fa8 --- /dev/null +++ b/C/majority_element.c @@ -0,0 +1,35 @@ +// majority_element.c +// Find the majority element in an array using Boyer-Moore Voting Algorithm +#include + +int findMajorityElement(int arr[], int n) { + int count = 0, candidate = -1; + for (int i = 0; i < n; i++) { + if (count == 0) { + candidate = arr[i]; + count = 1; + } else if (arr[i] == candidate) { + count++; + } else { + count--; + } + } + // Verify candidate + count = 0; + for (int i = 0; i < n; i++) { + if (arr[i] == candidate) count++; + } + if (count > n / 2) return candidate; + return -1; +} + +int main() { + int arr[] = {2, 2, 1, 1, 2, 2, 2}; + int n = sizeof(arr) / sizeof(arr[0]); + int result = findMajorityElement(arr, n); + if (result != -1) + printf("Majority element is %d\n", result); + else + printf("No majority element found.\n"); + return 0; +} diff --git a/C/matrix_multiplication.c b/C/matrix_multiplication.c new file mode 100644 index 00000000..61889460 --- /dev/null +++ b/C/matrix_multiplication.c @@ -0,0 +1,40 @@ +#include + +#define R1 2 // Row of first matrix +#define C1 3 // Column of first matrix (must match R2) +#define R2 3 // Row of second matrix +#define C2 2 // Column of second matrix + +void multiply_matrices(int mat1[R1][C1], int mat2[R2][C2], int res[R1][C2]) { + for (int i = 0; i < R1; i++) { + for (int j = 0; j < C2; j++) { + res[i][j] = 0; + for (int k = 0; k < C1; k++) { + res[i][j] += mat1[i][k] * mat2[k][j]; + } + } + } +} + +void print_matrix(int mat[R1][C2]) { + for (int i = 0; i < R1; i++) { + for (int j = 0; j < C2; j++) { + printf("%d\t", mat[i][j]); + } + printf("\n"); + } +} + +// Example +int main() { + int A[R1][C1] = { {1, 2, 3}, {4, 5, 6} }; + int B[R2][C2] = { {7, 8}, {9, 10}, {11, 12} }; + int C[R1][C2]; + + multiply_matrices(A, B, C); + + printf("Resultant Matrix (C):\n"); + print_matrix(C); + + return 0; +} \ No newline at end of file diff --git a/C/mini_http_cache_server.c b/C/mini_http_cache_server.c index 1607eab2..03683be1 100644 --- a/C/mini_http_cache_server.c +++ b/C/mini_http_cache_server.c @@ -1,207 +1,410 @@ -/* mini_http_cache_server.cpp +/* mini_http_cache_server.c * - * Complex single-file C++17 program: - * - TCP listener + thread pool - * - Minimal HTTP GET handler - * - In-memory LRU cache with std::unordered_map + std::list - * - MIME type detection - * - RAII + smart pointers - * - Graceful shutdown + * Single-file complex C program: + * - Non-blocking TCP accept + poll() event loop + * - Thread pool (fixed worker threads) + * - Simple HTTP/1.0 GET handling + * - In-memory LRU cache for file contents (configurable max bytes) + * - Tiny memory arena for per-request allocations + * - Minimal MIME type detection + * + * Compile: + * gcc -O2 -pthread mini_http_cache_server.c -o mini_http_cache_server + * + * Run: + * ./mini_http_cache_server + * + * Example: + * ./mini_http_cache_server 8080 ./www 50_000_000 */ -#include -#include +#define _GNU_SOURCE +#include +#include +#include #include -#include +#include +#include #include -using namespace std; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -/*** Utility ***/ -static volatile sig_atomic_t stopRequested = 0; -void handleSigint(int) { stopRequested = 1; } +/*** Configuration ***/ +#define MAX_EVENTS 1024 +#define BACKLOG 128 +#define WORKER_THREADS 8 +#define REQ_BUF_SIZE 8192 +#define CACHE_BUCKETS 4096 + +/*** Utilities ***/ +static void die(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} -string nowStr() { - time_t t = time(nullptr); - char buf[64]; - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t)); +static int set_nonblocking(int fd) { + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) return -1; + return fcntl(fd, F_SETFL, flags | O_NONBLOCK); +} + +static char *now_str() { + static __thread char buf[64]; + time_t t = time(NULL); + struct tm tm; + localtime_r(&t, &tm); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm); return buf; } -#define LOG(x) cerr << "[" << nowStr() << "] " << x << "\n" - -/*** Thread Pool ***/ -class ThreadPool { - vector workers; - queue> tasks; - mutex m; - condition_variable cv; - bool stopping = false; -public: - ThreadPool(size_t n) { - for(size_t i=0;i task; - { - unique_lock lock(m); - cv.wait(lock, [&]{ return stopping || !tasks.empty(); }); - if(stopping && tasks.empty()) return; - task = move(tasks.front()); - tasks.pop(); - } - task(); - } - }); - } - } - void enqueue(function f) { - { - unique_lock lock(m); - tasks.push(move(f)); - } - cv.notify_one(); + +static void log_info(const char *fmt, ...) { + va_list ap; va_start(ap, fmt); + fprintf(stderr, "[%s] INFO: ", now_str()); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +static void log_err(const char *fmt, ...) { + va_list ap; va_start(ap, fmt); + fprintf(stderr, "[%s] ERROR: ", now_str()); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +/*** Simple memory arena for per-request allocations ***/ +typedef struct { + char *buf; + size_t cap; + size_t used; +} arena_t; + +static void arena_init(arena_t *a, size_t cap) { + a->buf = malloc(cap); + a->cap = cap; + a->used = 0; +} + +static void arena_free(arena_t *a) { + free(a->buf); + a->buf = NULL; + a->cap = 0; + a->used = 0; +} + +static void *arena_alloc(arena_t *a, size_t n) { + if (a->used + n > a->cap) return NULL; + void *p = a->buf + a->used; + a->used += n; + return p; +} + +/*** LRU cache implementation for file contents ***/ + +typedef struct cache_entry { + // key -> filepath strdup'ed + char *key; + void *data; + size_t size; + // doubly-linked list pointers for LRU + struct cache_entry *prev, *next; + struct cache_entry *hash_next; // chaining in hash bucket + uint64_t last_access; // monotonic counter +} cache_entry_t; + +typedef struct { + cache_entry_t **buckets; + size_t nbuckets; + cache_entry_t *head; // most recently used + cache_entry_t *tail; // least recently used + size_t total_bytes; + size_t max_bytes; + pthread_mutex_t lock; + uint64_t tick; +} cache_t; + +static uint64_t hash_fn(const char *s) { + // simple FNV-1a 64-bit + uint64_t h = 1469598103934665603ULL; + while (*s) { + h ^= (unsigned char)*s++; + h *= 1099511628211ULL; } - void shutdown() { - { - unique_lock lock(m); - stopping = true; + return h; +} + +static cache_t *cache_create(size_t nbuckets, size_t max_bytes) { + cache_t *c = calloc(1, sizeof(cache_t)); + c->buckets = calloc(nbuckets, sizeof(cache_entry_t *)); + c->nbuckets = nbuckets; + c->max_bytes = max_bytes; + pthread_mutex_init(&c->lock, NULL); + c->head = c->tail = NULL; + c->total_bytes = 0; + c->tick = 1; + return c; +} + +static void cache_evict_one(cache_t *c) { + // Remove tail (least recently used) + if (!c->tail) return; + cache_entry_t *e = c->tail; + // unlink from LRU list + if (e->prev) e->prev->next = NULL; + c->tail = e->prev; + if (!c->tail) c->head = NULL; + // remove from hash bucket + uint64_t h = hash_fn(e->key) % c->nbuckets; + cache_entry_t *cur = c->buckets[h], *prev = NULL; + while (cur) { + if (cur == e) { + if (prev) prev->hash_next = cur->hash_next; + else c->buckets[h] = cur->hash_next; + break; } - cv.notify_all(); - for(auto &w: workers) w.join(); - } -}; - -/*** LRU Cache ***/ -class LRUCache { - struct Entry { string key; vector data; }; - size_t capacity, currentSize = 0; - list items; - unordered_map::iterator> map; - mutex m; -public: - LRUCache(size_t cap): capacity(cap) {} - optional> get(const string &key) { - lock_guard lock(m); - auto it = map.find(key); - if(it==map.end()) return {}; - items.splice(items.begin(), items, it->second); - return it->second->data; + prev = cur; + cur = cur->hash_next; } - void put(const string &key, vector data) { - lock_guard lock(m); - size_t sz = data.size(); - if(sz > capacity) return; - if(auto it = map.find(key); it!=map.end()) { - currentSize -= it->second->data.size(); - items.erase(it->second); - map.erase(it); - } - while(currentSize + sz > capacity && !items.empty()) { - currentSize -= items.back().data.size(); - map.erase(items.back().key); - items.pop_back(); + c->total_bytes -= e->size; + free(e->data); + free(e->key); + free(e); +} + +static void cache_touch(cache_t *c, cache_entry_t *e) { + // move to head (most recently used) + if (c->head == e) return; + // unlink + if (e->prev) e->prev->next = e->next; + if (e->next) e->next->prev = e->prev; + if (c->tail == e) c->tail = e->prev; + // put at head + e->prev = NULL; + e->next = c->head; + if (c->head) c->head->prev = e; + c->head = e; + if (!c->tail) c->tail = e; + e->last_access = ++c->tick; +} + +static cache_entry_t *cache_lookup_locked(cache_t *c, const char *key) { + uint64_t h = hash_fn(key) % c->nbuckets; + cache_entry_t *e = c->buckets[h]; + while (e) { + if (strcmp(e->key, key) == 0) { + cache_touch(c, e); + return e; } - items.push_front({key, move(data)}); - map[key] = items.begin(); - currentSize += sz; + e = e->hash_next; } -}; - -/*** HTTP Helpers ***/ -string guessMime(const string &path) { - if(path.ends_with(".html")||path.ends_with(".htm")) return "text/html"; - if(path.ends_with(".css")) return "text/css"; - if(path.ends_with(".js")) return "application/javascript"; - if(path.ends_with(".png")) return "image/png"; - if(path.ends_with(".jpg")||path.ends_with(".jpeg")) return "image/jpeg"; - if(path.ends_with(".gif")) return "image/gif"; - if(path.ends_with(".txt")) return "text/plain"; - return "application/octet-stream"; + return NULL; } -/*** Global state ***/ -static unique_ptr cache; -static string wwwRoot; - -/*** Client handler ***/ -void handleClient(int fd) { - char buf[4096]; - int n = recv(fd, buf, sizeof(buf)-1, 0); - if(n<=0) { close(fd); return; } - buf[n]=0; - string method, path, version; - { - stringstream ss(buf); - ss >> method >> path >> version; - } - if(method!="GET") { - string resp="HTTP/1.0 405 Method Not Allowed\r\n\r\n"; - send(fd, resp.c_str(), resp.size(), 0); - close(fd); return; +static void cache_put_locked(cache_t *c, const char *key, void *data, size_t size) { + if (size > c->max_bytes) { + // Too big to cache + free(data); + return; } - if(path=="/") path="/index.html"; - if(path.find("..")!=string::npos) { - string resp="HTTP/1.0 403 Forbidden\r\n\r\n"; - send(fd, resp.c_str(), resp.size(), 0); - close(fd); return; - } - string fullPath=wwwRoot+path; - - // Try cache - auto cdata = cache->get(fullPath); - if(cdata) { - string hdr="HTTP/1.0 200 OK\r\nContent-Length: "+to_string(cdata->size()) - +"\r\nContent-Type: "+guessMime(fullPath)+"\r\n\r\n"; - send(fd, hdr.c_str(), hdr.size(), 0); - send(fd, cdata->data(), cdata->size(), 0); - close(fd); return; + // evict until there's room + while (c->total_bytes + size > c->max_bytes) { + cache_evict_one(c); } + cache_entry_t *e = malloc(sizeof(cache_entry_t)); + e->key = strdup(key); + e->data = data; + e->size = size; + e->prev = NULL; e->next = c->head; + e->hash_next = NULL; + e->last_access = ++c->tick; + if (c->head) c->head->prev = e; + c->head = e; + if (!c->tail) c->tail = e; + // insert into hash bucket + uint64_t h = hash_fn(key) % c->nbuckets; + e->hash_next = c->buckets[h]; + c->buckets[h] = e; + c->total_bytes += size; +} - // Load file - ifstream f(fullPath, ios::binary); - if(!f) { - string resp="HTTP/1.0 404 Not Found\r\n\r\n"; - send(fd, resp.c_str(), resp.size(), 0); - close(fd); return; +static void cache_get(cache_t *c, const char *key, void **out_data, size_t *out_size) { + pthread_mutex_lock(&c->lock); + cache_entry_t *e = cache_lookup_locked(c, key); + if (e) { + *out_data = e->data; + *out_size = e->size; + } else { + *out_data = NULL; + *out_size = 0; } - vector data((istreambuf_iterator(f)), {}); - cache->put(fullPath, data); - string hdr="HTTP/1.0 200 OK\r\nContent-Length: "+to_string(data.size()) - +"\r\nContent-Type: "+guessMime(fullPath)+"\r\n\r\n"; - send(fd, hdr.c_str(), hdr.size(), 0); - send(fd, data.data(), data.size(), 0); - close(fd); -} - -/*** Main server loop ***/ -int main(int argc,char**argv){ - if(argc<4) { - cerr<<"Usage: "< \n"; return 1; + pthread_mutex_unlock(&c->lock); +} + +static void cache_put(cache_t *c, const char *key, void *data, size_t size) { + pthread_mutex_lock(&c->lock); + cache_put_locked(c, key, data, size); + pthread_mutex_unlock(&c->lock); +} + +/*** Simple thread pool + connection dispatch ***/ +typedef struct conn_task { + int fd; + struct conn_task *next; +} conn_task_t; + +typedef struct { + conn_task_t *head, *tail; + pthread_mutex_t lock; + pthread_cond_t cond; + bool stopping; +} task_queue_t; + +static void task_queue_init(task_queue_t *q) { + q->head = q->tail = NULL; + pthread_mutex_init(&q->lock, NULL); + pthread_cond_init(&q->cond, NULL); + q->stopping = false; +} + +static void task_queue_push(task_queue_t *q, int fd) { + conn_task_t *t = malloc(sizeof(conn_task_t)); + t->fd = fd; t->next = NULL; + pthread_mutex_lock(&q->lock); + if (q->tail) q->tail->next = t; + else q->head = t; + q->tail = t; + pthread_cond_signal(&q->cond); + pthread_mutex_unlock(&q->lock); +} + +static int task_queue_pop(task_queue_t *q) { + pthread_mutex_lock(&q->lock); + while (!q->head && !q->stopping) { + pthread_cond_wait(&q->cond, &q->lock); } - int port=stoi(argv[1]); - wwwRoot=argv[2]; - size_t cacheBytes=stoull(argv[3]); - cache=make_unique(cacheBytes); - signal(SIGINT, handleSigint); - - int listenfd=socket(AF_INET,SOCK_STREAM,0); - int one=1; setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one)); - sockaddr_in addr{}; addr.sin_family=AF_INET; addr.sin_port=htons(port); - addr.sin_addr.s_addr=INADDR_ANY; - bind(listenfd,(sockaddr*)&addr,sizeof(addr)); - listen(listenfd,128); - - LOG("Listening on port "<stopping && !q->head) { + pthread_mutex_unlock(&q->lock); + return -1; } + conn_task_t *t = q->head; + q->head = t->next; + if (!q->head) q->tail = NULL; + int fd = t->fd; + free(t); + pthread_mutex_unlock(&q->lock); + return fd; +} + +static void task_queue_stop(task_queue_t *q) { + pthread_mutex_lock(&q->lock); + q->stopping = true; + pthread_cond_broadcast(&q->cond); + pthread_mutex_unlock(&q->lock); +} + +/*** Minimal HTTP handling ***/ - LOG("Shutting down..."); - pool.shutdown(); - close(listenfd); +typedef struct { + int fd; + char method[8]; + char path[1024]; + char version[32]; +} http_req_t; + +static int http_parse_request(const char *buf, http_req_t *req) { + // Very minimal parsing: METHOD SP PATH SP VERSION CRLF + // e.g. "GET /index.html HTTP/1.1\r\n" + const char *p = buf; + if (sscanf(p, "%7s %1023s %31s", req->method, req->path, req->version) < 2) return -1; return 0; } + +static const char *guess_mime(const char *path) { + const char *ext = strrchr(path, '.'); + if (!ext) return "application/octet-stream"; + if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) return "text/html"; + if (strcmp(ext, ".css") == 0) return "text/css"; + if (strcmp(ext, ".js") == 0) return "application/javascript"; + if (strcmp(ext, ".png") == 0) return "image/png"; + if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg"; + if (strcmp(ext, ".gif") == 0) return "image/gif"; + if (strcmp(ext, ".svg") == 0) return "image/svg+xml"; + if (strcmp(ext, ".json") == 0) return "application/json"; + if (strcmp(ext, ".txt") == 0) return "text/plain"; + return "application/octet-stream"; +} + +/*** Server global state ***/ +static cache_t *global_cache = NULL; +static char *www_root = NULL; +static task_queue_t global_queue; + +/*** Worker logic: handle connection on fd ***/ +static void handle_client(int fd) { + arena_t arena; + arena_init(&arena, 16 * 1024); // small per-request arena + char buf[REQ_BUF_SIZE]; + ssize_t n = recv(fd, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + close(fd); + arena_free(&arena); + return; + } + buf[n] = '\0'; + http_req_t req = { .fd = fd }; + if (http_parse_request(buf, &req) != 0) { + // bad request + const char *resp = "HTTP/1.0 400 Bad Request\r\nContent-Length:11\r\n\r\nBad Request"; + send(fd, resp, strlen(resp), 0); + close(fd); + arena_free(&arena); + return; + } + // Only support GET + if (strcmp(req.method, "GET") != 0) { + const char *resp = "HTTP/1.0 405 Method Not Allowed\r\nContent-Length:18\r\n\r\nMethod Not Allowed"; + send(fd, resp, strlen(resp), 0); + close(fd); + arena_free(&arena); + return; + } + // Prevent path traversal + char clean_path[2048]; + if (strcmp(req.path, "/") == 0) strcpy(clean_path, "/index.html"); + else strncpy(clean_path, req.path, sizeof(clean_path)-1); + clean_path[sizeof(clean_path)-1] = '\0'; + if (strstr(clean_path, "..")) { + const char *resp = "HTTP/1.0 403 Forbidden\r\nContent-Length:9\r\n\r\nForbidden"; + send(fd, resp, strlen(resp), 0); + close(fd); + arena_free(&arena); + return; + } + // build full filesystem path + char fullpath[4096]; + snprintf(fullpath, sizeof(fullpath), "%s%s", www_root, clean_path); + // check cache + void *data = NULL; + size_t sz = 0; + cache_get(global_cache, fullpath, &data, &sz); + if (data) { + // send from cache + const char *mime = guess_mime(fullpath); + char hdr[256]; + int hdrlen = snprintf(hdr, sizeof(hdr), + "HTTP/1.0 200 OK\r\nContent-Length: %zu\r\nContent-Type: %s\r\n\r\n", sz, mime); + send(fd, hdr, hdrlen, 0); + send(fd, data diff --git a/C/prime_number_fuction.c b/C/prime_number_fuction.c new file mode 100644 index 00000000..e69de29b diff --git a/C/pyramid_pattern.c b/C/pyramid_pattern.c new file mode 100644 index 00000000..19a2321f --- /dev/null +++ b/C/pyramid_pattern.c @@ -0,0 +1,66 @@ +// The Pattern will look something like this +// 1 +// 1 2 1 +// 1 2 3 2 1 +// 1 2 3 4 3 2 1 +// 1 2 3 4 5 4 3 2 1 +// 1 2 3 4 3 2 1 +// 1 2 3 2 1 +// 1 2 1 +// 1 + + +#include + +int main() { + int n, i, j, k; + + // Input the number of rows (half of the diamond) + printf("Enter the number of rows: "); + scanf("%d", &n); + + // UPPER HALF of diamond + for (i = 1; i <= n; i++) { + // Print leading spaces + for (j = 1; j <= n - i; j++) { + printf(" "); + } + + // Print increasing numbers from 1 to i + for (j = 1; j <= i; j++) { + printf("%d ", j); + } + + // Print decreasing numbers from i-1 down to 1 + for (j = i - 1; j >= 1; j--) { + printf("%d ", j); + } + + // New line after each row + printf("\n"); + } + + // LOWER HALF of diamond + for (i = n - 1; i >= 1; i--) { + // Print leading spaces + for (j = 1; j <= n - i; j++) { + printf(" "); + } + + // Print increasing numbers from 1 to i + for (j = 1; j <= i; j++) { + printf("%d ", j); + } + + // Print decreasing numbers from i-1 down to 1 + for (j = i - 1; j >= 1; j--) { + printf("%d ", j); + } + + // New line after each row + printf("\n"); + } + + return 0; +} + diff --git a/C/race_circular_track_simulation.c b/C/race_circular_track_simulation.c new file mode 100644 index 00000000..1c473ec0 --- /dev/null +++ b/C/race_circular_track_simulation.c @@ -0,0 +1,190 @@ +#include +#include + +// --- Data Structure Definition --- + +/** + * @brief Represents a single segment or point on the circular race track. + * * This structure forms the node of the circular linked list. + */ +struct Node { + int id; // Unique identifier for the track segment (0 is the start/finish line). + struct Node *next; // Pointer to the next segment on the track, making it a circular list. +}; + +// --- Function Prototypes --- +struct Node *create_track(int n, struct Node *head); +int simulate_Race(int k, struct Node *head); + +// --- Core Function: Create Circular Track --- + +/** + * @brief Creates a circular race track (circular linked list). + * * The track has 'n' segments, with a total of (n+1) nodes (0 to n). + * The head node (id=0) links back to the last node (id=n), forming a circle. + * * @param n The number of track segments (nodes - 1). + * @param head Pointer to the head of the list (initially NULL). + * @return struct Node* The pointer to the head of the circular list (node with id=0). + */ +struct Node *create_track(int n, struct Node *head) { + struct Node *temp = NULL; + struct Node *prev = NULL; + + // Create n+1 nodes (from i=0 to i=n) + for (int i = 0; i <= n; i++) { + // Allocate memory for the new node (track segment) + temp = (struct Node *)malloc(sizeof(struct Node)); + + // Check if memory allocation failed + if (temp == NULL) { + fprintf(stderr, "Memory allocation failed!\n"); + // In a real application, you would need to free previously allocated memory here. + return NULL; + } + + temp->id = i; + temp->next = NULL; + + if (head == NULL) { + // First node is the head (Start/Finish Line: id=0) + head = temp; + } else { + // Link the previous node to the new node + prev->next = temp; + } + + // Move the 'previous' pointer forward + prev = temp; + } + + // Connect the last node (id=n) back to the head (id=0) to make the track circular + if (temp != NULL) { + temp->next = head; + } + + return head; +} + +// --- Core Function: Race Simulation (Lapping Challenge) --- + +/** + * @brief Simulates a race using the Tortoise and Hare (Floyd's) technique. + * * Dominic (Tortoise) moves 1 segment per turn. + * Stephano (Hare) moves 2 segments per turn. + * * The race ends if: + * 1. Stephano (faster) laps Dominic (slower) - Indicated by Dom == Steph. (Stephano wins this phase) + * 2. Dominic completes 'k' required laps without being lapped. (Dominic wins) + * * @param k The number of laps Dominic is required to finish. + * @param head The starting point (node with id=0). + * @return int Returns 0 upon completion. + */ +int simulate_Race(int k, struct Node *head) { + // Both racers start at the same position (head/id=0) + struct Node *Dom = head; + struct Node *Steph = head; + int laps = 0; // Counts the laps completed by Dominic (the slower racer) + + printf("\n--- Race Simulation Start ---\n"); + printf("Dominic speed: 1 segment/turn (Tortoise)\n"); + printf("Stephano speed: 2 segments/turn (Hare)\n"); + printf("Dominic's required laps: %d\n", k); + printf("Track segments start at id=0 (Start/Finish).\n\n"); + + // Race loop: continues as long as Dominic's required laps are not met + while (k > laps) { + // Safety check to ensure pointers are valid before moving + if (Dom == NULL || Steph == NULL || Steph->next == NULL) { + printf("Error: Invalid track structure (non-circular or too short).\n"); + return 0; + } + + // 1. Advance the Racers + Dom = Dom->next; // Dominic moves 1 step + Steph = Steph->next->next; // Stephano moves 2 steps + + // 2. Check for Lapping (Meeting Point) + // If the faster racer (Stephano) meets the slower racer (Dominic), + // it means Stephano has successfully lapped Dominic. + if (Dom == Steph) { + printf("Racer collision detected at segment id: %d!\n", Dom->id); + printf("Result: Stephano won the lapping challenge by catching Dominic!\n"); + return 0; + } + + // 3. Count Dominic's Laps + // We count a lap when Dominic (the slower one) crosses the start line (id=0) + // Note: The original code counted Stephano's lap, but since the end condition uses 'k' for Dom, + // it is more intuitive to track Dom's laps for the final goal check. + if (Dom->id == 0) { + laps++; + printf("Dominic finished lap %d of %d.\n", laps, k); + } + } + + // --- Race End Condition --- + + // If the loop finished because k <= laps, Dominic completed his required laps. + printf("\n--- Race Finished ---\n"); + printf("Result: Dominic finished his required %d laps without being lapped.\n", k); + printf("Dominic wins the distance challenge!\n"); + + return 0; +} + +// --- Main Program --- + +int main() { + int nodes; + int dom_laps; + + printf("Enter the number of track segments (e.g., 5 for a track with nodes 0 to 5): "); + // The number entered here is the 'n' in the create_track function. + if (scanf("%d", &nodes) != 1 || nodes < 1) { + printf("Invalid input for track segments.\n"); + return 1; + } + + printf("Enter the number of laps Dominic has to finish: "); + if (scanf("%d", &dom_laps) != 1 || dom_laps < 1) { + printf("Invalid input for laps.\n"); + return 1; + } + + struct Node *head = NULL; + + // Create and link the track + head = create_track(nodes, head); + + // Check for creation error + if (head == NULL) { + printf("Failed to create the track. Exiting.\n"); + return 1; + } + + // Run the simulation + simulate_Race(dom_laps, head); + + // --- Memory Cleanup --- + + // Free the dynamically allocated nodes to prevent memory leaks. + struct Node *current = head; + struct Node *temp_next = NULL; + + if (current != NULL) { + // Break the cycle at the head to allow proper traversal for freeing + struct Node *last_node = current; + while (last_node->next != head) { + last_node = last_node->next; + } + last_node->next = NULL; + + // Now traverse and free each node + while (current != NULL) { + temp_next = current->next; + free(current); + current = temp_next; + } + } + + return 0; +} \ No newline at end of file diff --git a/C/remove_duplicate_characters.c b/C/remove_duplicate_characters.c new file mode 100644 index 00000000..95ad0b22 --- /dev/null +++ b/C/remove_duplicate_characters.c @@ -0,0 +1,26 @@ +#include +#include + +void rm(char str[]) { + int n = strlen(str); + int i, j, k; + for(i = 0; i < n; i++) { + for(j = i + 1; str[j] != '\0'; ) { + if(str[i] == str[j]) { + for(k = j; str[k] != '\0'; k++) { + str[k] = str[k+1]; + } + } else { + j++; + } + } + } + printf("%s", str); +} + +int main() { + char str[100]; + scanf("%99s", str); + rm(str); + return 0; +} diff --git a/C/reverse_string_using_stack.c b/C/reverse_string_using_stack.c new file mode 100644 index 00000000..2f9b53b1 --- /dev/null +++ b/C/reverse_string_using_stack.c @@ -0,0 +1,47 @@ +#include +#include +#define MAX_SIZE 50 +char stack[MAX_SIZE]; +int top = -1; +void push(char item) +{ + if (top >= MAX_SIZE - 1) + { + printf("Stack Overflow!\n"); + } + else + { + stack[++top] = item; + } +} +char pop() +{ + if (top == -1) + { + printf("Stack Underflow!\n"); + return '\0'; + } + else + { + return stack[top--]; + } +} +int main() +{ + char str[MAX_SIZE]; + int i; + printf("Enter a string: "); + gets(str); + str[strlen(str)] ='\0'; + for (i = 0; i < strlen(str); i++) + { + push(str[i]); + } + printf("Reversed string: "); + while (top != -1) + { + printf("%c", pop()); + } + printf("\n"); + return 0; +} \ No newline at end of file diff --git a/C/revesearray.c b/C/revesearray.c new file mode 100644 index 00000000..3d1a25ad --- /dev/null +++ b/C/revesearray.c @@ -0,0 +1,27 @@ +#include + +// Function to reverse array elements in place +void reverseArray(int arr[], int n) { + int start = 0, end = n - 1, temp; + while (start < end) { + // Swap elements at start and end + temp = arr[start]; + arr[start] = arr[end]; + arr[end] = temp; + start++; + end--; + } +} + +int main() { + int arr[] = {1, 2, 3, 4, 5}; + int n = sizeof(arr) / sizeof(arr[0]); + + reverseArray(arr, n); + + printf("Reversed Array: "); + for (int i = 0; i < n; i++) + printf("%d ", arr[i]); + + return 0; +} diff --git a/C/search_in_rotated_sorted_array.c b/C/search_in_rotated_sorted_array.c new file mode 100644 index 00000000..e69de29b diff --git a/C/selection_sort.c b/C/selection_sort.c new file mode 100644 index 00000000..df6bfee7 --- /dev/null +++ b/C/selection_sort.c @@ -0,0 +1,38 @@ +#include + +int main() { + int arr[100], n, i, j, temp, minIndex; + + // Input array size + printf("Enter number of elements: "); + scanf("%d", &n); + + // Input elements + printf("Enter %d elements:\n", n); + for(i = 0; i < n; i++) { + scanf("%d", &arr[i]); + } + + // Selection sort logic + for(i = 0; i < n - 1; i++) { + minIndex = i; + for(j = i + 1; j < n; j++) { + if(arr[j] < arr[minIndex]) { + minIndex = j; + } + } + + // Swap smallest with first element of unsorted part + temp = arr[i]; + arr[i] = arr[minIndex]; + arr[minIndex] = temp; + } + + // Print sorted array + printf("Sorted array in ascending order:\n"); + for(i = 0; i < n; i++) { + printf("%d ", arr[i]); + } + + return 0; +} diff --git a/C/selectionsort.c b/C/selectionsort.c new file mode 100644 index 00000000..4e91a49d --- /dev/null +++ b/C/selectionsort.c @@ -0,0 +1,28 @@ +#include + +int main() +{ + int n; + int min; + int temp; + printf("Enter the number of elements in array\n"); + scanf("%d",&n); + int arr[n]; + printf("Enter the elements of array\n"); + for (int i=0;i + +void bubbleSort(int arr[], int n) { + int i, j, temp; + + // Outer loop for the number of passes + for (i = 0; i < n - 1; i++) { + // Inner loop for comparison and swapping + // n - i - 1 because the last 'i' elements are already in place + for (j = 0; j < n - i - 1; j++) { + // Compare adjacent elements + if (arr[j] > arr[j + 1]) { + // Swap arr[j] and arr[j+1] + temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } +} + +// Function to print the array +void printArray(int arr[], int size) { + for (int i = 0; i < size; i++) { + printf("%d ", arr[i]); + } + printf("\n"); +} + +int main() { + int data[] = {64, 34, 25, 12, 22, 11, 90}; + int n = sizeof(data) / sizeof(data[0]); + + printf("Original array: "); + printArray(data, n); + + // Sort the array + bubbleSort(data, n); + + printf("Sorted array: "); + printArray(data, n); + + return 0; +} \ No newline at end of file diff --git a/C/stringpalindrome.c b/C/stringpalindrome.c new file mode 100644 index 00000000..2ed29f66 --- /dev/null +++ b/C/stringpalindrome.c @@ -0,0 +1,27 @@ +#include +#include + +void palin(int start , int end , char str[]) +{ + if (str[start]!=str[end]) + { + printf("The string is not a palindrome"); + return; + } + if (start>=end) + { + printf("The string is a palindrome"); + return; + } + palin(start+1,end-1,str); +} + + +int main() +{ + char str[100]; + printf("Enter the string\n"); + scanf("%s",str); + size_t n = strlen(str); + palin(0,n-1,str); +} \ No newline at end of file diff --git a/Contribution_Dsa.md b/Contribution_Dsa.md new file mode 100644 index 00000000..7f993606 --- /dev/null +++ b/Contribution_Dsa.md @@ -0,0 +1,26 @@ +# 🧩 Contributing Guidelines + +Welcome to the **DSA Problems & Solutions Repository**! +We appreciate your interest in contributing. Please follow the guidelines below to maintain quality and consistency across all submissions. + +--- + +## ✅ Do’s + +### 1. Write Clean, Readable, and Well-Commented Code +- Use **meaningful variable names** and **consistent indentation**. +- Add comments to explain: + - Your **approach / algorithm** + - **Time and Space complexity** + - Any edge cases handled + +### 2. Add Only DSA-Related Problems and Solutions +- Accepted topics include: + - Arrays, Strings, Linked Lists, Stacks, Queues, Trees, Graphs, Hashing, Dynamic Programming, etc. +- At the top of each file, include: + ```cpp + // Problem: Two Sum + // Source: LeetCode #1 + // Approach: Hashmap + // Time Complexity: O(n) + // Space Complexity: O(n) diff --git a/DSA#/DSA-ALGORITHM b/DSA#/DSA-ALGORITHM new file mode 100644 index 00000000..318da3a2 --- /dev/null +++ b/DSA#/DSA-ALGORITHM @@ -0,0 +1,60 @@ +1. Linked List Sum + +class Node: + def __init__(self, data): + self.data, self.next = data, None + +def sum_linked_list(head): + total = 0 + while head: + total += head.data + head = head.next + return total + +# Example +head = Node(5); head.next = Node(10); head.next.next = Node(15) +print("Linked List Sum:", sum_linked_list(head)) + + +--- + +2. Half Linked List (Print first half) + +def print_half_list(head): + slow, fast = head, head + while fast and fast.next: + print(slow.data, end=" -> ") + slow, fast = slow.next, fast.next.next + print("END") + +# Example +head = Node(1); head.next = Node(2); head.next.next = Node(3) +head.next.next.next = Node(4); head.next.next.next.next = Node(5) +print_half_list(head) # Output: 1 -> 2 -> END + + +--- + +3. Hello World (ASCII Style) + +def hello_world(): + codes = [72,101,108,108,111,32,87,111,114,108,100] + return "".join(chr(c) for c in codes) + +print(hello_world()) + + +--- + +4. Sum of 1D Array + +def sum_array(arr): + total = 0 + for num in arr: + total += num + return total + +print("Array Sum:", sum_array([1,2,3,4,5])) + + +--- diff --git a/DSA#/Hard-LinkedListproblems.cpp b/DSA#/Hard-LinkedListproblems.cpp new file mode 100644 index 00000000..c708b999 --- /dev/null +++ b/DSA#/Hard-LinkedListproblems.cpp @@ -0,0 +1,182 @@ +#include +#include +using namespace std; + +//Delete all occurances of a key in dll + + +struct ListNode +{ + int val; + ListNode *next; + ListNode *prev; + ListNode() + { + val = 0; + next = nullptr; + prev = nullptr; + } + ListNode(int data1) + { + val = data1; + next = nullptr; + prev = nullptr; + } + ListNode(int data1, ListNode *next1, ListNode *prev1) + { + val = data1; + next = next1; + prev = prev1; + } +}; + + +class Solution { +public: + ListNode * deleteAllOccurrences(ListNode* head, int target) { + if (!head) return nullptr; +ListNode* temp = head; + +while(temp!=nullptr){ + + ListNode* front=temp->next; +if(temp->val==target){ + if(temp==head){ + head=head->next; + if(head) head->prev=nullptr; + }else{ + if(temp->prev) temp->prev->next=temp->next; + if(temp->next) temp->next->prev=temp->prev; + } + delete temp; + } + temp=front; +} +return head; + } +}; + +// Find Pairs with Given Sum in Doubly Linked List + + +class Solution2 { +public: + vector> findPairsWithGivenSum(ListNode* head, int target) { + vector> result; + if(!head) return result; + ListNode* left=head; + ListNode* right=head; + while(right->next!=nullptr){ +right=right->next; + } + while(left!=nullptr && right!=nullptr && left!=right && right->next!=left){ + int sum=left->val+right->val; + if(sum==target){ + result.push_back({left->val,right->val}); +left=left->next; +right=right->prev; + }else if(sumnext; + }else{ + right=right->prev; + } + } + return result; + } +}; + +// Remove duplicated from sorted DLL +class Solution { +public: + ListNode * removeDuplicates(ListNode *head) { +if(head==nullptr || head->next==nullptr){ + return head; +} + +ListNode* temp=head; + +while(temp!=nullptr && temp->next!=nullptr){ + + if(temp->val==temp->next->val){ + ListNode* dup=temp->next; + temp->next = dup->next; + +if(dup->next!=nullptr) +dup->next->prev=temp; +delete dup; + }else{ + temp=temp->next; + } +} +return head; + } +}; +class Solution { +public: + ListNode* reverseKGroup(ListNode* head, int k) { + if (head == nullptr || k == 1) return head; + + + ListNode* dummy = new ListNode(0); + dummy->next = head; + + ListNode* prevGroupEnd = dummy; + + while (true) { + + ListNode* kth = prevGroupEnd; + for (int i = 0; i < k && kth != nullptr; i++) { + kth = kth->next; + } + if (kth == nullptr) break; + + + ListNode* groupStart = prevGroupEnd->next; + ListNode* nextGroupStart = kth->next; + + ListNode* prev = nextGroupStart; + ListNode* curr = groupStart; + while (curr != nextGroupStart) { + ListNode* temp = curr->next; + curr->next = prev; + prev = curr; + curr = temp; + } + + prevGroupEnd->next = kth; + prevGroupEnd = groupStart; + } + + return dummy->next; + } +}; +// Merge k Sorted Lists +#include +class Solution { +public: + struct compare { + bool operator()(ListNode* a, ListNode* b) { + return a->val > b->val; + } + }; + + ListNode* mergeKLists(vector& lists) { + priority_queue, compare> pq; + for (auto node : lists) { + if (node) pq.push(node); + } + + ListNode* dummy = new ListNode(0); + ListNode* tail = dummy; + + while (!pq.empty()) { + ListNode* curr = pq.top(); + pq.pop(); + tail->next = curr; + tail = tail->next; + if (curr->next) pq.push(curr->next); + } + + return dummy->next; + } +}; diff --git a/DSA#/JobScheduling.java b/DSA#/JobScheduling.java new file mode 100644 index 00000000..b9a5bec4 --- /dev/null +++ b/DSA#/JobScheduling.java @@ -0,0 +1,65 @@ +// // <<<< Maximum Profit in Job Scheduling >>>> + +// /* You are given n jobs, where every job is represented by: +// i. startTime[i]: the start time of the job. +// ii. endTime[i]: the end time of the job. +// iii. profit[i]: the profit you earn by completing the job. +// Two jobs cannot be taken that overlap in time. +// Return the maximum profit you can earn such that there are no two overlapping jobs in your selected subset. + +// Note: A job ending at time X is allowed to overlap with another job that starts exactly at time X. */ + + + +// // <<<< Solution >>>> + +// /** +// * This implementation uses a combination of dynamic programming with memoization +// * and binary search for an efficient O(N log N) solution. +// */ + + +import java.util.Arrays; +import java.util.Comparator; + +public class JobScheduling { + + static class Job { + int s, e, p; + Job(int s, int e, int p) { this.s = s; this.e = e; this.p = p; } + } + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + Job[] jobs = new Job[n]; + for (int i = 0; i < n; i++) jobs[i] = new Job(startTime[i], endTime[i], profit[i]); + + Arrays.sort(jobs, Comparator.comparingInt(j -> j.s)); + int[] starts = new int[n]; + for (int i = 0; i < n; i++) starts[i] = jobs[i].s; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int next = findNextJob(starts, jobs[i].e); + dp[i] = Math.max(jobs[i].p + dp[next], dp[i + 1]); // take or skip + } + return dp[0]; + } + + private int findNextJob(int[] arr, int target) { + int l = 0, r = arr.length - 1, ans = arr.length; + while (l <= r) { + int m = l + (r - l) / 2; + if (arr[m] >= target) { ans = m; r = m - 1; } else l = m + 1; + } + return ans; + } + + public static void main(String[] args) { + JobScheduling js = new JobScheduling(); + int[] start = {1, 2, 3}; + int[] end = {3, 4, 5}; + int[] prof = {50, 10, 40}; + System.out.println("Maximum Profit = " + js.jobScheduling(start, end, prof)); + } +} diff --git a/DSA#/LRU_Cache.cpp b/DSA#/LRU_Cache.cpp new file mode 100644 index 00000000..e3149d4c --- /dev/null +++ b/DSA#/LRU_Cache.cpp @@ -0,0 +1,120 @@ +// 🧠 DSA Problem: LRU Cache Implementation +// 📁 Folder: DSA/Design/ +// 🧑 Author: Aditya +// 📝 Description: +// Implement a Least Recently Used (LRU) Cache using +// HashMap + Doubly Linked List for O(1) get() and put() operations. + +#include +using namespace std; + +// Node structure for doubly linked list +class Node { +public: + int key, value; + Node* prev; + Node* next; + Node(int k, int v) { + key = k; + value = v; + prev = next = nullptr; + } +}; + +class LRUCache { +private: + int capacity; + unordered_map cache; + Node* head; + Node* tail; + + // Helper to add a node right after the head + void addNode(Node* node) { + node->next = head->next; + node->prev = head; + head->next->prev = node; + head->next = node; + } + + // Helper to remove a node + void removeNode(Node* node) { + Node* prev = node->prev; + Node* next = node->next; + prev->next = next; + next->prev = prev; + } + + // Move a node to the front (most recently used) + void moveToHead(Node* node) { + removeNode(node); + addNode(node); + } + + // Pop least recently used (tail->prev) + Node* popTail() { + Node* res = tail->prev; + removeNode(res); + return res; + } + +public: + LRUCache(int cap) { + capacity = cap; + head = new Node(0, 0); + tail = new Node(0, 0); + head->next = tail; + tail->prev = head; + } + + int get(int key) { + if (cache.find(key) == cache.end()) + return -1; + + Node* node = cache[key]; + moveToHead(node); + return node->value; + } + + void put(int key, int value) { + if (cache.find(key) != cache.end()) { + Node* node = cache[key]; + node->value = value; + moveToHead(node); + } else { + Node* node = new Node(key, value); + cache[key] = node; + addNode(node); + + if (cache.size() > capacity) { + Node* tailNode = popTail(); + cache.erase(tailNode->key); + delete tailNode; + } + } + } + + // Optional: Print cache state (for debugging) + void printCache() { + Node* curr = head->next; + cout << "Cache state (MRU -> LRU): "; + while (curr != tail) { + cout << "[" << curr->key << ":" << curr->value << "] "; + curr = curr->next; + } + cout << endl; + } +}; + +// 🧪 Example test +int main() { + LRUCache cache(2); + cache.put(1, 1); + cache.put(2, 2); + cout << cache.get(1) << endl; // 1 + cache.put(3, 3); // evicts key 2 + cout << cache.get(2) << endl; // -1 + cache.put(4, 4); // evicts key 1 + cout << cache.get(1) << endl; // -1 + cout << cache.get(3) << endl; // 3 + cout << cache.get(4) << endl; // 4 +} diff --git a/DSA#/LinkedlistAlgos.cpp b/DSA#/LinkedlistAlgos.cpp new file mode 100644 index 00000000..70dab468 --- /dev/null +++ b/DSA#/LinkedlistAlgos.cpp @@ -0,0 +1,45 @@ +struct ListNode { + int val; + ListNode* next; + ListNode(int v) : val(v), next(nullptr) {} +}; + +//Detect Cycle in Linked List (Floyd’s Algorithm) +bool hasCycle(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) return true; + } + return false; +} +//Detect Cycle & Remove Cycle (Floyd’s Algorithm, Singly) +bool detectCycle(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) return true; + } + return false; +} + +void removeCycle(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head; + do { + if (!fast || !fast->next) return; + slow = slow->next; + fast = fast->next->next; + } while (slow != fast); + + fast = head; + while (slow->next != fast->next) { + slow = slow->next; + fast = fast->next; + } + slow->next = nullptr; +} diff --git a/DSA#/NOTES.md b/DSA#/NOTES.md new file mode 100644 index 00000000..76f766f1 --- /dev/null +++ b/DSA#/NOTES.md @@ -0,0 +1,88 @@ +# DSA Notes + +A compact collection of Data Structures & Algorithms notes, patterns, and study checklist. + +## Table of Contents +- Purpose +- Study checklist +- Core data structures (summary) +- Common algorithms & patterns +- Time complexity quick reference +- Problem patterns and tips +- Recommended practice problems & resources + +## Purpose +Keep short, high-value reminders for solving typical DSA problems during interview prep and practice. + +## Study checklist +- [ ] Arrays & Strings basics +- [ ] Two pointers & sliding window patterns +- [ ] Linked lists (insert/delete/reverse) +- [ ] Stacks & queues +- [ ] Trees (BST, traversal, LCA) +- [ ] Graphs (BFS, DFS, shortest paths) +- [ ] Heaps & priority queues +- [ ] Hash tables / maps / sets +- [ ] Sorting & searching +- [ ] Dynamic programming (top-down & bottom-up) +- [ ] Greedy algorithms +- [ ] Backtracking +- [ ] Complexity analysis practice + +## Core data structures (short) +- Array: contiguous memory, O(1) access, O(n) insert/delete worst-case. +- Linked List: O(1) insert/delete at known position, O(n) search/access. +- Stack/Queue: LIFO / FIFO, use for recursion elimination, scheduling. +- Hash map/set: average O(1) lookup/insert, watch for collisions and worst-case. +- Heap: O(log n) push/pop, used for top-k, priority scheduling. +- Tree (binary/AVL/Red-Black): hierarchical data, BST supports ordered ops O(h). +- Graph: adjacency list (sparse) vs matrix (dense). + +## Common algorithms & patterns +- Two pointers: sorted arrays, pair-sum, remove duplicates, partitioning. +- Sliding window: subarray problems with variable window (max/min sum, num distinct). +- Fast & slow pointers: detect cycles, middle of list. +- DFS/BFS: tree/graph traversal, connected components, topological sort (Kahn/DFS). +- Dynamic Programming: identify state, transition, base case, iterative vs memoized. +- Greedy: pick local optimum, prove with exchange argument. +- Backtracking: generate combinations/permutations, search with pruning. +- Divide & conquer: mergesort, quicksort, binary search. + +## Time complexity quick reference +- Access array by index: O(1) +- Search unsorted array: O(n) +- Binary search (sorted): O(log n) +- Insertion in array (shift): O(n) +- Hash table ops: average O(1) +- BST ops: O(h) (balanced: O(log n)) +- Heap push/pop: O(log n) +- Merge sort / Heap sort: O(n log n) +- Quick sort: average O(n log n), worst O(n^2) +- DFS/BFS: O(V + E) +- DP (typical knapsack / longest common subsequence): O(n*m) depending on states + +## Problem patterns & tips +- When you see "subarray" think sliding window or prefix sums. +- When asked for "k-th" or "top-k", use heaps or selection algorithms. +- When constraints are large (n up to 10^5+), avoid O(n^2) solutions. +- Use hash maps for frequency/count problems and two-sum variants. +- Convert recursive brute force to DP by identifying overlapping subproblems. +- Sketch small examples and invariants before coding. + +## Recommended practice problems +- Arrays: Two Sum, 3Sum, Longest Subarray with Sum K +- Strings: Longest Palindromic Substring, Anagram grouping +- Linked List: Reverse Linked List, Detect Cycle, Merge K Sorted Lists +- Trees: Binary Tree Maximum Path Sum, Serialize/Deserialize +- Graphs: Course Schedule, Number of Islands, Dijkstra problems +- DP: Knapsack, Longest Increasing Subsequence, Edit Distance +- Backtracking: Permutations, Combination Sum + +## Resources +- "Introduction to Algorithms" (CLRS) — deep theory +- "Algorithms" by Sedgewick — practical +- LeetCode / HackerRank / Codeforces for practice +- Grokking the Coding Interview (patterns) + +--- + diff --git a/DSA#/RatInAMaze DSA Algo CPP b/DSA#/RatInAMaze DSA Algo CPP new file mode 100644 index 00000000..eac99073 --- /dev/null +++ b/DSA#/RatInAMaze DSA Algo CPP @@ -0,0 +1,56 @@ +class Solution { + public: + void pushing(int x, int y, vector> &v,string temp, vector &ans, vector> &vis) { + int n = v.size(); + if (x == n-1 && y == n-1) { + ans.push_back(temp); + return; + + } + if (y+1=0 && v[x][y-1] && vis[x][y-1] == 0) { + vis[x][y-1] = 1; + temp += "L"; + pushing(x,y-1,v,temp,ans,vis); + temp.pop_back(); + vis[x][y-1] = 0; + + } + if (x+1=0 && v[x-1][y] && vis[x-1][y] == 0) { + vis[x-1][y] = 1; + temp += "U"; + pushing(x-1,y,v,temp,ans,vis); + temp.pop_back(); + vis[x-1][y] = 0; + + } + return; + + } + vector ratInMaze(vector>& maze) { + int n = maze.size(); + string ans = ""; + vector v; + vector> vis(n,vector(n,0)); + vis[0][0] = 1; + pushing(0,0,maze,ans,v,vis); + sort(v.begin(),v.end()); + return v; + + } +}; diff --git a/DSA#/Sorting-Algos/BubbleSort.java b/DSA#/Sorting-Algos/BubbleSort.java new file mode 100644 index 00000000..c487094d --- /dev/null +++ b/DSA#/Sorting-Algos/BubbleSort.java @@ -0,0 +1,27 @@ +//Bubble Sort: Compare the adjacent elements and swap them if they are in wrong order repeatedly, until the array is sorted. + +public class BubbleSort { + public static void bubbleSort(int[] arr){ + int n =arr.length; + for(int i=0; iarr[j+1]){ + //Swap using a temp variable + int temp=arr[j]; + arr[j] = arr[j+1]; + arr[j+1] = temp; + } + } + } + } + public static void main(String[] args){ + int[] numbers={9,2,6,3,8}; + bubbleSort(numbers); + for(int num: numbers){ + System.out.print(num+" "); + } + } + +} +//Time Complexity: O(n^2) +//Preferred when dataset is small / Nearly sorted \ No newline at end of file diff --git a/DSA#/Sorting-Algos/CountingSort.cpp b/DSA#/Sorting-Algos/CountingSort.cpp new file mode 100644 index 00000000..afd4a06c --- /dev/null +++ b/DSA#/Sorting-Algos/CountingSort.cpp @@ -0,0 +1,34 @@ +#include +#include +using namespace std; + +void countingSort(int arr[], int n) { + int max = *max_element(arr, arr + n); + int count[max + 1] = {0}; + + for (int i = 0; i < n; i++) + count[arr[i]]++; + + int index = 0; + for (int i = 0; i <= max; i++) + while (count[i]--) + arr[index++] = i; +} + +void printArray(int arr[], int n) { + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + cout << endl; +} + +int main() { + int arr[] = {4, 2, 2, 8, 3, 3, 1}; + int n = sizeof(arr) / sizeof(arr[0]); + + countingSort(arr, n); + + cout << "Sorted array: "; + printArray(arr, n); + + return 0; +} diff --git a/DSA#/Sorting-Algos/HeapSort.java b/DSA#/Sorting-Algos/HeapSort.java new file mode 100644 index 00000000..073d19de --- /dev/null +++ b/DSA#/Sorting-Algos/HeapSort.java @@ -0,0 +1,63 @@ +public class HeapSort { + + public void sort(int arr[]) { + int n = arr.length; + + // Build heap (rearrange array) + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // One by one extract an element from heap + for (int i = n - 1; i > 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // To heapify a subtree rooted with node i which is an index in arr[]. n is size of heap + void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int l = 2 * i + 1; // left = 2*i + 1 + int r = 2 * i + 2; // right = 2*i + 2 + + // If left child is larger than root + if (l < n && arr[l] > arr[largest]) + largest = l; + + // If right child is larger than largest so far + if (r < n && arr[r] > arr[largest]) + largest = r; + + // If largest is not root + if (largest != i) { + int swap = arr[i]; + arr[i] = arr[largest]; + arr[largest] = swap; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = {12, 11, 13, 5, 6, 7}; + HeapSort hs = new HeapSort(); + hs.sort(arr); + + System.out.println("Sorted array is"); + printArray(arr); + } +} \ No newline at end of file diff --git a/DSA#/Sorting-Algos/Huffman_Algorithm.cpp b/DSA#/Sorting-Algos/Huffman_Algorithm.cpp new file mode 100644 index 00000000..60f36ae6 --- /dev/null +++ b/DSA#/Sorting-Algos/Huffman_Algorithm.cpp @@ -0,0 +1,56 @@ +#include +using namespace std; + +// Node for Huffman Tree +struct Node { + char ch; + int freq; + Node *left, *right; + Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} +}; + +// Comparator for priority queue +struct compare { + bool operator()(Node* a, Node* b) { + return a->freq > b->freq; + } +}; + +// Recursive function to print codes +void printCodes(Node* root, string code) { + if(!root) return; + if(!root->left && !root->right) { + cout << root->ch << ": " << code << endl; + } + printCodes(root->left, code + "0"); + printCodes(root->right, code + "1"); +} + +int main() { + int n; + cout << "Enter number of characters: "; + cin >> n; + + vector chars(n); + vector freq(n); + cout << "Enter characters:\n"; + for(int i = 0; i < n; i++) cin >> chars[i]; + cout << "Enter their frequencies:\n"; + for(int i = 0; i < n; i++) cin >> freq[i]; + + priority_queue, compare> pq; + for(int i = 0; i < n; i++) pq.push(new Node(chars[i], freq[i])); + + while(pq.size() > 1) { + Node* left = pq.top(); pq.pop(); + Node* right = pq.top(); pq.pop(); + Node* merged = new Node('\0', left->freq + right->freq); + merged->left = left; + merged->right = right; + pq.push(merged); + } + + cout << "Huffman Codes:\n"; + printCodes(pq.top(), ""); + return 0; +} diff --git a/DSA#/Sorting-Algos/MergeSort.java b/DSA#/Sorting-Algos/MergeSort.java new file mode 100644 index 00000000..e531abd1 --- /dev/null +++ b/DSA#/Sorting-Algos/MergeSort.java @@ -0,0 +1,67 @@ +// Based on divide and conquer algorithm +// Divide the array into two halves and recursively sort them +// Then merge the arrays to get a sorted array + +public class MergeSort{ + public static void mergeSort(int[] arr, int left, int right){ + if(left< right){ + int mid = left + (right-left) /2; //the middle element index + mergeSort(arr, left, mid); //left subarray + mergeSort(arr, mid+1, right); //right subarray + merge(arr, left, mid, right); + } + } + + //to merge both sorted subarrays + private static void merge(int[] arr, int left, int mid, int right){ + int n1= mid-left+1; + int n2= right-mid; + + int[] leftArray = new int[n1]; + int[] rightArray = new int[n2]; + + for(int i=0; i +#include +using namespace std; + +int getMax(int arr[], int n) { + return *max_element(arr, arr + n); +} + +void countingSortRadix(int arr[], int n, int exp) { + int output[n]; + int count[10] = {0}; + + for (int i = 0; i < n; i++) + count[(arr[i] / exp) % 10]++; + + for (int i = 1; i < 10; i++) + count[i] += count[i - 1]; + + for (int i = n - 1; i >= 0; i--) { + output[count[(arr[i] / exp) % 10] - 1] = arr[i]; + count[(arr[i] / exp) % 10]--; + } + + for (int i = 0; i < n; i++) + arr[i] = output[i]; +} + +void radixSort(int arr[], int n) { + int m = getMax(arr, n); + for (int exp = 1; m / exp > 0; exp *= 10) + countingSortRadix(arr, n, exp); +} + +void printArray(int arr[], int n) { + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + cout << endl; +} + +int main() { + int arr[] = {170, 45, 75, 90, 802, 24, 2, 66}; + int n = sizeof(arr) / sizeof(arr[0]); + + radixSort(arr, n); + + cout << "Sorted array: "; + printArray(arr, n); + + return 0; +} diff --git a/DSA#/Sorting-Algos/ShellSort.cpp b/DSA#/Sorting-Algos/ShellSort.cpp new file mode 100644 index 00000000..c5028697 --- /dev/null +++ b/DSA#/Sorting-Algos/ShellSort.cpp @@ -0,0 +1,32 @@ +#include +using namespace std; + +void shellSort(int arr[], int n) { + for (int gap = n/2; gap > 0; gap /= 2) { + for (int i = gap; i < n; i++) { + int temp = arr[i]; + int j; + for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) + arr[j] = arr[j - gap]; + arr[j] = temp; + } + } +} + +void printArray(int arr[], int n) { + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + cout << endl; +} + +int main() { + int arr[] = {23, 12, 1, 8, 34, 54, 2, 3}; + int n = sizeof(arr) / sizeof(arr[0]); + + shellSort(arr, n); + + cout << "Sorted array: "; + printArray(arr, n); + + return 0; +} diff --git a/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/MergeSort.py b/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/MergeSort.py new file mode 100644 index 00000000..d5091b12 --- /dev/null +++ b/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/MergeSort.py @@ -0,0 +1,34 @@ +def merge_sort(arr): + if len(arr) <= 1: + return arr + + mid = len(arr) // 2 + + left = merge_sort(arr[:mid]) + + right = merge_sort(arr[mid:]) + + return merge(left, right) + + +def merge(left, right): + result = [] + i = j = 0 + + while i < len(left) and j < len(right): + if left[i] < right[j]: + result.append(left[i]) + i += 1 + else: + result.append(right[j]) + j += 1 + + result += left[i:] + result += right[j:] + return result + + +arr = [5, 3, 8, 4, 2, 7, 1, 10] +print("Original array:", arr) +sorted_arr = merge_sort(arr) +print("Sorted array:", sorted_arr) diff --git a/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/QuickSort.py b/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/QuickSort.py new file mode 100644 index 00000000..b0e8f22a --- /dev/null +++ b/DSA#/Sorting-Algos/Sorting-Algorithms-Using-Python/QuickSort.py @@ -0,0 +1,23 @@ +def quicksort(arr): + """ + Sorts a list using the Quick Sort algorithm. + """ + if len(arr) <= 1: + return arr + else: + pivot = arr[0] # Choosing the first element as the pivot + less = [x for x in arr[1:] if x < pivot] + greater = [x for x in arr[1:] if x >= pivot] + return quicksort(less) + [pivot] + quicksort(greater) + +# Example usage: +if __name__ == "__main__": + unsorted_list = [10, 7, 8, 9, 1, 5, 2, 6, 3, 4] + print("Unsorted list:", unsorted_list) + sorted_list = quicksort(unsorted_list) + print("Sorted list:", sorted_list) + + unsorted_list_2 = [64, 34, 25, 12, 22, 11, 90] + print("Unsorted list 2:", unsorted_list_2) + sorted_list_2 = quicksort(unsorted_list_2) + print("Sorted list 2:", sorted_list_2) \ No newline at end of file diff --git a/DSA#/Sorting-Algos/heap_sort.cpp b/DSA#/Sorting-Algos/heap_sort.cpp new file mode 100644 index 00000000..bf241905 --- /dev/null +++ b/DSA#/Sorting-Algos/heap_sort.cpp @@ -0,0 +1,45 @@ +#include +using namespace std; + +void heapify(int arr[], int n, int i) { + int largest = i; + int l = 2*i + 1; + int r = 2*i + 2; + + if (l < n && arr[l] > arr[largest]) + largest = l; + if (r < n && arr[r] > arr[largest]) + largest = r; + + if (largest != i) { + swap(arr[i], arr[largest]); + heapify(arr, n, largest); + } +} + +void heapSort(int arr[], int n) { + for (int i = n/2 - 1; i >= 0; i--) + heapify(arr, n, i); + for (int i = n - 1; i > 0; i--) { + swap(arr[0], arr[i]); + heapify(arr, i, 0); + } +} + +void printArray(int arr[], int n) { + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + cout << endl; +} + +int main() { + int arr[] = {12, 11, 13, 5, 6, 7}; + int n = sizeof(arr) / sizeof(arr[0]); + + heapSort(arr, n); + + cout << "Sorted array: "; + printArray(arr, n); + + return 0; +} diff --git a/DSA#/Sorting-Algos/selectionSort.java b/DSA#/Sorting-Algos/selectionSort.java new file mode 100644 index 00000000..7cfc3d3f --- /dev/null +++ b/DSA#/Sorting-Algos/selectionSort.java @@ -0,0 +1,25 @@ +# Selection Sort in Python + +def selection_sort(arr): + # Loop through all elements in the array + for i in range(len(arr)): + # Assume the current index has the smallest element + min_index = i + + # Find the smallest element in the remaining unsorted part + for j in range(i + 1, len(arr)): + if arr[j] < arr[min_index]: + min_index = j # Update index of smallest element + + # Swap the found smallest element with the first element of unsorted part + arr[i], arr[min_index] = arr[min_index], arr[i] + + return arr # Return the sorted array + + +# Example usage +arr = [64, 25, 12, 22, 11] +print("Original array:", arr) + +sorted_arr = selection_sort(arr) +print("Sorted array:", sorted_arr) diff --git a/DSA#/Sorting-Algos/selection_sort.cpp b/DSA#/Sorting-Algos/selection_sort.cpp new file mode 100644 index 00000000..e0224c67 --- /dev/null +++ b/DSA#/Sorting-Algos/selection_sort.cpp @@ -0,0 +1,30 @@ +#include +using namespace std; + +void selectionSort(int arr[], int n) { + for (int i = 0; i < n - 1; i++) { + int minIdx = i; + for (int j = i + 1; j < n; j++) + if (arr[j] < arr[minIdx]) + minIdx = j; + swap(arr[i], arr[minIdx]); + } +} + +void printArray(int arr[], int n) { + for (int i = 0; i < n; i++) + cout << arr[i] << " "; + cout << endl; +} + +int main() { + int arr[] = {29, 10, 14, 37, 13}; + int n = sizeof(arr) / sizeof(arr[0]); + + selectionSort(arr, n); + + cout << "Sorted array: "; + printArray(arr, n); + + return 0; +} diff --git a/DSA#/heap_operation.py b/DSA#/heap_operation.py new file mode 100644 index 00000000..bf1bad5a --- /dev/null +++ b/DSA#/heap_operation.py @@ -0,0 +1,55 @@ +class Heap: + def __init__(self): + self.heap = [] + + def createHeap(self, c): + for e in c: + self.insert(e) + + def insert(self, e): + self.heap.append(e) + + index = len(self.heap) - 1 + parent = (index - 1) // 2 + + while index > 0 and self.heap[parent] < self.heap[index]: + self.heap[index], self.heap[parent] = self.heap[parent], self.heap[index] + index = parent + parent = (index - 1) // 2 + + def top(self): + if not self.heap: + return None + return self.heap[0] + + def delete(self): + if len(self.heap) == 0: + print("Empty") + return None + + if len(self.heap) == 1: + return self.heap.pop() + + maxm = self.heap[0] + self.heap[0] = self.heap.pop() + + index = 0 + + while True: + left_child_index = (2 * index) + 1 + right_child_index = (2 * index) + 2 + largest = index + + if left_child_index < len(self.heap) and self.heap[left_child_index] > self.heap[largest]: + largest = left_child_index + + if right_child_index < len(self.heap) and self.heap[right_child_index] > self.heap[largest]: + largest = right_child_index + + if largest != index: + self.heap[index], self.heap[largest] = self.heap[largest], self.heap[index] + index = largest + else: + break + + return maxm \ No newline at end of file diff --git a/DSA#/linkedlist_operation.py b/DSA#/linkedlist_operation.py new file mode 100644 index 00000000..0f501029 --- /dev/null +++ b/DSA#/linkedlist_operation.py @@ -0,0 +1,67 @@ +class Node: + def __init__(self, val): + self.val = val + self.next = None + +class SLL: + def __init__(self): + self.head = None + def printList(self): + if self.head is None: + print("Empty List") + else: + temp = self.head + while temp: + print(temp.val) + temp = temp.next + def insertBegin(self): + val = input() + nodeBegin = Node(val) + nodeBegin.next = self.head + self.head = nodeBegin + def deleteBegin(self): + temp = self.head + self.head=temp.next + temp=None + def insertPos(self): + pos=int(input()) + val=input() + np=Node(val) + temp=self.head.next + prev=self.head + for i in range(pos-1): + temp=temp.next + prev=prev.next + prev.next=np + np.next=temp + def deletePos(self): + pos=int(input()) + temp=self.head.next + prev=self.head + for i in range(1,pos-1): + temp=temp.next + prev=prev.next + prev.next=temp.next + temp.next=None + def insertEnd(self): + val=input() + ne=Node(val) + temp=self.head + while temp.next: + temp=temp.next + temp.next=ne + def deleteEnd(self): + temp=self.head.next + prev=self.head + while temp.next: + temp=temp.next + prev=prev.next + prev.next=None + + +obj = SLL() +obj.insertBegin() +obj.insertBegin() +obj.insertBegin() +obj.deleteEnd() +obj.printList() \ No newline at end of file diff --git a/DSA-Project/DSA-Project.iml b/DSA-Project/DSA-Project.iml new file mode 100644 index 00000000..93cddcd4 --- /dev/null +++ b/DSA-Project/DSA-Project.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/DSA-Project/src/Main.java b/DSA-Project/src/Main.java new file mode 100644 index 00000000..a2806cbb --- /dev/null +++ b/DSA-Project/src/Main.java @@ -0,0 +1,44 @@ +import java.util.Scanner; +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + TodoList todo=new TodoList(); + Scanner sc = new Scanner(System.in); + int choice; + + do { + System.out.println("\n1. Add Task\n2. Mark Done\n3. Remove Task\n4. Display Tasks\n0. Exit"); + choice = sc.nextInt(); + sc.nextLine(); // consume newline + + switch (choice) { + case 1: + System.out.print("Enter task description: "); + String desc = sc.nextLine(); + todo.addTask(desc); + break; + case 2: + System.out.print("Enter task number to mark done: "); + int doneIndex = sc.nextInt(); + todo.markTaskDone(doneIndex); + break; + case 3: + System.out.print("Enter task number to remove: "); + int remIndex = sc.nextInt(); + todo.removeTask(remIndex); + break; + case 4: + todo.displayTasks(); + break; + case 0: + System.out.println("Exiting..."); + break; + default: + System.out.println("Invalid option."); + } + } while (choice != 0); + + sc.close(); + } +} \ No newline at end of file diff --git a/DSA-Project/src/Task.java b/DSA-Project/src/Task.java new file mode 100644 index 00000000..2740aac3 --- /dev/null +++ b/DSA-Project/src/Task.java @@ -0,0 +1,22 @@ +public class Task { + private String description; + private boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getDescription() { + return description; + } + + public boolean isDone() { + return isDone; + } + + public void markDone() { + isDone = true; + } + +} diff --git a/DSA-Project/src/TodoList.java b/DSA-Project/src/TodoList.java new file mode 100644 index 00000000..427db9e1 --- /dev/null +++ b/DSA-Project/src/TodoList.java @@ -0,0 +1,38 @@ +import java.util.LinkedList; + +public class TodoList { + private LinkedList tasks; + + public TodoList() { + tasks = new LinkedList<>(); + } + + // Add task + public void addTask(String description) { + tasks.add(new Task(description)); + } + + // Mark a task done + public void markTaskDone(int index) { + if (index >= 0 && index < tasks.size()) { + tasks.get(index).markDone(); + } + } + + // Remove a task + public void removeTask(int index) { + if (index >= 0 && index < tasks.size()) { + tasks.remove(index); + } + } + + // Display the list + public void displayTasks() { + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); + String status = task.isDone() ? "[Done]" : "[Pending]"; + System.out.println(i + " - " + status + " " + task.getDescription()); + } + } + +} diff --git a/Dfs.java b/Dfs.java new file mode 100644 index 00000000..b686f54e --- /dev/null +++ b/Dfs.java @@ -0,0 +1,53 @@ +import java.util.*; + +public class Dfs { + private int V; // Number of vertices + private LinkedList[] adj; // Adjacency lists + + // Constructor + public Dfs(int v) { + V = v; + adj = new LinkedList[v]; + for (int i = 0; i < v; i++) { + adj[i] = new LinkedList<>(); + } + } + + // Add an edge to the graph + public void addEdge(int v, int w) { + adj[v].add(w); + } + + // DFS traversal from a given source + public void DFS(int start) { + boolean[] visited = new boolean[V]; + dfsUtil(start, visited); + } + + // Utility function for DFS + private void dfsUtil(int v, boolean[] visited) { + visited[v] = true; + System.out.print(v + " "); + + for (int n : adj[v]) { + if (!visited[n]) { + dfsUtil(n, visited); + } + } + } + + // Sample usage + public static void main(String[] args) { + Dfs graph = new Dfs(4); + + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(1, 2); + graph.addEdge(2, 0); + graph.addEdge(2, 3); + graph.addEdge(3, 3); + + System.out.println("DFS starting from vertex 2:"); + graph.DFS(2); + } +} diff --git a/DoublyLinkedList.java b/DoublyLinkedList.java new file mode 100644 index 00000000..31e7d3d0 --- /dev/null +++ b/DoublyLinkedList.java @@ -0,0 +1,113 @@ +import java.util.NoSuchElementException; + +public class DoublyLinkedList { + + /** + * Private inner class to represent a node in the list. + * It holds the data, a reference to the next node, and a reference to the previous node. + */ + private class Node { + int data; + Node next; + Node prev; + + public Node(int data) { + this.data = data; + this.next = null; // Initially null + this.prev = null; // Initially null + } + } + + // --- List Attributes --- + private Node head; // Pointer to the first node + private Node tail; // Pointer to the last node + private int size; // Number of nodes in the list + + /** + * Constructor for an empty DoublyLinkedList. + */ + public DoublyLinkedList() { + this.head = null; + this.tail = null; + this.size = 0; + } + + // --- Core Methods --- + + /** + * Checks if the list is empty. + * @return true if the list has 0 elements, false otherwise. + */ + public boolean isEmpty() { + return size == 0; + } + + /** + * Returns the number of elements in the list. + * @return the size of the list. + */ + public int getSize() { + return size; + } + + /** + * Adds a new node to the front (head) of the list. + * @param data The data for the new node. + */ + public void addFirst(int data) { + Node newNode = new Node(data); + + if (isEmpty()) { + // If list is empty, new node is both head and tail + head = newNode; + tail = newNode; + } else { + // 1. Link new node to the old head + newNode.next = head; + // 2. Link old head back to the new node + head.prev = newNode; + // 3. Move head pointer to the new node + head = newNode; + } + size++; + } + + /** + * Adds a new node to the end (tail) of the list. + * @param data The data for the new node. + */ + public void addLast(int data) { + Node newNode = new Node(data); + + if (isEmpty()) { + // If list is empty, new node is both head and tail + head = newNode; + tail = newNode; + } else { + // 1. Link old tail to the new node + tail.next = newNode; + // 2. Link new node back to the old tail + newNode.prev = tail; + // 3. Move tail pointer to the new node + tail = newNode; + } + size++; + } + + /** + * Removes and returns the first node (head) from the list. + * @return The data of the removed node. + * @throws NoSuchElementException if the list is empty. + */ + public int removeFirst() { + if (isEmpty()) { + throw new NoSuchElementException("Cannot remove from an empty list."); + } + + int data = head.data; + + if (head == tail) { + // Case 1: Only one node in the list + head = null; + tail = null; + } else { diff --git a/Dsa_sum b/Dsa_sum new file mode 100644 index 00000000..ca4a74ba --- /dev/null +++ b/Dsa_sum @@ -0,0 +1,29 @@ +def subset_sum(nums, target): + result = [] + + def backtrack(start, path, current_sum): + # If current sum equals target, record this subset + if current_sum == target: + result.append(path[:]) + return + + # If sum exceeds target, stop exploring further + if current_sum > target: + return + + # Try adding each remaining element + for i in range(start, len(nums)): + path.append(nums[i]) + backtrack(i + 1, path, current_sum + nums[i]) + path.pop() + + backtrack(0, [], 0) + return result + + +# Example +nums = [3, 4, 5, 2] +target = 7 +solutions = subset_sum(nums, target) + +print("Subsets that sum to", target, "are:", solutions) diff --git a/FactorialExample.class b/FactorialExample.class new file mode 100644 index 00000000..17f1d9fa Binary files /dev/null and b/FactorialExample.class differ diff --git a/FactorialExample.java b/FactorialExample.java new file mode 100644 index 00000000..605d2eb0 --- /dev/null +++ b/FactorialExample.java @@ -0,0 +1,21 @@ +import java.util.*; + +public class FactorialExample { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter a non-negative integer: "); + int num = sc.nextInt(); + long factorial = 1; + + if (num < 0) { + System.out.println("Factorial is not defined for negative numbers."); + } else { + for (int i = 1; i <= num; i++) { + factorial *= i; + } + System.out.println("Factorial of " + num + " = " + factorial); + } + + sc.close(); + } +} diff --git a/Int_as_sum_of_powers.py b/Int_as_sum_of_powers.py new file mode 100644 index 00000000..dcf37756 --- /dev/null +++ b/Int_as_sum_of_powers.py @@ -0,0 +1,20 @@ +class Solution: + def numberOfWays(self, n: int, x: int) -> int: + MOD=10**9+7 + # find largest m with m^x<=n + m=int(n**(1.0/x)) + # fix rounding edge-cases + while (m+1)**x<=n: + m+=1 + while m**x>n: + m-=1 + + powers=[i**x for i in range(1,m+1)] + dp=[0]*(n+1) + dp[0]=1 + + for v in powers: + for s in range(n,v-1,-1): # iterate backwards for 0/1 usage + dp[s]=(dp[s]+dp[s-v])%MOD + + return dp[n] diff --git a/LIS_Dsa b/LIS_Dsa new file mode 100644 index 00000000..bb1c9f58 --- /dev/null +++ b/LIS_Dsa @@ -0,0 +1,42 @@ +# ------------------------------------------------------------ +# Problem: Longest Increasing Subsequence +# Difficulty: Advanced +# Source: LeetCode #300 +# ------------------------------------------------------------ +# Statement: +# Given an integer array nums, return the length of the longest +# strictly increasing subsequence. +# +# Example: +# Input: nums = [10,9,2,5,3,7,101,18] +# Output: 4 # LIS: [2,3,7,101] +# +# Approach: +# - Use Dynamic Programming with a patience sorting technique. +# - Maintain a list `sub` representing the smallest possible +# tail of all increasing subsequences with length i+1. +# - Use binary search to find the position to replace or append. +# +# Time Complexity: O(n log n) +# Space Complexity: O(n) +# ------------------------------------------------------------ + +from bisect import bisect_left + +def length_of_lis(nums): + sub = [] # Holds the smallest tail of all increasing subsequences + for num in nums: + i = bisect_left(sub, num) # Find position to replace or append + if i == len(sub): + sub.append(num) # Extend the subsequence + else: + sub[i] = num # Replace to keep smaller tail + return len(sub) + +# ------------------------------------------------------------ +# Driver Code for Testing +# ------------------------------------------------------------ +if __name__ == "__main__": + nums = [10, 9, 2, 5, 3, 7, 101, 18] + print("Input Array:", nums) + print("Length of LIS:", length_of_lis(nums)) diff --git a/LIS_Dsa_Code.md b/LIS_Dsa_Code.md new file mode 100644 index 00000000..bb1c9f58 --- /dev/null +++ b/LIS_Dsa_Code.md @@ -0,0 +1,42 @@ +# ------------------------------------------------------------ +# Problem: Longest Increasing Subsequence +# Difficulty: Advanced +# Source: LeetCode #300 +# ------------------------------------------------------------ +# Statement: +# Given an integer array nums, return the length of the longest +# strictly increasing subsequence. +# +# Example: +# Input: nums = [10,9,2,5,3,7,101,18] +# Output: 4 # LIS: [2,3,7,101] +# +# Approach: +# - Use Dynamic Programming with a patience sorting technique. +# - Maintain a list `sub` representing the smallest possible +# tail of all increasing subsequences with length i+1. +# - Use binary search to find the position to replace or append. +# +# Time Complexity: O(n log n) +# Space Complexity: O(n) +# ------------------------------------------------------------ + +from bisect import bisect_left + +def length_of_lis(nums): + sub = [] # Holds the smallest tail of all increasing subsequences + for num in nums: + i = bisect_left(sub, num) # Find position to replace or append + if i == len(sub): + sub.append(num) # Extend the subsequence + else: + sub[i] = num # Replace to keep smaller tail + return len(sub) + +# ------------------------------------------------------------ +# Driver Code for Testing +# ------------------------------------------------------------ +if __name__ == "__main__": + nums = [10, 9, 2, 5, 3, 7, 101, 18] + print("Input Array:", nums) + print("Length of LIS:", length_of_lis(nums)) diff --git a/LongestCommonPrefix.java b/LongestCommonPrefix.java new file mode 100644 index 00000000..3aa4d626 --- /dev/null +++ b/LongestCommonPrefix.java @@ -0,0 +1,45 @@ +LongestCommonPrefix + +import java.util.Scanner; +import java.util.Arrays; + +public class LongestCommonPrefix { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Taking user input for number of strings + System.out.print("Enter number of strings: "); + int n = sc.nextInt(); + sc.nextLine(); // consume newline + + String[] strs = new String[n]; + System.out.println("Enter the strings one by one:"); + for (int i = 0; i < n; i++) { + strs[i] = sc.nextLine(); + } + + // Call the function + String result = longestCommonPrefix(strs); + System.out.println("Longest Common Prefix: " + result); + + sc.close(); + } + + public static String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + + Arrays.sort(strs); // Sort the array + + String first = strs[0]; + String last = strs[strs.length - 1]; + + int i = 0; + while (i < first.length() && i < last.length() && first.charAt(i) == last.charAt(i)) { + i++; + } + + return first.substring(0, i); + } +} diff --git a/MergeSort.java b/MergeSort.java new file mode 100644 index 00000000..61ec1d89 --- /dev/null +++ b/MergeSort.java @@ -0,0 +1,107 @@ +import java.util.Arrays; + +public class MergeSort { + + /** + * The main function that sorts arr[l...r] using merge() + * This is the recursive "divide" part. + * + * @param arr The array to be sorted + * @param left The starting index + * @param right The ending index + */ + public void sort(int arr[], int left, int right) { + if (left < right) { + // Find the middle point + int middle = (left + right) / 2; + + // Recursively sort the first and second halves + sort(arr, left, middle); + sort(arr, middle + 1, right); + + // Merge the sorted halves + merge(arr, left, middle, right); + } + } + + /** + * Merges two subarrays of arr[]. + * First subarray is arr[left...middle] + * Second subarray is arr[middle+1...right] + * This is the "conquer" part. + * + * @param arr The original array + * @param left The starting index of the first subarray + * @param middle The ending index of the first subarray + * @param right The ending index of the second subarray + */ + void merge(int arr[], int left, int middle, int right) { + // Find sizes of two subarrays to be merged + int n1 = middle - left + 1; + int n2 = right - middle; + + // --- Create temporary arrays --- + int L[] = new int[n1]; + int R[] = new int[n2]; + + // --- Copy data to temp arrays --- + for (int i = 0; i < n1; ++i) { + L[i] = arr[left + i]; + } + for (int j = 0; j < n2; ++j) { + R[j] = arr[middle + 1 + j]; + } + + // --- Merge the temp arrays --- + + // Initial indexes of first and second subarrays + int i = 0, j = 0; + + // Initial index of the merged subarray in the original array + int k = left; + + // Compare elements from L and R and place the smaller one into arr + while (i < n1 && j < n2) { + if (L[i] <= R[j]) { + arr[k] = L[i]; + i++; + } else { + arr[k] = R[j]; + j++; + } + k++; + } + + // --- Copy remaining elements (if any) --- + + // Copy remaining elements of L[] if any + while (i < n1) { + arr[k] = L[i]; + i++; + k++; + } + + // Copy remaining elements of R[] if any + while (j < n2) { + arr[k] = R[j]; + j++; + k++; + } + } + + /** + * A main method to test the merge sort implementation. + */ + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + + System.out.println("Original array:"); + System.out.println(Arrays.toString(arr)); + + MergeSort ob = new MergeSort(); + ob.sort(arr, 0, arr.length - 1); + + System.out.println("\nSorted array:"); + System.out.println(Arrays.toString(arr)); + } +} diff --git a/MoveZeros.java b/MoveZeros.java new file mode 100644 index 00000000..96d0c7bb --- /dev/null +++ b/MoveZeros.java @@ -0,0 +1,22 @@ +//https://leetcode.com/problems/move-zeroes/ + +class Solution { + public void moveZeroes(int[] nums) { + int cnt = 0; + int index = 0; + for(int i=0 ; i < nums.length ; i++){ + if(nums[i] == 0) cnt++; + else{ + nums[index] = nums[i]; + index++; + } + + } + + for(int i=nums.length-1 ; i>=nums.length - cnt ; i--){ + nums[i] = 0; + } + + for(int i=0 ; i < nums.length ; i++) System.out.print(nums[i]+" "); + } +} diff --git a/MultiplicationTable.class b/MultiplicationTable.class new file mode 100644 index 00000000..13a38720 Binary files /dev/null and b/MultiplicationTable.class differ diff --git a/MultiplicationTable.java b/MultiplicationTable.java new file mode 100644 index 00000000..3fa8f2dd --- /dev/null +++ b/MultiplicationTable.java @@ -0,0 +1,21 @@ +import java.util.Scanner; + +public class MultiplicationTable { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + System.out.print("Enter a number to print its multiplication table: "); + int number = sc.nextInt(); + + System.out.print("Enter how many multiples you want: "); + int limit = sc.nextInt(); + + System.out.println("\nMultiplication Table of " + number + ":"); + + for (int i = 1; i <= limit; i++) { + System.out.println(number + " x " + i + " = " + (number * i)); + } + + sc.close(); + } +} diff --git a/Product of Array Except Self.cpp b/Product of Array Except Self.cpp new file mode 100644 index 00000000..5e253f22 --- /dev/null +++ b/Product of Array Except Self.cpp @@ -0,0 +1,31 @@ +#include +#include +using namespace std; + +// Function to calculate the product of all +// elements except the current element +vector productExceptSelf(vector& arr) { + int n = arr.size(); + + // Fill result array with 1 + vector res(n, 1); + + for (int i = 0; i < n; i++) { + + // Compute product of all elements except arr[i] + for (int j = 0; j < n; j++) { + if (i != j) + res[i] *= arr[j]; + } + } + + return res; +} + +int main() { + vector arr = {10, 3, 5, 6, 2}; + vector res = productExceptSelf(arr); + for (int val : res) + cout << val << " "; + return 0; +} diff --git a/Projects/android/NotesApp/app/src/main/java/com/example/notesapp/MainActivity.java b/Projects/android/NotesApp/app/src/main/java/com/example/notesapp/MainActivity.java new file mode 100644 index 00000000..e64978f5 --- /dev/null +++ b/Projects/android/NotesApp/app/src/main/java/com/example/notesapp/MainActivity.java @@ -0,0 +1,47 @@ +package com.example.notesapp; + +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; +import android.content.SharedPreferences; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +public class MainActivity extends AppCompatActivity { + + private EditText notesInput; + private Button saveBtn, clearBtn; + private SharedPreferences sharedPreferences; + private static final String PREFS_NAME = "MyNotesPref"; + private static final String KEY_NOTE = "note"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + notesInput = findViewById(R.id.notesInput); + saveBtn = findViewById(R.id.saveBtn); + clearBtn = findViewById(R.id.clearBtn); + + sharedPreferences = getSharedPreferences(PREFS_NAME, MODE_PRIVATE); + + // Load saved note + String savedNote = sharedPreferences.getString(KEY_NOTE, ""); + notesInput.setText(savedNote); + + // Save note + saveBtn.setOnClickListener(v -> { + String note = notesInput.getText().toString(); + sharedPreferences.edit().putString(KEY_NOTE, note).apply(); + Toast.makeText(this, "📝 Note saved!", Toast.LENGTH_SHORT).show(); + }); + + // Clear note + clearBtn.setOnClickListener(v -> { + notesInput.setText(""); + sharedPreferences.edit().remove(KEY_NOTE).apply(); + Toast.makeText(this, "🗑️ Note cleared!", Toast.LENGTH_SHORT).show(); + }); + } +} diff --git a/Projects/android/NotesApp/app/src/main/res/layout/activity_main.xml b/Projects/android/NotesApp/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..18ca4805 --- /dev/null +++ b/Projects/android/NotesApp/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/html/Forms_All_input_types.html b/html/Forms_All_input_types.html new file mode 100644 index 00000000..5170dbb4 --- /dev/null +++ b/html/Forms_All_input_types.html @@ -0,0 +1,224 @@ + + + + + + Comprehensive HTML Form Demo + + + +

All Input Types Form

+ +
+
+ Personal Information + + + + + + + + + + + + + + + + + + +
+ +
+ Contact + + + + + + + + + + + +
+ +
+ + Preferences + + + + + + + + + + +
+ +
+ Dates & Numbers + + + + + + + + + + + + + + + + + + + + 5 + + + + + + + + +
+ +
+ Files + + +
+ +
+ Misc + + + + + 70% + + +
+ + + +
+ + + \ No newline at end of file diff --git a/html/HappyBday.html b/html/HappyBday.html new file mode 100644 index 00000000..603afc5d --- /dev/null +++ b/html/HappyBday.html @@ -0,0 +1,387 @@ + + + + + +Happy Birthday Card 🎉 + + + +
+
+
+
🎈 Creative Happy Birthday Card
+
Enter a name and press Surprise! — enjoy an animated card, tune & confetti.
+
+ +
+ + + +
+ +
+
Tip: click "Surprise!" multiple times for more confetti and sound variations.
+
+ +
+ Made with ❤️ — customize colors and text freely. +
+
+ +
+
+ + + +
+ + +
Happy Birthday!
+
A joyful day full of laughter, cake, and sparkling moments.
+ +
Click Surprise! to open me ✨
+
+ + + +
+
+
+ + + + diff --git a/html/RandomColourGenerator.html b/html/RandomColourGenerator.html new file mode 100644 index 00000000..d60b1b57 --- /dev/null +++ b/html/RandomColourGenerator.html @@ -0,0 +1,29 @@ + + + + + + Random Color Generator + + + +

Random Color Generator

+
+

Click the button to generate a color!

+ + + + + diff --git a/html/RandomQuoteGeneratoor.html b/html/RandomQuoteGeneratoor.html new file mode 100644 index 00000000..57fd9149 --- /dev/null +++ b/html/RandomQuoteGeneratoor.html @@ -0,0 +1,34 @@ + + + + + + + Random Quote Generator + + + +

Random Quote Generator

+

Click the button to get a quote!

+ + + + + diff --git a/html/RandomQuoteGenerator.html b/html/RandomQuoteGenerator.html new file mode 100644 index 00000000..be55947f --- /dev/null +++ b/html/RandomQuoteGenerator.html @@ -0,0 +1,33 @@ + + + + + + Random Quote Generator + + + +

Random Quote Generator

+

Click the button to get a quote!

+ + + + + diff --git a/html/Valentine_project.html b/html/Valentine_project.html new file mode 100644 index 00000000..70414d46 --- /dev/null +++ b/html/Valentine_project.html @@ -0,0 +1,131 @@ + + + + + + + Valentine Project + + + + +
+ 💖 + 💗 + 💞 + 💘 + 💝 + 💓 +
+ +
+
Happy Valentine’s Day! ❤️
+ + + + + + \ No newline at end of file diff --git a/html/ageCalculator.html b/html/ageCalculator.html new file mode 100644 index 00000000..213c2f07 --- /dev/null +++ b/html/ageCalculator.html @@ -0,0 +1,513 @@ + + + + + + Age Calculator + + + +
+

🎂 Age Calculator

+

Calculate your exact age in years, months, and days

+ +
+
+ +
+ + + +
+
Please enter a valid date
+
+ +
+ OR +
+ +
+ +
+ +
+
Please select a valid date
+
+ + +
+ +
+
Your Age Is
+ +
+
+ 0 + Years +
+
+ 0 + Months +
+
+ 0 + Days +
+
+ +
+
+ Total Months + 0 +
+
+ Total Weeks + 0 +
+
+ Total Days + 0 +
+
+ Total Hours + 0 +
+
+ Total Minutes + 0 +
+
+ +
+
Next Birthday In
+
0 days
+
+
+
+ + + + \ No newline at end of file diff --git a/html/calculator.html b/html/calculator.html new file mode 100644 index 00000000..22a3ceb0 --- /dev/null +++ b/html/calculator.html @@ -0,0 +1,109 @@ + + + + + + Document + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + diff --git a/html/catchFallingObject.html b/html/catchFallingObject.html new file mode 100644 index 00000000..5f2a2d22 --- /dev/null +++ b/html/catchFallingObject.html @@ -0,0 +1,69 @@ + + + + + + Catch the Falling Object + + + + + + + \ No newline at end of file diff --git a/html/catch_the_ball.html b/html/catch_the_ball.html new file mode 100644 index 00000000..e7eb8c16 --- /dev/null +++ b/html/catch_the_ball.html @@ -0,0 +1,180 @@ + + + + + + Catch the Ball Game + + + +
+
Score: 0
+
+
+
+

Game Over!

+

Your final score: 0

+ +
+
+ + + + diff --git a/html/counter.html b/html/counter.html new file mode 100644 index 00000000..30cf5f73 --- /dev/null +++ b/html/counter.html @@ -0,0 +1,67 @@ + + + + + + Counter + + + +

My Counter

+

0

+
+ + + +
+ + + \ No newline at end of file diff --git a/html/digital_greeting_card.html b/html/digital_greeting_card.html new file mode 100644 index 00000000..eba9e731 --- /dev/null +++ b/html/digital_greeting_card.html @@ -0,0 +1,214 @@ + + + + + + 💌 Digital Greeting Card Maker + + + + +

💌 Digital Greeting Card Maker

+ +
+ + + + + + + + + + + + + +
+ +
+
+

Your message will appear here 💖

+
+ +
Made with ❤️ for Hacktoberfest 2025
+ + + + diff --git a/html/max-xor-trie.html b/html/max-xor-trie.html new file mode 100644 index 00000000..429e9759 --- /dev/null +++ b/html/max-xor-trie.html @@ -0,0 +1,150 @@ + + + + + +Binary Trie — Max XOR Pair + + + +

Binary Trie — Max XOR Pair (small DSA demo)

+

Paste integers (comma or space separated), or generate a random set. Click Find max XOR.

+ +
+ +
+ +
+ + +
Bit-width: + +
+
+ +
+
+ + + + + diff --git a/html/numberguess.html b/html/numberguess.html new file mode 100644 index 00000000..9e6779a9 --- /dev/null +++ b/html/numberguess.html @@ -0,0 +1,155 @@ + + + + + + Number Guess + + +
+
+

Number Guess 🔢

+

I'm thinking of a number between 1 and 100. Can you guess it in 10 tries?

+
+ +
+
+ + + +
+ +
Make your first guess!
+ +
+
+
Attempts left
+
10
+
+
+
Your guesses
+
+
+
+ + +
+ +
+ Tip: Use hints to zero in quickly. + Hint +
+
+ + + + + diff --git a/html/quizgame.html b/html/quizgame.html new file mode 100644 index 00000000..cb7882de --- /dev/null +++ b/html/quizgame.html @@ -0,0 +1,273 @@ + + + + JavaScript Quiz App + + + +
+

Quiz App

+
+
+ + + +
+ + + \ No newline at end of file diff --git a/html/simplefarminggmae.html b/html/simplefarminggmae.html new file mode 100644 index 00000000..e4ce4943 --- /dev/null +++ b/html/simplefarminggmae.html @@ -0,0 +1,186 @@ + + + + + + Simple Farming Game + + + +

Simple Farming Game

+
+ +
+
Score: 0Harvest crops to earn points
+
Water: 3Use W to water (speeds growth)
+
Time: 0sElapsed
+
+ + +
+
+ + + + diff --git a/html/simplemanufacturingame.html b/html/simplemanufacturingame.html new file mode 100644 index 00000000..b8855182 --- /dev/null +++ b/html/simplemanufacturingame.html @@ -0,0 +1,208 @@ + + + + + + Simple Manufacturing Game + + + +

Simple Manufacturing Game

+
+ +
+
Score: 0Deliver assembled products
+
Carrying: NonePick raw parts and assemble
+
Time: 0sElapsed
+
+ + +
+
+ + + + diff --git a/html/stack-visualizer.html b/html/stack-visualizer.html new file mode 100644 index 00000000..18fdcfb9 --- /dev/null +++ b/html/stack-visualizer.html @@ -0,0 +1,667 @@ + + + + + + Stack Visualizer - LIFO Data Structure + + + +
+
+

📚 Stack Visualizer

+

Learn LIFO (Last In, First Out) Data Structure

+
+ +
+ +
+

Stack Operations

+
Push & Pop elements in LIFO order
+
+ + +
+ +
+ + +
+
📊 Stack Visualization
+
+
+
🎯
+
Stack is Empty
+
+
+
+ + +
+
⚙️ Controls
+
+ +
+
+ + + +
+
+ + +
+
+
Size
+
0
+
+
+
Top Element
+
-
+
+
+ + +
+
💡 What is a Stack?
+
+ A Stack is a linear data structure that follows the LIFO (Last In, First Out) principle: +
+
    +
  • Push: Add an element to the top
  • +
  • Pop: Remove the top element
  • +
  • LIFO: Last element pushed is first to be popped
  • +
  • Use Cases: Undo/Redo, Function calls, Expression evaluation
  • +
+
+
+
+
+ + + + diff --git a/html/taskManager.html b/html/taskManager.html new file mode 100644 index 00000000..5b156f2c --- /dev/null +++ b/html/taskManager.html @@ -0,0 +1,116 @@ + + + + + + Task Manager + + + +
+

🗂️ Task Manager

+ + +
    + +
    + + + + diff --git a/html/tiktaktoe.html b/html/tiktaktoe.html new file mode 100644 index 00000000..8ef276b2 --- /dev/null +++ b/html/tiktaktoe.html @@ -0,0 +1,245 @@ + + + + + + Tic‑Tac‑Toe — Single HTML File + + + +
    +

    🎮 Tic‑Tac‑Toe

    +
    +
    Turn: X
    + +
    + +
    + +
    + +
    + + + + +
    + + +
    + + + + diff --git a/html/to_do_list.html b/html/to_do_list.html new file mode 100644 index 00000000..c8d71b14 --- /dev/null +++ b/html/to_do_list.html @@ -0,0 +1,468 @@ + + + + + + Online Notepad + + + + + + +
    +
    +
    +

    📝 Online Notepad

    +
    +
    +
    + +
    + +
    + + + + + + + + + + +
    +
    + +
    + + + + + + +
    + +
    +
    +
    EditorSaved
    + +
    + +
    + + +
    + + + + diff --git a/iterative_traversals.py b/iterative_traversals.py new file mode 100644 index 00000000..e69de29b diff --git a/java/.DS_Store b/java/.DS_Store new file mode 100644 index 00000000..053a375f Binary files /dev/null and b/java/.DS_Store differ diff --git a/java/.idea/.gitignore b/java/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/java/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/java/.idea/misc.xml b/java/.idea/misc.xml new file mode 100644 index 00000000..6f29fee2 --- /dev/null +++ b/java/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java/.idea/modules.xml b/java/.idea/modules.xml new file mode 100644 index 00000000..07f2a9b1 --- /dev/null +++ b/java/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/java/.idea/vcs.xml b/java/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/java/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java/0295-find-median-from-data-stream.java b/java/0295-find-median-from-data-stream.java new file mode 100644 index 00000000..b0fd304d --- /dev/null +++ b/java/0295-find-median-from-data-stream.java @@ -0,0 +1,24 @@ +class MedianFinder { + public void addNum(int num) { + if (maxHeap.isEmpty() || num <= maxHeap.peek()) + maxHeap.offer(num); + else + minHeap.offer(num); + + // Balance two heaps s.t. + // |maxHeap| >= |minHeap| and |maxHeap| - |minHeap| <= 1 + if (maxHeap.size() < minHeap.size()) + maxHeap.offer(minHeap.poll()); + else if (maxHeap.size() - minHeap.size() > 1) + minHeap.offer(maxHeap.poll()); + } + + public double findMedian() { + if (maxHeap.size() == minHeap.size()) + return (double) (maxHeap.peek() + minHeap.peek()) / 2.0; + return (double) maxHeap.peek(); + } + + private Queue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + private Queue minHeap = new PriorityQueue<>(); +} \ No newline at end of file diff --git a/java/0345-reverse-vowels-of-a-string.java b/java/0345-reverse-vowels-of-a-string.java new file mode 100644 index 00000000..093d09a3 --- /dev/null +++ b/java/0345-reverse-vowels-of-a-string.java @@ -0,0 +1,21 @@ +class Solution { + public String reverseVowels(String s) { + final String vowels = "aeiouAEIOU"; + StringBuilder sb = new StringBuilder(s); + int l = 0; + int r = s.length() - 1; + + while (l < r) { + while (l < r && !vowels.contains("" + sb.charAt(l))) + ++l; + while (l < r && !vowels.contains("" + sb.charAt(r))) + --r; + sb.setCharAt(l, s.charAt(r)); + sb.setCharAt(r, s.charAt(l)); + ++l; + --r; + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/java/0380-insert-delete-getrandom-o1.java b/java/0380-insert-delete-getrandom-o1.java new file mode 100644 index 00000000..652cd06e --- /dev/null +++ b/java/0380-insert-delete-getrandom-o1.java @@ -0,0 +1,37 @@ +class RandomizedSet { + public: + + bool insert(int val) { + if (valToIndex.count(val)) + return false; + + valToIndex[val] = vals.size(); + vals.push_back(val); + return true; + } + + /** Removes a value from the set. Returns true if the set contained the + * specified element. */ + bool remove(int val) { + if (!valToIndex.count(val)) + return false; + + const int index = valToIndex[val]; + // Following two lines order are important when vals.size() == 1 + valToIndex[vals.back()] = index; + valToIndex.erase(val); + vals[index] = vals.back(); + vals.pop_back(); + return true; + } + + /** Get a random element from the set. */ + int getRandom() { + const int index = rand() % vals.size(); + return vals[index]; + } + + private: + unordered_map valToIndex; // {val: index in vals} + vector vals; +}; diff --git a/java/2273. Find Resultant Array After Removing Anagrams b/java/2273. Find Resultant Array After Removing Anagrams new file mode 100644 index 00000000..ed8afacb --- /dev/null +++ b/java/2273. Find Resultant Array After Removing Anagrams @@ -0,0 +1,26 @@ +import java.util.*; + +public class RemoveAnagrams { + public List removeAnagrams(String[] words) { + List result = new ArrayList<>(); + String prev = ""; // To store the sorted version of the previous word + + for (String word : words) { + char[] chars = word.toCharArray(); + Arrays.sort(chars); // Sort the characters to check for anagrams + String sortedWord = new String(chars); + + if (!sortedWord.equals(prev)) { // Add to result if not an anagram of the previous word + result.add(word); + prev = sortedWord; // Update the previous word + } + } + return result; + } + + public static void main(String[] args) { + RemoveAnagrams solution = new RemoveAnagrams(); + String[] words = {"abba", "baba", "bbaa", "cd", "cd"}; + System.out.println(solution.removeAnagrams(words)); // Output: [abba, cd] + } +} diff --git a/java/2D Array/MatrixMultiplication.java b/java/2D Array/MatrixMultiplication.java new file mode 100644 index 00000000..f5b542a8 --- /dev/null +++ b/java/2D Array/MatrixMultiplication.java @@ -0,0 +1,57 @@ +import java.util.*; + +public class MatrixMultiplication { + public static void main(String[] args) { + + Scanner sc = new Scanner(System.in); + System.err.println("First Matrix Dimensions and Elements:"); + int r1 = sc.nextInt(); + int c1 = sc.nextInt(); + + int [][] arr1 = new int[r1][c1]; + + //Input for n*m + for(int i=0;imax){ + return false; + } + } + return true; + } + +} diff --git a/java/2D Array/SpiralMatrix.java b/java/2D Array/SpiralMatrix.java new file mode 100644 index 00000000..23a66ac9 --- /dev/null +++ b/java/2D Array/SpiralMatrix.java @@ -0,0 +1,122 @@ +/* + * 🌀 SpiralMatrix.java + * + * [Algorithm]: Spiral Order Traversal of a Matrix + * [Description]: Prints the elements of a 2D matrix in spiral (clockwise) order. + * [Author]: Akriti Saroj (Hacktoberfest 2025) + * [License]: MIT License + * + * 👩‍💻 How to Run: + * 1️⃣ Compile: javac SpiralMatrix.java + * 2️⃣ Run: java SpiralMatrix + */ + +import java.util.*; + +public class SpiralMatrix { + + /** + * Prints the matrix elements in spiral order. + * + * @param matrix the 2D array to be printed in spiral order + */ + public static void printSpiral(int[][] matrix) { + if (matrix == null || matrix.length == 0) { + System.out.println("Matrix is empty!"); + return; + } + + int startRow = 0, startCol = 0; + int endRow = matrix.length - 1; + int endCol = matrix[0].length - 1; + + System.out.println("\n🔹 Spiral Order Traversal:"); + + while (startRow <= endRow && startCol <= endCol) { + + // → top row + for (int j = startCol; j <= endCol; j++) { + System.out.print(matrix[startRow][j] + " "); + } + + // ↓ right column + for (int i = startRow + 1; i <= endRow; i++) { + System.out.print(matrix[i][endCol] + " "); + } + + // ← bottom row + if (startRow < endRow) { + for (int j = endCol - 1; j >= startCol; j--) { + System.out.print(matrix[endRow][j] + " "); + } + } + + // ↑ left column + if (startCol < endCol) { + for (int i = endRow - 1; i > startRow; i--) { + System.out.print(matrix[i][startCol] + " "); + } + } + + startRow++; + endRow--; + startCol++; + endCol--; + } + System.out.println(); + } + + /** + * Returns the matrix elements in spiral order as a list (for algorithmic use). + * + * @param matrix the 2D array + * @return list of integers in spiral order + */ + public static List getSpiralList(int[][] matrix) { + List result = new ArrayList<>(); + + if (matrix == null || matrix.length == 0) return result; + + int startRow = 0, startCol = 0; + int endRow = matrix.length - 1; + int endCol = matrix[0].length - 1; + + while (startRow <= endRow && startCol <= endCol) { + for (int j = startCol; j <= endCol; j++) result.add(matrix[startRow][j]); + for (int i = startRow + 1; i <= endRow; i++) result.add(matrix[i][endCol]); + if (startRow < endRow) + for (int j = endCol - 1; j >= startCol; j--) result.add(matrix[endRow][j]); + if (startCol < endCol) + for (int i = endRow - 1; i > startRow; i--) result.add(matrix[i][startCol]); + + startRow++; + endRow--; + startCol++; + endCol--; + } + + return result; + } + + public static void main(String[] args) { + int[][] matrix = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13,14, 15,16} + }; + + // Print formatted matrix + System.out.println("📋 Original Matrix:"); + for (int[] row : matrix) { + System.out.println(Arrays.toString(row)); + } + + // Print spiral traversal + printSpiral(matrix); + + // Get spiral as a list (for testing or algorithmic reuse) + List spiral = getSpiralList(matrix); + System.out.println("\n📜 Spiral List: " + spiral); + } +} diff --git a/java/2D Array/TwoDArraySearch.java b/java/2D Array/TwoDArraySearch.java new file mode 100644 index 00000000..b535f0de --- /dev/null +++ b/java/2D Array/TwoDArraySearch.java @@ -0,0 +1,84 @@ +/* + * 🔍 TwoDArraySearch.java + * + * [Algorithm]: Linear Search in a 2D Matrix + * [Description]: Reads a matrix from user input and searches for a given key. + * [Author]: Akriti Saroj (Hacktoberfest 2025) + * [License]: MIT License + * + * 👩‍💻 How to Run: + * 1️⃣ Compile: javac TwoDArraySearch.java + * 2️⃣ Run: java TwoDArraySearch + */ + +import java.util.*; + +public class TwoDArraySearch { + + /** + * Searches for a key in the given 2D matrix. + * + * @param matrix the 2D integer array + * @param key the value to search for + * @return true if found, false otherwise + */ + public static boolean search(int[][] matrix, int key) { + if (matrix == null || matrix.length == 0) { + System.out.println("⚠️ Matrix is empty!"); + return false; + } + + for (int i = 0; i < matrix.length; i++) { + for (int j = 0; j < matrix[0].length; j++) { + if (matrix[i][j] == key) { + System.out.println("\n✅ Found " + key + " at cell: (" + i + ", " + j + ")"); + return true; + } + } + } + System.out.println("\n❌ " + key + " not found in matrix."); + return false; + } + + /** + * Reads and prints a matrix, then searches for a user-specified key. + */ + public static void main(String[] args) { + Scanner scn = new Scanner(System.in); + + System.out.println("🔹 2D Array Search Program (Hacktoberfest 2025)\n"); + + // Input matrix size + System.out.print("Enter number of rows: "); + int n = scn.nextInt(); + + System.out.print("Enter number of columns: "); + int m = scn.nextInt(); + + int[][] matrix = new int[n][m]; + + // Input matrix elements + System.out.println("\n📥 Enter elements row by row:"); + for (int i = 0; i < n; i++) { + System.out.print("Row " + (i + 1) + ": "); + for (int j = 0; j < m; j++) { + matrix[i][j] = scn.nextInt(); + } + } + + // Print the matrix + System.out.println("\n📋 Matrix is:"); + for (int[] row : matrix) { + System.out.println(Arrays.toString(row)); + } + + // Input key to search + System.out.print("\n🔍 Enter key to search: "); + int key = scn.nextInt(); + + // Perform search + search(matrix, key); + + scn.close(); + } +} diff --git a/java/2D-Array/RatInMaze.java b/java/2D-Array/RatInMaze.java new file mode 100644 index 00000000..6e7772ab --- /dev/null +++ b/java/2D-Array/RatInMaze.java @@ -0,0 +1,76 @@ +public class RatInMaze { + /** + * Utility function to check whether (x, y) is a valid move in the maze. + */ + static boolean isSafe(int maze[][], int x, int y) { + int rows = maze.length; + int cols = maze[0].length; + return (x >= 0 && x < rows && y >= 0 && y < cols && maze[x][y] == 1); + } + /** + * Solves the maze for variable-size input. + */ + static boolean solveMaze(int maze[][]) { + int rows = maze.length; + int cols = maze[0].length; + int sol[][] = new int[rows][cols]; + + if (!solveMazeUtil(maze, 0, 0, sol)) { + System.out.println("No solution exists"); + return false; + } + + printSolution(sol); + return true; + } + /** + * A recursive utility to solve the maze problem. + */ + static boolean solveMazeUtil(int maze[][], int x, int y, int sol[][]) { + int rows = maze.length; + int cols = maze[0].length; + // Base case: destination is reached + if (x == rows - 1 && y == cols - 1 && maze[x][y] == 1) { + sol[x][y] = 1; + return true; + } + // Check if maze[x][y] is valid + if (isSafe(maze, x, y)) { + sol[x][y] = 1; // mark x, y as part of the solution path + // Try all possible moves: down, right, up, left + if (solveMazeUtil(maze, x + 1, y, sol)) return true; + if (solveMazeUtil(maze, x, y + 1, sol)) return true; + if (solveMazeUtil(maze, x - 1, y, sol)) return true; + if (solveMazeUtil(maze, x, y - 1, sol)) return true; + // None moves are valid, BACKTRACK + sol[x][y] = 0; + return false; + } + return false; + } + /** + * Utility function to print the solution matrix. + */ + static void printSolution(int sol[][]) { + System.out.println("Solution Path (1s):"); + for (int i = 0; i < sol.length; i++) { + for (int j = 0; j < sol[0].length; j++) { + System.out.print(sol[i][j] + " "); + } + System.out.println(); + } + } + /** + * Usage Example: Try with any maze size! + */ + public static void main(String args[]) { + // Example: a 4x6 maze + int maze[][] = { + {1, 0, 0, 0, 0, 0}, + {1, 1, 0, 1, 1, 1}, + {0, 1, 1, 1, 0, 0}, + {1, 0, 0, 1, 1, 1} + }; + solveMaze(maze); + } +} diff --git a/java/2D-Array/SpiralMatrix.java b/java/2D-Array/SpiralMatrix.java new file mode 100644 index 00000000..fc0ba69b --- /dev/null +++ b/java/2D-Array/SpiralMatrix.java @@ -0,0 +1,53 @@ +public class SpiralMatrix { + + public static void printSpiral(int matrix[][]) { + int startRow = 0; + int startCol = 0; + int endRow = matrix.length - 1; + int endCol = matrix[0].length - 1; + + while(startRow <= endRow && startCol <= endCol) { + + // top + for(int j = startCol; j <= endCol; j++) { + System.out.print(matrix[startRow][j] + " "); + } + + // right + for(int i = startRow + 1; i <= endRow; i++) { + System.out.print(matrix[i][endCol] + " "); + } + + // bottom + for(int j = endCol - 1; j >= startCol; j--) { + if(startRow == endRow) { + break; + } + System.out.print(matrix[endRow][j] + " "); + } + + // left + for(int i = endRow - 1; i >= startRow + 1; i--) { + if(startCol == endCol) { + break; + } + System.out.print(matrix[i][startCol] + " "); + } + + startCol++; + startRow++; + endCol--; + endRow--; + } + System.out.println(); + } + public static void main(String[] args) { + int matrix[][] = {{1, 2, 3, 4}, + {5, 6, 7, 8}, + {9, 10, 11, 12}, + {13, 14, 15, 16}}; + + printSpiral(matrix); + + } +} diff --git a/java/2D-Array/TwoDArraySearch.class b/java/2D-Array/TwoDArraySearch.class new file mode 100644 index 00000000..adb9ec07 Binary files /dev/null and b/java/2D-Array/TwoDArraySearch.class differ diff --git a/java/2D-Array/TwoDArraySearch.java b/java/2D-Array/TwoDArraySearch.java new file mode 100644 index 00000000..bcf97232 --- /dev/null +++ b/java/2D-Array/TwoDArraySearch.java @@ -0,0 +1,46 @@ +import java.util.*; + +public class TwoDArraySearch { + + public static boolean search(int matrix[][], int key) { + for(int i=0; iTrapping Rain Water II Difficulty: Hard

    Given an m x n integer matrix heightMap representing the height of each unit cell in a 2D elevation map, return the volume of water it can trap after raining.

    + +

     

    +

    Example 1:

    + +
    +Input: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
    +Output: 4
    +Explanation: After the rain, water is trapped between the blocks.
    +We have two small ponds 1 and 3 units trapped.
    +The total volume of water trapped is 4.
    +
    + +

    Example 2:

    + +
    +Input: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]]
    +Output: 10
    +
    + +

     

    +

    Constraints:

    + +
      +
    • m == heightMap.length
    • +
    • n == heightMap[i].length
    • +
    • 1 <= m, n <= 200
    • +
    • 0 <= heightMap[i][j] <= 2 * 104
    • +
    diff --git a/java/407-traping-rain-water-ii/traping-rain-water-ii.java b/java/407-traping-rain-water-ii/traping-rain-water-ii.java new file mode 100644 index 00000000..e9d0f58f --- /dev/null +++ b/java/407-traping-rain-water-ii/traping-rain-water-ii.java @@ -0,0 +1,66 @@ +class Solution { + int ans = 0; + PriorityQueue heap; + public int trapRainWater(int[][] heightMap) { + + this.heap = new PriorityQueue<>( + (a,b) -> a.height - b.height + ); + + int n = heightMap[0].length; + int m = heightMap.length; + + for(int i = 0; i < m; i++){ + for(int j = 0; j < n; j++){ + if(i == 0 || i == m-1 || j == 0 || j == n-1){ + heap.add(new Building(i,j,heightMap[i][j])); + heightMap[i][j] = -1; + } + } + } + + while(!heap.isEmpty()){ + Building b = heap.poll(); + int i = b.x; + int j = b.y; + int maxHeight = b.height; + dfs(heightMap, i, j + 1, maxHeight); + dfs(heightMap, i, j - 1, maxHeight); + dfs(heightMap, i + 1, j, maxHeight); + dfs(heightMap, i - 1, j, maxHeight); + } + + return ans; + } + + public void dfs(int[][] grid, int i, int j, int maxHeight){ + if(i <= 0 || j <= 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == -1) + return; + + if(grid[i][j] >= maxHeight){ + heap.add(new Building(i, j, grid[i][j])); + grid[i][j] = -1; + } else { + ans += (maxHeight - grid[i][j]); + grid[i][j] = -1; + dfs(grid, i, j + 1, maxHeight); + dfs(grid, i, j - 1, maxHeight); + dfs(grid, i + 1, j, maxHeight); + dfs(grid, i - 1, j, maxHeight); + } + } +} + +class Building{ + int x; + int y; + int height; + + public Building(int x, int y, int height){ + this.x = x; + this.y = y; + this.height = height; + } + + +} diff --git a/java/42-trapping-rain-water/README.md b/java/42-trapping-rain-water/README.md new file mode 100644 index 00000000..fb9f3ae5 --- /dev/null +++ b/java/42-trapping-rain-water/README.md @@ -0,0 +1,26 @@ +

    Trapping Rain Water

    Difficulty: Hard

    Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

    + +

     

    +

    Example 1:

    + +
    +Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
    +Output: 6
    +Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.
    +
    + +

    Example 2:

    + +
    +Input: height = [4,2,0,3,2,5]
    +Output: 9
    +
    + +

     

    +

    Constraints:

    + +
      +
    • n == height.length
    • +
    • 1 <= n <= 2 * 104
    • +
    • 0 <= height[i] <= 105
    • +
    diff --git a/java/42-trapping-rain-water/trapping-rain-water.java b/java/42-trapping-rain-water/trapping-rain-water.java new file mode 100644 index 00000000..60e891a7 --- /dev/null +++ b/java/42-trapping-rain-water/trapping-rain-water.java @@ -0,0 +1,175 @@ +/************************************************ */ +/* Solution 1 Using two pointer */ +/************************************************ */ + +class Solution { + public int trap(int[] height) { + int l = 0, r = height.length - 1; + int lmax = height[l], rmax = height[r]; + int water = 0; + + while(l < r){ + if(lmax <= rmax){ + ++l; + if(height[l] >= lmax) + lmax = height[l]; + else + water += lmax - height[l]; + + } else { + --r; + if(height[r] >= rmax) + rmax = height[r]; + + else + water += rmax - height[r]; + } + } + return water; + } +} + +/* ===================================================================================================================== + TIME COMPLEXITY ANALYSIS FOR THE ABOVE CODE: + + The time complexity of the above code is O(n) where n = height.length. + + Explanation : The condition "while(l < r)" loop runs once for each element in the array. So, each element is processed atmost once +======================================================================================================================= + + SPACE COMPLEXITY ANALYSIS FOR THE ABOVE CODE : + +The space complexity of the above code is O(1) and I say that because the extra space is being used only by the variables (l, r, lmax, rmax, water) and no additional Data Structures and being used. +======================================================================================================================== +*/ + + +/************************************************ */ +/* Solution 2 Using arrays */ +/************************************************ */ + +// class Solution { +// public int trap(int[] height) { +// int[] leftMax = new int[height.length]; +// int[] rightMax = new int[height.length]; +// int water = 0; + +// leftMax[0] = height[0]; +// rightMax[height.length - 1] = height[height.length - 1]; + +// for(int i = 1; i < height.length; i++) +// leftMax[i] = Math.max(leftMax[i-1],height[i]); + +// for(int i = (height.length - 2); i >= 0; i--) +// rightMax[i] = Math.max(rightMax[i+1],height[i]); + +// for(int i = 0; i < height.length; i++) +// water += Math.min(rightMax[i],leftMax[i]) - height[i]; + +// return water; +// } +// } + +/* ===================================================================================================================== + TIME COMPLEXITY ANALYSIS FOR THE ABOVE CODE: + +Explanation : As this code consists of traverising the array multiple times, let's go step by step: +First loop : It is calculating the values for left max array and the loop runs n-1 times (Time complexity : O(n)). +Second loop : It is calulating the values for the right max array and the lop runs n-1 times (Time complexity : O(n)). +Third loop : It is calculating the overall final value (final trapped water) and it runs n times (Time complexity : O(n)). + +where is n = height.length. + +Overall Time complexity : O(n) + O(n) + O(n) = O(n). + +======================================================================================================================= + + SPACE COMPLEXITY ANALYSIS FOR THE ABOVE CODE : +Explanation : The array leftmax and rightmax are of size n. So, O(n) + O(n) = O(2n). +Also, there are few more variables being used like : water, i etc. + +Total Space Complexity : O(2n) => simplifies to O(n). + + +======================================================================================================================== +*/ + + +/************************************************ */ +/* Solution 2 Using stacks */ +/************************************************ */ + + +// class Solution { +// public int trap(int[] height) { + +// int water = 0, baseHeight = height[0]; +// Stack st = new Stack<>(); +// Stack st2 = new Stack<>(); + +// st.push(height[0]); + +// for(int i = 1; i < height.length; i++) { + +// if(baseHeight <= height[i]) { +// while(!st.empty()){ +// water += baseHeight - st.pop(); +// } +// baseHeight = height[i]; +// st.push(height[i]); +// } else { +// st.push(height[i]); +// } +// } + +// baseHeight = st.pop(); +// while(!st.empty()) { +// if(baseHeight <= st.peek()) { +// while(!st2.empty()){ +// water += baseHeight - st2.pop(); +// } +// baseHeight = st.pop(); +// st2.push(baseHeight); +// } else { +// st2.push(st.pop()); +// } +// } + +// return water; +// } +// } + + +/* ===================================================================================================================== + TIME COMPLEXITY ANALYSIS FOR THE ABOVE CODE: + +Explanation : As the code looks little bulky, let's analyze the time complexity of the above code step by step : +First while loop : +-> It runs once for each element i in height array. +-> The inner loop "while(!st.isEmpty())" pops elements from the stack. + +Second while loop : +-> It processes the remaining elements in "st" and moves them into "st2". +-> Again, each element is pushed and popped at most once across both stacks. + + +Thus, even though there are nested loops, each element is processed a constant number of times. + +Time Complexity : O(n) + +======================================================================================================================= + + SPACE COMPLEXITY ANALYSIS FOR THE ABOVE CODE : +Explanation : + Stack st = new Stack<>(); + Stack st2 = new Stack<>(); + +The above 2 lines in the code, the stack uses upto n elements. +The second stack uses upto n elements. +-> Here too, few constant variables are being used (like baseHeight, water etc). + +Overall Space Complexity : O(n). + + +======================================================================================================================== +*/ diff --git a/java/778-swim-in-rising-water/README.md b/java/778-swim-in-rising-water/README.md new file mode 100644 index 00000000..acd0afe3 --- /dev/null +++ b/java/778-swim-in-rising-water/README.md @@ -0,0 +1,40 @@ +

    Swim in Rising Water

    Difficulty: Hard

    You are given an n x n integer matrix grid where each value grid[i][j] represents the elevation at that point (i, j).

    + +

    It starts raining, and water gradually rises over time. At time t, the water level is t, meaning any cell with elevation less than equal to t is submerged or reachable.

    + +

    You can swim from a square to another 4-directionally adjacent square if and only if the elevation of both squares individually are at most t. You can swim infinite distances in zero time. Of course, you must stay within the boundaries of the grid during your swim.

    + +

    Return the minimum time until you can reach the bottom right square (n - 1, n - 1) if you start at the top left square (0, 0).

    + +

     

    +

    Example 1:

    + +
    +Input: grid = [[0,2],[1,3]]
    +Output: 3
    +Explanation:
    +At time 0, you are in grid location (0, 0).
    +You cannot go anywhere else because 4-directionally adjacent neighbors have a higher elevation than t = 0.
    +You cannot reach point (1, 1) until time 3.
    +When the depth of water is 3, we can swim anywhere inside the grid.
    +
    + +

    Example 2:

    + +
    +Input: grid = [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
    +Output: 16
    +Explanation: The final route is shown.
    +We need to wait until time 16 so that (0, 0) and (4, 4) are connected.
    +
    + +

     

    +

    Constraints:

    + +
      +
    • n == grid.length
    • +
    • n == grid[i].length
    • +
    • 1 <= n <= 50
    • +
    • 0 <= grid[i][j] < n2
    • +
    • Each value grid[i][j] is unique.
    • +
    diff --git a/java/778-swim-in-rising-water/swim-in-rising-water.java b/java/778-swim-in-rising-water/swim-in-rising-water.java new file mode 100644 index 00000000..854aaf95 --- /dev/null +++ b/java/778-swim-in-rising-water/swim-in-rising-water.java @@ -0,0 +1,36 @@ +class Solution { + boolean[][] visited; + public int swimInWater(int[][] grid) { + int n = grid.length; + int l = 0; int r = n * n - 1; + int min = n * n - 1; + + while(l <= r) { + int mid = l + ((r - l)/2); + visited = new boolean[n][n]; + if(dfs(grid, mid, 0, 0, n)){ + r = mid - 1; + min = mid; + } + else + l = mid + 1; + } + return min; + } + private boolean dfs(int[][] grid, int max_value, int i, int j, int n){ + if(i < 0 || j < 0 || j == n || i == n || visited[i][j] || grid[i][j] > max_value) //break + return false; + if(i == n-1 && j == n-1) + return true; + + visited[i][j] = true; // mark visited + + boolean right = dfs(grid, max_value, i, j+1, n); + boolean left = dfs(grid, max_value, i, j-1, n); + boolean bottom = dfs(grid, max_value, i+1, j, n); + boolean top = dfs(grid, max_value, i-1, j, n); + + return (right || left || bottom || top) ? true : false; + } + +} diff --git a/java/AVLTree.java b/java/AVLTree.java new file mode 100644 index 00000000..a32b1964 --- /dev/null +++ b/java/AVLTree.java @@ -0,0 +1,169 @@ +/** + * AVL Tree Implementation + * A self-balancing Binary Search Tree (BST) where the difference of heights + * of left and right subtrees cannot be more than one for all nodes. + */ +public class AVLTree { + class Node { + int key, height; + Node left, right; + + Node(int d) { + key = d; + height = 1; + } + } + + Node root; + + // Get height of the tree + int height(Node N) { + if (N == null) + return 0; + return N.height; + } + + // Get balance factor of node N + int getBalance(Node N) { + if (N == null) + return 0; + return height(N.left) - height(N.right); + } + + // Right rotate subtree rooted with y + Node rightRotate(Node y) { + Node x = y.left; + Node T2 = x.right; + + x.right = y; + y.left = T2; + + y.height = Math.max(height(y.left), height(y.right)) + 1; + x.height = Math.max(height(x.left), height(x.right)) + 1; + + return x; + } + + // Left rotate subtree rooted with x + Node leftRotate(Node x) { + Node y = x.right; + Node T2 = y.left; + + y.left = x; + x.right = T2; + + x.height = Math.max(height(x.left), height(x.right)) + 1; + y.height = Math.max(height(y.left), height(y.right)) + 1; + + return y; + } + + Node insert(Node node, int key) { + if (node == null) + return (new Node(key)); + + if (key < node.key) + node.left = insert(node.left, key); + else if (key > node.key) + node.right = insert(node.right, key); + else + return node; + + node.height = 1 + Math.max(height(node.left), height(node.right)); + + int balance = getBalance(node); + + // Left Left Case + if (balance > 1 && key < node.left.key) + return rightRotate(node); + + // Right Right Case + if (balance < -1 && key > node.right.key) + return leftRotate(node); + + // Left Right Case + if (balance > 1 && key > node.left.key) { + node.left = leftRotate(node.left); + return rightRotate(node); + } + + // Right Left Case + if (balance < -1 && key < node.right.key) { + node.right = rightRotate(node.right); + return leftRotate(node); + } + + return node; + } + + public void insert(int key) { + root = insert(root, key); + } + + // Inorder traversal of the tree + public void inorder() { + System.out.println("\nInorder traversal:"); + inorderRec(root); + } + + private void inorderRec(Node root) { + if (root != null) { + inorderRec(root.left); + System.out.print(root.key + " "); + inorderRec(root.right); + } + } + + // Method to print level order traversal + public void printLevelOrder() { + System.out.println("\nLevel order traversal:"); + int h = height(root); + for (int i = 1; i <= h; i++) { + printGivenLevel(root, i); + System.out.println(); + } + } + + private void printGivenLevel(Node root, int level) { + if (root == null) + return; + if (level == 1) + System.out.print(root.key + " "); + else if (level > 1) { + printGivenLevel(root.left, level - 1); + printGivenLevel(root.right, level - 1); + } + } + + // Main method to test the AVL Tree implementation + public static void main(String[] args) { + AVLTree tree = new AVLTree(); + + /* Constructing tree given in the above figure */ + tree.insert(10); + tree.insert(20); + tree.insert(30); + tree.insert(40); + tree.insert(50); + tree.insert(25); + + System.out.println("AVL Tree created successfully!"); + + // Print different traversals + tree.inorder(); + tree.printLevelOrder(); + + // Demonstrate tree balance + System.out.println("\nTree root: " + tree.root.key); + System.out.println("Root balance factor: " + tree.getBalance(tree.root)); + + // Additional insertions to show self-balancing + System.out.println("\nInserting more elements..."); + tree.insert(5); + tree.insert(15); + + // Print updated tree + tree.inorder(); + tree.printLevelOrder(); + } +} \ No newline at end of file diff --git a/java/Account.class b/java/Account.class new file mode 100644 index 00000000..07877f92 Binary files /dev/null and b/java/Account.class differ diff --git a/java/AllLeadersInTheArray.java b/java/AllLeadersInTheArray.java new file mode 100644 index 00000000..1825cd90 --- /dev/null +++ b/java/AllLeadersInTheArray.java @@ -0,0 +1,43 @@ +import java.util.*; + +class Solution { + public List leaders(int[] arr) { + int n = arr.length; + List leaders = new ArrayList<>(); + + // Start with the rightmost element (always a leader) + int maxFromRight = arr[n - 1]; + leaders.add(maxFromRight); + + // Traverse from right to left + for (int i = n - 2; i >= 0; i--) { + if (arr[i] > maxFromRight) { + leaders.add(arr[i]); + maxFromRight = arr[i]; + } + } + + // Reverse since we collected leaders in reverse order + Collections.reverse(leaders); + return leaders; + } +} + +public class AllLeadersInTheArray { + public static void main(String[] args) { + Solution solution = new Solution(); + Scanner sc = new Scanner(System.in); + + System.out.print("Enter number of elements: "); + int n = sc.nextInt(); + int[] arr = new int[n]; + + System.out.println("Enter the array elements:"); + for (int i = 0; i < n; i++) { + arr[i] = sc.nextInt(); + } + + List leaders = solution.leaders(arr); + System.out.println("Leaders in the array: " + leaders); + } +} diff --git a/java/AllPathToSource.java b/java/AllPathToSource.java new file mode 100644 index 00000000..7be10eab --- /dev/null +++ b/java/AllPathToSource.java @@ -0,0 +1,27 @@ +import java.util.ArrayList; +import java.util.List; + +public class AllPathToSource { + public static List> allPathsSourceTarget(int[][] graph) { + List> paths = new ArrayList<>(); + List path = new ArrayList<>(); + path.add(0); + helper(graph,0,path,paths); + return paths; + } + public static void helper(int[][] graph,int node,List path,List> paths){ + if(node == graph.length-1){ + paths.add(new ArrayList<>(path)); + return; + } + for(int i=0;i charCount = new HashMap<>(); + + for (char c : word1.toCharArray()) { + charCount.put(c, charCount.getOrDefault(c, 0) + 1); + } + + for (char c : word2.toCharArray()) { + if (!charCount.containsKey(c)) { + return false; + } + + int count = charCount.get(c) - 1; + if (count == 0) { + charCount.remove(c); + } else { + charCount.put(c, count); + } + } + + return charCount.isEmpty(); + } + + /** + * Alternative approach using sorting (simpler but slightly less efficient) + * + * Time Complexity: O(n log n) + * Space Complexity: O(n) for character arrays + * + * @param word1 First string + * @param word2 Second string + * @return true if anagrams + */ + public static boolean isAnagramSorting(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + word1 = word1.replaceAll("[^a-zA-Z]", "").toLowerCase(); + word2 = word2.replaceAll("[^a-zA-Z]", "").toLowerCase(); + + if (word1.length() != word2.length()) { + return false; + } + + char[] arr1 = word1.toCharArray(); + char[] arr2 = word2.toCharArray(); + + Arrays.sort(arr1); + Arrays.sort(arr2); + + return Arrays.equals(arr1, arr2); + } + + /** + * Optimized approach using character frequency array (for lowercase letters + * only) + * Most efficient for simple anagram checking + * + * Time Complexity: O(n) + * Space Complexity: O(1) - fixed 26 character array + * + * @param word1 First string + * @param word2 Second string + * @return true if anagrams + */ + public static boolean isAnagramOptimized(String word1, String word2) { + if (word1 == null || word2 == null) { + return false; + } + + word1 = word1.replaceAll("[^a-zA-Z]", "").toLowerCase(); + word2 = word2.replaceAll("[^a-zA-Z]", "").toLowerCase(); + + if (word1.length() != word2.length()) { + return false; + } + + int[] charFreq = new int[26]; // For 'a' to 'z' + + for (int i = 0; i < word1.length(); i++) { + charFreq[word1.charAt(i) - 'a']++; + charFreq[word2.charAt(i) - 'a']--; + } + + for (int count : charFreq) { + if (count != 0) { + return false; + } + } + + return true; + } + + /** + * Prints test result in formatted manner + */ + private static void testAnagram(String word1, String word2) { + boolean result1 = isAnagram(word1, word2); + boolean result2 = isAnagramSorting(word1, word2); + boolean result3 = isAnagramOptimized(word1, word2); + + System.out.printf("%-20s | %-20s | HashMap: %-5s | Sorting: %-5s | Optimized: %-5s%n", + "\"" + word1 + "\"", "\"" + word2 + "\"", + result1, result2, result3); + } + + public static void main(String[] args) { + System.out.println("=== Anagram Checker Test Cases ===\n"); + System.out.printf("%-20s | %-20s | %-14s | %-14s | %-14s%n", + "Word 1", "Word 2", "HashMap", "Sorting", "Optimized"); + System.out.println("-".repeat(95)); + + // Basic anagrams + testAnagram("evil", "vile"); + testAnagram("angel", "glean"); + testAnagram("listen", "silent"); + + // With spaces and punctuation + testAnagram("school master", "the classroom"); + testAnagram("conversation", "voices rant on"); + + // Not anagrams + testAnagram("listen", "hearing"); + testAnagram("hello", "world"); + + // Edge cases + testAnagram("", ""); + testAnagram("a", "a"); + testAnagram("abc", "def"); + + System.out.println("\n=== Performance Comparison ===\n"); + + String str1 = "astronomer"; + String str2 = "moon starer"; + + // Benchmark HashMap approach + long start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagram(str1, str2); + } + long hashMapTime = System.nanoTime() - start; + + // Benchmark Sorting approach + start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagramSorting(str1, str2); + } + long sortingTime = System.nanoTime() - start; + + // Benchmark Optimized approach + start = System.nanoTime(); + for (int i = 0; i < 100000; i++) { + isAnagramOptimized(str1, str2); + } + long optimizedTime = System.nanoTime() - start; + + System.out.printf("HashMap approach: %d ms%n", hashMapTime / 1_000_000); + System.out.printf("Sorting approach: %d ms%n", sortingTime / 1_000_000); + System.out.printf("Optimized approach: %d ms%n", optimizedTime / 1_000_000); + + System.out.println("\nRecommendation:"); + System.out.println("- Use Optimized (array) for simple lowercase anagrams"); + System.out.println("- Use HashMap for Unicode/multilingual support"); + System.out.println("- Use Sorting for simplicity and readability"); + } +} \ No newline at end of file diff --git a/java/Anagrams.java b/java/Anagrams.java new file mode 100644 index 00000000..4fc09a37 --- /dev/null +++ b/java/Anagrams.java @@ -0,0 +1,37 @@ +import java.util.Arrays; +import java.util.Scanner; + +public class Anagrams { // Question 4 + public static void main(String[] args) { + Scanner scn = new Scanner(System.in); + + System.out.print("Enter first string: "); + String str1 = scn.nextLine(); + + System.out.print("Enter second string: "); + String str2 = scn.nextLine(); + + str1 = str1.toLowerCase(); + str2 = str2.toLowerCase(); + + // If lengths are not equal, they cannot be anagrams + if (str1.length() != str2.length()) { + System.out.println("Not Anagrams"); + } else { + + char[] arr1 = str1.toCharArray(); + char[] arr2 = str2.toCharArray(); + + Arrays.sort(arr1); + Arrays.sort(arr2); + + if (Arrays.equals(arr1, arr2)) { + System.out.println("Anagrams"); + } else { + System.out.println("Not Anagrams"); + } + } + + scn.close(); + } +} diff --git a/java/AreaCalculator.class b/java/AreaCalculator.class new file mode 100644 index 00000000..150201d4 Binary files /dev/null and b/java/AreaCalculator.class differ diff --git a/java/AreaCalculator.java b/java/AreaCalculator.java new file mode 100644 index 00000000..48cf5226 --- /dev/null +++ b/java/AreaCalculator.java @@ -0,0 +1,55 @@ +import java.util.Scanner; + +public class AreaCalculator { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int choice; + + do { + System.out.println("\n--- Area Calculator ---"); + System.out.println("1. Circle"); + System.out.println("2. Rectangle"); + System.out.println("3. Triangle"); + System.out.println("4. Exit"); + System.out.print("Enter your choice: "); + choice = sc.nextInt(); + + switch (choice) { + case 1: + System.out.print("Enter radius of circle: "); + double radius = sc.nextDouble(); + double circleArea = 3.14159 * radius * radius; + System.out.println("Area of Circle = " + circleArea); + break; + + case 2: + System.out.print("Enter length of rectangle: "); + double length = sc.nextDouble(); + System.out.print("Enter width of rectangle: "); + double width = sc.nextDouble(); + double rectArea = length * width; + System.out.println("Area of Rectangle = " + rectArea); + break; + + case 3: + System.out.print("Enter base of triangle: "); + double base = sc.nextDouble(); + System.out.print("Enter height of triangle: "); + double height = sc.nextDouble(); + double triArea = 0.5 * base * height; + System.out.println("Area of Triangle = " + triArea); + break; + + case 4: + System.out.println("Exiting program. Goodbye!"); + break; + + default: + System.out.println("Invalid choice! Please try again."); + } + + } while (choice != 4); + + sc.close(); + } +} diff --git a/java/ArmstrongNumberCheck.class b/java/ArmstrongNumberCheck.class new file mode 100644 index 00000000..e378207d Binary files /dev/null and b/java/ArmstrongNumberCheck.class differ diff --git a/java/ArmstrongNumberCheck.java b/java/ArmstrongNumberCheck.java new file mode 100644 index 00000000..dc98e717 --- /dev/null +++ b/java/ArmstrongNumberCheck.java @@ -0,0 +1,23 @@ +import java.util.Scanner; + +public class ArmstrongNumberCheck { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter a number: "); + int num = sc.nextInt(); + int original = num; + int digits = String.valueOf(num).length(); + int sum = 0; + + while (num > 0) { + int digit = num % 10; + sum += Math.pow(digit, digits); + num /= 10; + } + + if (sum == original) + System.out.println(original + " is an Armstrong Number"); + else + System.out.println(original + " is not an Armstrong Number"); + } +} diff --git a/java/ArrayListDemo.java b/java/ArrayListDemo.java new file mode 100644 index 00000000..e740d7ad --- /dev/null +++ b/java/ArrayListDemo.java @@ -0,0 +1,32 @@ +import java.util.ArrayList; + +public class ArrayListDemo { + + public static void main(String[] args) { + + ArrayList arrayList = new ArrayList(5); + + //adding elements + for(int i = 1; i <= 5; i++) { + arrayList.add(i); + } + + //printing elements + System.out.println(arrayList); + + //removing element using index + arrayList.remove(3); + + //printing elements + System.out.println(arrayList); + + //printing element one by one + for(int i = 0; i < arrayList.size(); i++) { + System.out.println(arrayList.get(i) + " "); + } + //for each + for(int i : arrayList) { + System.out.println(i); + } + } +} diff --git a/java/ArrayOperations.java b/java/ArrayOperations.java new file mode 100644 index 00000000..242cf51c --- /dev/null +++ b/java/ArrayOperations.java @@ -0,0 +1,76 @@ +import java.util.*; + +public class ArrayOperations { + + // Find maximum element in array + public int findMax(int[] arr) { + int max = arr[0]; + for (int i = 1; i < arr.length; i++) { + if (arr[i] > max) max = arr[i]; + } + return max; + } + + // Reverse array in-place + public void reverseArray(int[] arr) { + int left = 0, right = arr.length - 1; + while (left < right) { + int temp = arr[left]; + arr[left] = arr[right]; + arr[right] = temp; + left++; + right--; + } + } + + // Find missing number in array 1 to n + public int findMissing(int[] arr, int n) { + int sum = n * (n + 1) / 2; + for (int num : arr) { + sum -= num; + } + return sum; + } + + // Remove duplicates from sorted array + public int removeDuplicates(int[] arr) { + if (arr.length == 0) return 0; + int j = 0; + for (int i = 1; i < arr.length; i++) { + if (arr[i] != arr[j]) { + arr[++j] = arr[i]; + } + } + return j + 1; + } + + // Rotate array right by k positions + public void rotateRight(int[] arr, int k) { + k %= arr.length; + reverse(arr, 0, arr.length - 1); + reverse(arr, 0, k - 1); + reverse(arr, k, arr.length - 1); + } + + private void reverse(int[] arr, int start, int end) { + while (start < end) { + int temp = arr[start]; + arr[start] = arr[end]; + arr[end] = temp; + start++; + end--; + } + } + + public static void main(String[] args) { + ArrayOperations ap = new ArrayOperations(); + + int[] arr = {3, 1, 4, 1, 5, 9, 2, 6}; + System.out.println("Max: " + ap.findMax(arr)); + + ap.reverseArray(arr); + System.out.println("Reversed: " + Arrays.toString(arr)); + + System.out.println("Missing: " + ap.findMissing(new int[]{1,2,4,5}, 5)); + } +} \ No newline at end of file diff --git a/java/ArrayPythagorasTriplet.java b/java/ArrayPythagorasTriplet.java new file mode 100644 index 00000000..6e28a357 --- /dev/null +++ b/java/ArrayPythagorasTriplet.java @@ -0,0 +1,31 @@ +public class ArrayPythagorasTriplet { + + public static void main(String[] args) { + int[] arr = {3, 1, 4, 6, 5}; + System.out.println(isPythagorasTripletExists(arr) ? "TRUE" : "FALSE"); + } + + private static boolean isPythagorasTripletExists(int[] arr) { + for (int i = 0; i < arr.length; i++) { + arr[i] = arr[i] * arr[i]; + } + + Arrays.sort(arr); + + for (int i = arr.length - 1; i >= 2; i--) { + int left = 0; + int right = i - 1; + + while (left <= right) { + if (arr[left] + arr[right] == arr[i]) { + return true; + } else if (arr[left] + arr[right] < arr[i]) { + left++; + } else { + right--; + } + } + } + return false; + } +} diff --git a/java/ArrayUtils.java b/java/ArrayUtils.java new file mode 100644 index 00000000..c048176b --- /dev/null +++ b/java/ArrayUtils.java @@ -0,0 +1,55 @@ +import java.util.Arrays; + +public class ArrayUtils { + + public static int findMax(int[] arr) { + if (arr == null || arr.length == 0) + throw new IllegalArgumentException("Array is empty or null"); + int max = arr[0]; + for (int num : arr) if (num > max) max = num; + return max; + } + + public static int findMin(int[] arr) { + if (arr == null || arr.length == 0) + throw new IllegalArgumentException("Array is empty or null"); + int min = arr[0]; + for (int num : arr) if (num < min) min = num; + return min; + } + + public static int sum(int[] arr) { + if (arr == null) return 0; + int total = 0; + for (int num : arr) total += num; + return total; + } + + public static double average(int[] arr) { + if (arr == null || arr.length == 0) + throw new IllegalArgumentException("Array is empty or null"); + return (double) sum(arr) / arr.length; + } + + public static void reverse(int[] arr) { + if (arr == null) return; + int left = 0, right = arr.length - 1; + while (left < right) { + int temp = arr[left]; + arr[left] = arr[right]; + arr[right] = temp; + left++; + right--; + } + } + + public static boolean contains(int[] arr, int target) { + if (arr == null) return false; + for (int num : arr) if (num == target) return true; + return false; + } + + public static String toString(int[] arr) { + return Arrays.toString(arr); + } +} diff --git a/java/ArrayUtilsTest.java b/java/ArrayUtilsTest.java new file mode 100644 index 00000000..c86ea981 --- /dev/null +++ b/java/ArrayUtilsTest.java @@ -0,0 +1,56 @@ +package algorithms.utils; +import static org.junit.jupiter.api.Assertions.*; + + +public class ArrayUtilsTest { + + int[] sample = {1, 3, 5, 7, 9}; + + @Test + void testFindMax() { + assertEquals(9, ArrayUtils.findMax(sample)); + } + + @Test + void testFindMin() { + assertEquals(1, ArrayUtils.findMin(sample)); + } + + @Test + void testSum() { + assertEquals(25, ArrayUtils.sum(sample)); + } + + @Test + void testAverage() { + assertEquals(5.0, ArrayUtils.average(sample)); + } + + @Test + void testReverse() { + int[] arr = {1, 2, 3, 4}; + ArrayUtils.reverse(arr); + assertArrayEquals(new int[]{4, 3, 2, 1}, arr); + } + + @Test + void testContains() { + assertTrue(ArrayUtils.contains(sample, 5)); + assertFalse(ArrayUtils.contains(sample, 10)); + } + + @Test + void testEmptyArray() { + int[] empty = {}; + assertThrows(IllegalArgumentException.class, () -> ArrayUtils.findMax(empty)); + assertThrows(IllegalArgumentException.class, () -> ArrayUtils.findMin(empty)); + assertThrows(IllegalArgumentException.class, () -> ArrayUtils.average(empty)); + } + + @Test + void testNullArray() { + int[] arr = null; + assertEquals(0, ArrayUtils.sum(arr)); + assertFalse(ArrayUtils.contains(arr, 1)); + } +} diff --git a/java/Arrays/Apple_Price.java b/java/Arrays/Apple_Price.java new file mode 100644 index 00000000..defa6854 --- /dev/null +++ b/java/Arrays/Apple_Price.java @@ -0,0 +1,89 @@ +package Arrays; + +import java.util.Arrays; + +public class Apple_Price { + + public static void name() { + int prices[] = {3, 5, 8, 10}; + int demands[] = {1, 6, 10}; + + int m=prices.length; + int n=demands.length; + + + + Arrays.sort(prices); + + boolean used[]=new boolean[m]; + int result[]=new int[n]; + + for (int i = 0; i < n; i++) { + int demand=demands[i]; + + int choosen=-1; + + for (int j = m-1;j>=0; j--) { + + if (!used[j] && prices[j]<=demand) { + + choosen=prices[j]; + used[j]=true; + break; + + } + } + result[i]=choosen; + + } + + + for (int i = 0; i < result.length; i++) { + + System.out.print(result[i]+" "); + } + + + } + + + + + public static void main(String[] args) { + + + int prices[] = {3, 5, 8, 10}; + int demands[] = {1, 6, 10}; + + int m = prices.length; + int n = demands.length; + + + Arrays.sort(prices); + + boolean used[] = new boolean[m]; // Track whether apple at index j is sold + int results[] = new int[n]; // Output results for each customer + + for (int i = 0; i < n; i++) { + int demand = demands[i]; + int chosen = -1; + + // Loop through prices from high to low (right to left) + for (int j = m - 1; j >= 0; j--) { + if (!used[j] && prices[j] <= demand) { + chosen = prices[j]; + used[j] = true; // Mark this apple as sold + break; + } + } + results[i] = chosen; + } + + // Print the result + for (int i = 0; i < n; i++) { + System.out.print(results[i] + " "); + } + } + + +} diff --git a/java/Arrays/LongestSubseqwithXOR.java b/java/Arrays/LongestSubseqwithXOR.java new file mode 100644 index 00000000..530fee2d --- /dev/null +++ b/java/Arrays/LongestSubseqwithXOR.java @@ -0,0 +1,26 @@ +class longestSubsequencewithXOR { +public int longestSubsequence(int[] nums) { + int xor = 0; // Variable to store cumulative XOR of all elements + + // Compute XOR of all numbers in the array + for (int num : nums) { + xor = xor ^ num; + } + + // If the total XOR is non-zero, the entire array itself is a valid subsequence + if (xor != 0) { + return nums.length; + } + + // If total XOR is zero, check if there's at least one non-zero element + // Removing any one non-zero element will make the XOR non-zero + for (int num : nums) { + if (num != 0) { + return nums.length - 1; + } + } + + // If all elements are zero, no non-zero XOR subsequence exists + return 0; + } +} \ No newline at end of file diff --git a/java/Arrays/Longest_Consecutive_Sequence_in_an_Array.java b/java/Arrays/Longest_Consecutive_Sequence_in_an_Array.java new file mode 100644 index 00000000..69996877 --- /dev/null +++ b/java/Arrays/Longest_Consecutive_Sequence_in_an_Array.java @@ -0,0 +1,84 @@ +// contributed by Tushar Kumar +// GitHub - https://github.com/Tusharkumar200 + +package arrays; + +import java.util.HashSet; +import java.util.Set; + +public class Longest_Consecutive_Sequence_in_an_Array { + + // Brute Force + + public static boolean linearSearch(int[] a, int num) { + + for (int i : a) { + + if (i == num) + return true; + } + return false; + } + + public static int longestSuccessiveElements(int[] a) { + + int longest = 1; + + for (int i : a) { + int x = i; + int cnt = 1; + + while (linearSearch(a, x + 1) == true) { + + x += 1; + cnt += 1; + } + + longest = Math.max(cnt, longest); + } + return longest; + } + + // Optimal Approched + + public static int longestSuccessiveElementsOptimal(int[] a) { + + int n = a.length; + if (n == 0) + return 0; + + int longest = 1; + + Set set = new HashSet<>(); + + for (int i : a) { + set.add(i); + } + + for (int it : set) { + + int cnt = 1; + int x = it; + + if (!set.contains(it - 1)) { + + while (set.contains(x + 1)) { + + x = x + 1; + cnt = cnt + 1; + } + + longest = Math.max(longest, cnt); + } + } + return longest; + } + + public static void main(String[] args) { + int[] a = { 100, 200, 1, 2, 3, 4 }; + // int ans = longestSuccessiveElements(a); + int ans = longestSuccessiveElementsOptimal(a); + + System.out.println("The longest consecutive sequence is " + ans); + } +} diff --git a/java/Arrays/MaximumSubarray.java b/java/Arrays/MaximumSubarray.java new file mode 100644 index 00000000..f7a95df3 --- /dev/null +++ b/java/Arrays/MaximumSubarray.java @@ -0,0 +1,14 @@ +class MaximumSubarray { + public int maxSubArray(int[] nums) { + int maxSum = nums[0]; // Best sum so far + int currentSum = nums[0]; // Current subarray sum + + for (int i = 1; i < nums.length; i++) { + // If currentSum becomes negative, start new subarray + currentSum = Math.max(nums[i], currentSum + nums[i]); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; + } +} diff --git a/java/Arrays/Median_of_Two_Sorted_Arrays.java b/java/Arrays/Median_of_Two_Sorted_Arrays.java new file mode 100644 index 00000000..3fcd51b5 --- /dev/null +++ b/java/Arrays/Median_of_Two_Sorted_Arrays.java @@ -0,0 +1,31 @@ +class Solution { + public double findMedianSortedArrays(int[] smaller, int[] larger) { + if(smaller.length > larger.length) return findMedianSortedArrays(larger, smaller); + int sn = smaller.length, ln = larger.length; + int low = 0, high = sn; + + while(low <= high) { + int mid1 = low + (high - low)/2; // x -> the no. of elements I take from A1 + int mid2 = (sn + ln + 1)/2 - mid1; // because I need to take (real mid (median point) - mid1); this gives me no. of elements I can take from A2 + + int l1 = mid1 == 0 ? Integer.MIN_VALUE : smaller[mid1-1]; // if mid1 is 0 that means no elements are taken from A1, so minimum value + int l2 = mid2 == 0 ? Integer.MIN_VALUE : larger[mid2-1]; // if mid2 is 0 that means no elements are taken from A2 + + int r1 = mid1 == sn ? Integer.MAX_VALUE : smaller[mid1]; + int r2 = mid2 == ln ? Integer.MAX_VALUE : larger[mid2]; + + if(l1 <= r2 && l2 <= r1) { + if((sn + ln)%2 == 1) + return Math.max(l1, l2); + else + return (Math.max(l1, l2) + Math.min(r1, r2))/2.0; + } else if(l1 > r2) { + high = mid1-1; + } else { // l2 > r1 + low = mid1+1; + } + } + + return 0.0; + } +} \ No newline at end of file diff --git a/java/Arrays/Min_Product_SubArray.java b/java/Arrays/Min_Product_SubArray.java new file mode 100644 index 00000000..56684c0d --- /dev/null +++ b/java/Arrays/Min_Product_SubArray.java @@ -0,0 +1,33 @@ +package Arrays; + +public class Min_Product_SubArray { + + public static int minSumArray(int arr[]) { + + + int res=arr[0]; + int minValue=arr[0]; + + for (int i = 1; i < arr.length; i++) { + + minValue=Math.min(minValue+arr[i], arr[i]); + + + res=Math.min(minValue, res); + + + + } + + + return res; + } + + public static void main(String[] args) { + + int arr[]= {2, 3, 5, -2, -7, 4,-8}; + + System.out.println(minSumArray(arr)); + + } +} diff --git a/java/Arrays/MoveZeroes.java b/java/Arrays/MoveZeroes.java new file mode 100644 index 00000000..abeef26b --- /dev/null +++ b/java/Arrays/MoveZeroes.java @@ -0,0 +1,17 @@ +class MoveZeroes { + public void moveZeroes(int[] nums) { + int index = 0; // Tracks where to place the next non-zero element + + // First, move all non-zero elements to the front + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + nums[index++] = nums[i]; + } + } + + // Fill the rest of the array with zeroes + while (index < nums.length) { + nums[index++] = 0; + } + } +} diff --git a/java/Arrays/RearrangeArray.java b/java/Arrays/RearrangeArray.java new file mode 100644 index 00000000..ee95b452 --- /dev/null +++ b/java/Arrays/RearrangeArray.java @@ -0,0 +1,22 @@ +class RearrangeArray { + public int[] rearrangeArray(int[] nums) { + int n = nums.length; // Get the total number of elements in the input array + int ans[] = new int[n]; // Create a new array to store the rearranged elements + + int pos = 0; // Pointer for placing positive numbers (even indices) + int neg = 1; // Pointer for placing negative numbers (odd indices) + + // Traverse through each element in the input array + for (int i = 0; i < n; i++) { + if (nums[i] > 0) { // If the current number is positive + ans[pos] = nums[i]; // Place it at the current positive index + pos = pos + 2; // Move to the next positive position (skip one index) + } else { // Otherwise, it's a negative number + ans[neg] = nums[i]; // Place it at the current negative index + neg = neg + 2; // Move to the next negative position + } + } + + return ans; // Return the rearranged array + } +} diff --git a/java/Arrays/SortColors.java b/java/Arrays/SortColors.java new file mode 100644 index 00000000..a8a41d19 --- /dev/null +++ b/java/Arrays/SortColors.java @@ -0,0 +1,29 @@ +package Arrays; + +class Solution { + public void Swap(int[] arr,int i,int j){ + int temp = arr[i]; + arr[i]= arr[j]; + arr[j]=temp; + } + public void sortColors(int[] arr) { + int n=arr.length; + int lo=0; + int mid=0; + int hi=n-1; + while(mid<=hi){ + if(arr[mid]==0){ + Swap(arr,mid,lo); + lo++; + mid++; + } + else if(arr[mid]==1){ + mid++; + } + else if(arr[mid]==2){ + Swap(arr,mid,hi); + hi--; + } + } + } +} \ No newline at end of file diff --git a/java/Arrays/ThreeeeSum.java b/java/Arrays/ThreeeeSum.java new file mode 100644 index 00000000..99843d27 --- /dev/null +++ b/java/Arrays/ThreeeeSum.java @@ -0,0 +1,37 @@ +import java.util.*; + +public class ThreeeeSum { + public List> threeSum(int[] nums) { + Arrays.sort(nums); + List> result = new ArrayList<>(); + + for (int i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates + + int left = i + 1, right = nums.length - 1; + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + + if (sum == 0) { + result.add(Arrays.asList(nums[i], nums[left], nums[right])); + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } else if (sum < 0) { + left++; + } else { + right--; + } + } + } + + return result; + } + + public static void main(String[] args) { + ThreeeeSum obj = new ThreeeeSum(); + System.out.println(obj.threeSum(new int[]{-1,0,1,2,-1,-4})); + // [[-1,-1,2], [-1,0,1]] + } +} diff --git a/java/Arrays/TransposeMatrix.java b/java/Arrays/TransposeMatrix.java new file mode 100644 index 00000000..32b4221a --- /dev/null +++ b/java/Arrays/TransposeMatrix.java @@ -0,0 +1,76 @@ +package Arrays; + +import java.util.Scanner; + +public class TransposeMatrix { + + + public static void main(String[] args) { + Scanner scanner=new Scanner(System.in); + + + System.out.println("Enter the row size:"); + int row=scanner.nextInt(); + System.out.println("Enter the column size:"); + int col=scanner.nextInt(); + + if(row==col) { + + + + + int arr[][]=new int[row][col]; + + int trans[][]=new int[row][col]; + + System.out.println("Enter elements matrix:"); + for (int i = 0; i < row; i++) { + + for (int j = 0; j < col; j++) { + + arr[i][j]=scanner.nextInt(); + + } + } + + System.out.println("elements :"); + for (int i = 0; i < row; i++) { + + for (int j = 0; j < col; j++) { + + System.out.print(arr[i][j]+" "); + + } + System.out.println(); + } + System.out.println("Transpose :"); + for (int i = 0; i < row; i++) { + + for (int j = 0; j < col; j++) { + + trans[i][j]=arr[j][i]; + + } + System.out.println(); + } + + for (int i = 0; i < row; i++) { + + for (int j = 0; j < col; j++) { + + System.out.print(trans[i][j]+" "); + + } + System.out.println(); + } + + } + else { + System.out.println("row and column size must be same...."); + } + + } + + + +} \ No newline at end of file diff --git a/java/Arrays/TriangularSumArray.java b/java/Arrays/TriangularSumArray.java new file mode 100644 index 00000000..1542f874 --- /dev/null +++ b/java/Arrays/TriangularSumArray.java @@ -0,0 +1,28 @@ + +public class TriangularSumArray { + + public static void main(String[] args) { + // Example input + int[] nums = {1, 2, 3, 4, 5}; + + // Call the function + int result = triangularSum(nums); + + // Print the result + System.out.println("Triangular Sum: " + result); + } + + public static int triangularSum(int[] nums) { + int n = nums.length; + + // Reduce the array step by step + for (int size = n; size > 1; size--) { + for (int i = 0; i < size - 1; i++) { + nums[i] = (nums[i] + nums[i + 1]) % 10; + } + } + + // The first element becomes the final triangular sum + return nums[0]; + } +} diff --git a/java/Arrays/TwoSum.java b/java/Arrays/TwoSum.java new file mode 100644 index 00000000..57b3fff6 --- /dev/null +++ b/java/Arrays/TwoSum.java @@ -0,0 +1,20 @@ +import java.util.HashMap; + +class TwoSum { + public int[] twoSum(int[] nums, int target) { + HashMap map = new HashMap<>(); // Stores number → index + + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; // The number needed to reach target + + if (map.containsKey(complement)) { + return new int[]{map.get(complement), i}; // Found the pair + } + + map.put(nums[i], i); // Store current number and its index + } + + return new int[]{}; // If no pair found + } +} + diff --git a/java/BFS.class b/java/BFS.class new file mode 100644 index 00000000..ed6a24cc Binary files /dev/null and b/java/BFS.class differ diff --git a/java/BFS.java b/java/BFS.java index a4b43f7d..ce024efd 100644 --- a/java/BFS.java +++ b/java/BFS.java @@ -1,82 +1,67 @@ // BFS from given source s import java.util.*; +import java.util.Queue; +import java.util.LinkedList; -class Main { +public class BFS { - // BFS from given source s - static ArrayList - bfsOfGraph(ArrayList> adj, - int s, boolean[] visited, ArrayList res) { - - // Create a queue for BFS - Queue q = new LinkedList<>(); - - // Mark source node as visited and enqueue it - visited[s] = true; - q.add(s); - - // Iterate over the queue - while (!q.isEmpty()) { - - // Dequeue a vertex and store it - int curr = q.poll(); - res.add(curr); - - // Get all adjacent vertices of the dequeued - // vertex curr If an adjacent has not been - // visited, mark it visited and enqueue it - for (int x : adj.get(curr)) { - if (!visited[x]) { - visited[x] = true; - q.add(x); - } - } - } - return res; - } - - // Perform BFS for the entire graph which maybe - // disconnected - static ArrayList bfsDisconnected( - ArrayList> adj) { + static ArrayList bfs(ArrayList> adj) { int V = adj.size(); - - // create an array to store the traversal - ArrayList res = new ArrayList<>(); - - // Initially mark all the vertices as not visited + ArrayList result = new ArrayList<>(); boolean[] visited = new boolean[V]; + Queue q = new LinkedList<>(); - // perform BFS for each node - for (int i = 0; i < V; i++) { - if (!visited[i]) { - bfsOfGraph(adj, i, visited, res); + // Iterate through all vertices to ensure all components are visited + for (int startNode = 0; startNode < V; startNode++) { + + // Start BFS only if the node hasn't been visited (i.e., it's a new component) + if (!visited[startNode]) { + // Initialize the BFS for the new component + visited[startNode] = true; + q.add(startNode); + + // Standard BFS logic + while (!q.isEmpty()) { + int curr = q.poll(); + result.add(curr); // Add the current node to the result list + + // Traverse neighbors + for (int neighbor : adj.get(curr)) { + if (!visited[neighbor]) { + visited[neighbor] = true; + q.add(neighbor); + } + } + } } } - return res; + return result; } public static void main(String[] args) { + // Graph from the original example: + // Component 1: 0, 1, 2 + // Component 2: 3, 4, 5 ArrayList> adj = new ArrayList<>(); - adj.add(new ArrayList<>(Arrays.asList(1, 2))); + + // Node 0: neighbors 1, 2 + adj.add(new ArrayList<>(Arrays.asList(1, 2))); + // Node 1: neighbor 0 adj.add(new ArrayList<>(Arrays.asList(0))); - adj.add(new ArrayList<>(Arrays.asList(0))); + // Node 2: neighbor 0 + adj.add(new ArrayList<>(Arrays.asList(0))); + // Node 3: neighbor 4 adj.add(new ArrayList<>(Arrays.asList(4))); + // Node 4: neighbors 3, 5 adj.add(new ArrayList<>(Arrays.asList(3, 5))); - adj.add(new ArrayList<>(Arrays.asList(4))); + // Node 5: neighbor 4 + adj.add(new ArrayList<>(Arrays.asList(4))); - int src = 0; - ArrayList ans = bfsDisconnected(adj); + ArrayList ans = bfs(adj); + System.out.println("BFS Traversal:"); for (int i : ans) { System.out.print(i + " "); } + System.out.println(); } -} - -// Output -// 0 1 2 3 4 5 - - -// Time Complexity: O(V + E), BFS explores all the vertices and edges in the graph. In the worst case, it visits every vertex and edge once. Therefore, the time complexity of BFS is O(V + E), where V and E are the number of vertices and edges in the given graph. - -// Auxiliary Space: O(V), BFS uses a queue to keep track of the vertices that need to be visited. In the worst case, the queue can contain all the vertices in the graph. Therefore, the space complexity of BFS is O(V). +} \ No newline at end of file diff --git a/java/BSTDemo.java b/java/BSTDemo.java new file mode 100644 index 00000000..94800d7b --- /dev/null +++ b/java/BSTDemo.java @@ -0,0 +1,147 @@ +import java.util.*; + +// Node class for BST +class BSTNode { + int data; + BSTNode left, right; + + BSTNode(int value) { + data = value; + left = right = null; + } +} + +class BSTViews { + BSTNode root; + + BSTViews() { root = null; } + + // Insert + void insert(int value) { + root = insertRec(root, value); + } + + BSTNode insertRec(BSTNode node, int value) { + if (node == null) return new BSTNode(value); + if (value < node.data) node.left = insertRec(node.left, value); + else if (value > node.data) node.right = insertRec(node.right, value); + return node; + } + + // Traversals + void preorder(BSTNode node) { + if (node == null) return; + System.out.print(node.data + " "); + preorder(node.left); + preorder(node.right); + } + + void inorder(BSTNode node) { + if (node == null) return; + inorder(node.left); + System.out.print(node.data + " "); + inorder(node.right); + } + + void postorder(BSTNode node) { + if (node == null) return; + postorder(node.left); + postorder(node.right); + System.out.print(node.data + " "); + } + + void levelOrder() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + BSTNode temp = q.poll(); + System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + + // Left View + void leftView() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + int n = q.size(); + for (int i = 1; i <= n; i++) { + BSTNode temp = q.poll(); + if (i == 1) System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + } + + // Right View + void rightView() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + int n = q.size(); + for (int i = 1; i <= n; i++) { + BSTNode temp = q.poll(); + if (i == n) System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + } + + // Top View + void topView() { + if (root == null) return; + class Pair { BSTNode node; int hd; Pair(BSTNode n, int h) {node=n;hd=h;} } + Queue q = new LinkedList<>(); + Map map = new TreeMap<>(); + q.add(new Pair(root, 0)); + while (!q.isEmpty()) { + Pair p = q.poll(); + if (!map.containsKey(p.hd)) map.put(p.hd, p.node.data); + if (p.node.left != null) q.add(new Pair(p.node.left, p.hd-1)); + if (p.node.right != null) q.add(new Pair(p.node.right, p.hd+1)); + } + for (int val : map.values()) System.out.print(val + " "); + } + + // Bottom View + void bottomView() { + if (root == null) return; + class Pair { BSTNode node; int hd; Pair(BSTNode n,int h){node=n;hd=h;} } + Queue q = new LinkedList<>(); + Map map = new TreeMap<>(); + q.add(new Pair(root,0)); + while(!q.isEmpty()){ + Pair p = q.poll(); + map.put(p.hd, p.node.data); + if(p.node.left!=null) q.add(new Pair(p.node.left,p.hd-1)); + if(p.node.right!=null) q.add(new Pair(p.node.right,p.hd+1)); + } + for(int val: map.values()) System.out.print(val + " "); + } +} + +// Demo to prove correctness +public class BSTDemo { + public static void main(String[] args) { + BSTViews bst = new BSTViews(); + int[] values = {50, 30, 20, 40, 70, 60, 80}; + for(int val : values) bst.insert(val); + + System.out.println("BST Views:"); + System.out.print("Preorder: "); bst.preorder(bst.root); System.out.println(); + System.out.print("Inorder: "); bst.inorder(bst.root); System.out.println(); + System.out.print("Postorder: "); bst.postorder(bst.root); System.out.println(); + System.out.print("Level-order: "); bst.levelOrder(); System.out.println(); + System.out.print("Left View: "); bst.leftView(); System.out.println(); + System.out.print("Right View: "); bst.rightView(); System.out.println(); + System.out.print("Top View: "); bst.topView(); System.out.println(); + System.out.print("Bottom View: "); bst.bottomView(); System.out.println(); + } +} diff --git a/java/BackTracking/Arrays.class b/java/BackTracking/Arrays.class new file mode 100644 index 00000000..8a18091a Binary files /dev/null and b/java/BackTracking/Arrays.class differ diff --git a/java/BackTracking/Arrays.java b/java/BackTracking/Arrays.java new file mode 100644 index 00000000..17d64155 --- /dev/null +++ b/java/BackTracking/Arrays.java @@ -0,0 +1,41 @@ +public class Arrays{ + public static void main(String args[]){ + // only initialize an array + // we will fill this arr using recursion + + int arr[] = new int[5]; + + // idx on each element + int i=0; + + // element's value + int val = 1; + + changeArrays(arr, i, val); + printArr(arr); + } + + public static void printArr(int arr[]){ + for(int i=0; i a new str char is added to the ans str + findSubsets(str, i+1, ans+str.charAt(i)); + + // NO choice -> a new str char is not added to the ans str + findSubsets(str, i+1, ans); + + } +} \ No newline at end of file diff --git a/java/BackTracking/GridWays.class b/java/BackTracking/GridWays.class new file mode 100644 index 00000000..f3c04577 Binary files /dev/null and b/java/BackTracking/GridWays.class differ diff --git a/java/BackTracking/GridWays.java b/java/BackTracking/GridWays.java new file mode 100644 index 00000000..8abb9e26 --- /dev/null +++ b/java/BackTracking/GridWays.java @@ -0,0 +1,25 @@ +public class GridWays{ + public static void main(String args[]){ + int n=10, m=10; + int i=0, j=0; + + System.out.println(gridways(m, n, i, j)); + } + + public static int gridways(int m, int n, int i, int j){ + + // base case + if(i == n-1 && j==m-1){ // last case condition (cell at the boundary / last cell ) + return 1; + } else if( i == n || j == m){ // if cell exceeds boundary + return 0; + } + + // 2 cases only exists + + // 1. go right + int w1_right = gridways(m,n,i+1, j); + int w2_down = gridways(m, n, i, j+1); + return w1_right + w2_down; + } +} \ No newline at end of file diff --git a/java/BackTracking/Permutation.class b/java/BackTracking/Permutation.class new file mode 100644 index 00000000..3f6840dd Binary files /dev/null and b/java/BackTracking/Permutation.class differ diff --git a/java/BackTracking/Permutation.java b/java/BackTracking/Permutation.java new file mode 100644 index 00000000..49ccebaf --- /dev/null +++ b/java/BackTracking/Permutation.java @@ -0,0 +1,27 @@ +import java.util.*; +public class Permutation{ + public static void main(String args[]){ + String str = "abc"; + findPermutation(str, " "); + } + + public static void findPermutation(String str, String ans){ + if(str.length() == 0){ + System.out.print(ans); + return; + } + + // recursion + for(int i = 0; i < str.length(); i++){ + + // to access the string's curr character + char curr = str.charAt(i); + + // now i want to delete that curr char from the str bec we cant access that char again + // "abcde" => "ab" + "de" = "abde" + String Newstr = str.substring(0, i) + str.substring(i+1); + findPermutation(Newstr, ans+curr); + } + + } +} \ No newline at end of file diff --git a/java/BackTracking/nQueen.class b/java/BackTracking/nQueen.class new file mode 100644 index 00000000..469b5b78 Binary files /dev/null and b/java/BackTracking/nQueen.class differ diff --git a/java/BackTracking/nQueen.java b/java/BackTracking/nQueen.java new file mode 100644 index 00000000..a6eadc97 --- /dev/null +++ b/java/BackTracking/nQueen.java @@ -0,0 +1,74 @@ +public class nQueen{ + public static void main(String args[]){ + int n=4; + char board[][] = new char[n][n]; + int row=0; + // initialize + for(int i=0; i=0; i--){ + if(board[i][col] == 'Q'){ + return false; + } + } + + // 2. no queens in diagonal left up (Diagonal up Check) + for(int i=row-1, j = col-1; i>=0 && j>=0; i--, j--){ + if(board[i][j] == 'Q'){ + return false; + } + } + + // 3. no queens in diagonal right up (Diagonal up Check) + for(int i=row-1, j = col+1; i>=0 && j= 0; i--) { + if (board[i][col] == 'Q') { + return false; + } + } + // left diagonal + for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) { + if (board[i][j] == 'Q') { + return false; + } + } + // right diagonal + for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) { + if (board[i][j] == 'Q') { + return false; + } + } + return true; + } +} diff --git a/java/Bank.class b/java/Bank.class new file mode 100644 index 00000000..8d21b9bd Binary files /dev/null and b/java/Bank.class differ diff --git a/java/BankManagementSystem.class b/java/BankManagementSystem.class new file mode 100644 index 00000000..34afe1b0 Binary files /dev/null and b/java/BankManagementSystem.class differ diff --git a/java/BankManagementSystem.java b/java/BankManagementSystem.java new file mode 100644 index 00000000..f9e66e39 --- /dev/null +++ b/java/BankManagementSystem.java @@ -0,0 +1,166 @@ +import java.util.*; + +// Abstraction +abstract class Account { + private static int counter = 1000; + protected String accountNumber; + protected double balance; + + public Account(double initialDeposit) { + this.accountNumber = "ACCT" + (++counter); + this.balance = initialDeposit; + } + + public String getAccountNumber() { + return accountNumber; + } + + public double getBalance() { + return balance; + } + + public abstract void deposit(double amount); + public abstract void withdraw(double amount); + + @Override + public String toString() { + return "Account Number: " + accountNumber + ", Balance: $" + balance; + } +} + +// Inheritance and Polymorphism (overriding) +class SavingsAccount extends Account { + private double interestRate = 0.04; + + public SavingsAccount(double deposit) { + super(deposit); + } + + @Override + public void deposit(double amount) { + balance += amount + (amount * interestRate); + } + + @Override + public void withdraw(double amount) { + if (amount <= balance) { + balance -= amount; + } else { + System.out.println("Insufficient balance."); + } + } +} + +class CurrentAccount extends Account { + private double overdraftLimit = 500; + + public CurrentAccount(double deposit) { + super(deposit); + } + + @Override + public void deposit(double amount) { + balance += amount; + } + + @Override + public void withdraw(double amount) { + if (balance + overdraftLimit >= amount) { + balance -= amount; + } else { + System.out.println("Overdraft limit exceeded."); + } + } +} + +// Encapsulation +class Customer { + private String customerId; + private String name; + private List accounts; + + public Customer(String customerId, String name) { + this.customerId = customerId; + this.name = name; + this.accounts = new ArrayList<>(); + } + + public String getCustomerId() { + return customerId; + } + + public String getName() { + return name; + } + + public void addAccount(Account account) { + accounts.add(account); + } + + public List getAccounts() { + return accounts; + } + + @Override + public String toString() { + return "Customer ID: " + customerId + ", Name: " + name; + } +} + +// Aggregation - Bank has Customers +class Bank { + private String name; + private Map customers; + + public Bank(String name) { + this.name = name; + this.customers = new HashMap<>(); + } + + public void addCustomer(Customer customer) { + customers.put(customer.getCustomerId(), customer); + } + + public Customer getCustomer(String id) { + return customers.get(id); + } + + public void displayAllCustomers() { + for (Customer c : customers.values()) { + System.out.println(c); + for (Account a : c.getAccounts()) { + System.out.println(" -> " + a); + } + } + } +} + +// Main Class +public class BankManagementSystem { + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Bank bank = new Bank("Global Bank"); + + Customer c1 = new Customer("C101", "Alice"); + Account a1 = new SavingsAccount(1000); + Account a2 = new CurrentAccount(2000); + c1.addAccount(a1); + c1.addAccount(a2); + + Customer c2 = new Customer("C102", "Bob"); + Account a3 = new SavingsAccount(1500); + c2.addAccount(a3); + + bank.addCustomer(c1); + bank.addCustomer(c2); + + // Polymorphism (method overriding at runtime) + a1.deposit(500); // Applies interest + a2.withdraw(2500); // Uses overdraft + a3.withdraw(300); // Simple savings withdrawal + + bank.displayAllCustomers(); + + scanner.close(); + } +} diff --git a/java/Best Time to Buy and Sell Stock.java b/java/BestTimetoBuyandSellStock.java similarity index 96% rename from java/Best Time to Buy and Sell Stock.java rename to java/BestTimetoBuyandSellStock.java index 6ca80c89..037ab742 100644 --- a/java/Best Time to Buy and Sell Stock.java +++ b/java/BestTimetoBuyandSellStock.java @@ -1,20 +1,20 @@ -public class BestTimeToBuySellStock { - public int maxProfit(int[] prices) { - int minPrice = Integer.MAX_VALUE; - int maxProfit = 0; - - for (int price : prices) { - if (price < minPrice) { - minPrice = price; - } else if (price - minPrice > maxProfit) { - maxProfit = price - minPrice; - } - } - return maxProfit; - } - - public static void main(String[] args) { - BestTimeToBuySellStock obj = new BestTimeToBuySellStock(); - System.out.println(obj.maxProfit(new int[]{7,1,5,3,6,4})); // 5 - } -} +public class BestTimeToBuySellStock { + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE; + int maxProfit = 0; + + for (int price : prices) { + if (price < minPrice) { + minPrice = price; + } else if (price - minPrice > maxProfit) { + maxProfit = price - minPrice; + } + } + return maxProfit; + } + + public static void main(String[] args) { + BestTimeToBuySellStock obj = new BestTimeToBuySellStock(); + System.out.println(obj.maxProfit(new int[]{7,1,5,3,6,4})); // 5 + } +} diff --git a/java/Best_Time_To_Buy_And_Sell_Stocks.java b/java/Best_Time_To_Buy_And_Sell_Stocks.java new file mode 100644 index 00000000..037ab742 --- /dev/null +++ b/java/Best_Time_To_Buy_And_Sell_Stocks.java @@ -0,0 +1,20 @@ +public class BestTimeToBuySellStock { + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE; + int maxProfit = 0; + + for (int price : prices) { + if (price < minPrice) { + minPrice = price; + } else if (price - minPrice > maxProfit) { + maxProfit = price - minPrice; + } + } + return maxProfit; + } + + public static void main(String[] args) { + BestTimeToBuySellStock obj = new BestTimeToBuySellStock(); + System.out.println(obj.maxProfit(new int[]{7,1,5,3,6,4})); // 5 + } +} diff --git a/java/BinarySearchTree$Node.class b/java/BinarySearchTree$Node.class new file mode 100644 index 00000000..18a667c0 Binary files /dev/null and b/java/BinarySearchTree$Node.class differ diff --git a/java/BinarySearchTree.class b/java/BinarySearchTree.class new file mode 100644 index 00000000..ddee50cd Binary files /dev/null and b/java/BinarySearchTree.class differ diff --git a/java/BinarySearchTree.java b/java/BinarySearchTree.java index 5940360c..8714fba0 100644 --- a/java/BinarySearchTree.java +++ b/java/BinarySearchTree.java @@ -1,15 +1,19 @@ /** - * BinarySearchTree class: Implements a Binary Search Tree (BST) - * with insertion and deletion operations, utilizing the Node structure - * from BinaryTree. + * with insertion, deletion, and traversal operations. */ public class BinarySearchTree { - // Reuse the Node structure defined in BinaryTree.java - public static class Node extends BinaryTree.Node { + // Node class for BST + public static class Node { + int data; + Node left; + Node right; + public Node(int data) { - super(data); + this.data = data; + this.left = null; + this.right = null; } } @@ -19,151 +23,60 @@ public BinarySearchTree() { this.root = null; } - // --- 1. Insertion Operation --- - + // Insert operation public void insert(int data) { root = insertRec(root, data); } - // A recursive function to insert a new key in BST private Node insertRec(Node root, int data) { - // If the tree is empty, return a new node if (root == null) { - root = new Node(data); - return root; + return new Node(data); } - - // Otherwise, recur down the tree if (data < root.data) { - root.left = insertRec((Node) root.left, data); + root.left = insertRec(root.left, data); } else if (data > root.data) { - root.right = insertRec((Node) root.right, data); + root.right = insertRec(root.right, data); } - - // Return the (unchanged) node pointer return root; } - // --- 2. Deletion Operation --- - + // Delete operation public void delete(int data) { root = deleteRec(root, data); } - // A recursive function to delete a key in BST private Node deleteRec(Node root, int data) { - // Base case: If the tree is empty or the key is not found - - * Implements a Binary Search Tree (BST) with insertion, deletion, and traversal operations. - * It inherits properties from the BinaryTree class. - */ -public class BinarySearchTree extends BinaryTree { - - /** - * Inserts a new key into the BST. - * @param key The data to insert. - */ - public void insert(int key) { - root = insertRec(root, key); - } - - /** - * A recursive utility function to insert a new key in the BST. - * @param root The current root of the subtree. - * @param key The data to insert. - * @return The node pointer (after insertion). - */ - private Node insertRec(Node root, int key) { if (root == null) { - root = new Node(key); return root; } - if (key < root.data) { - root.left = insertRec(root.left, key); - } else if (key > root.data) { - root.right = insertRec(root.right, key); - } - return root; - } - - /** - * Deletes a key from the BST. - * @param key The data to delete. - */ - public void delete(int key) { - root = deleteRec(root, key); - } - - /** - * A recursive utility function to delete a key from the BST. - * @param root The current root of the subtree. - * @param key The data to delete. - * @return The root of the modified subtree. - */ - private Node deleteRec(Node root, int key) { - if (root == null) { - return root; - } - - - // Recur down the tree if (data < root.data) { - root.left = deleteRec((Node) root.left, data); + root.left = deleteRec(root.left, data); } else if (data > root.data) { - root.right = deleteRec((Node) root.right, data); - } - // If data is the same as root's data, then this is the node to be deleted - else { - // Case 1: Node with only one child or no child - if (root.left == null) { - return (Node) root.right; - } else if (root.right == null) { - return (Node) root.left; - } - - // Case 2: Node with two children: Get the inorder successor - // (smallest in the right subtree) - root.data = minValue((Node) root.right); - - // Delete the inorder successor - root.right = deleteRec((Node) root.right, root.data); - - if (key < root.data) { - root.left = deleteRec(root.left, key); - } else if (key > root.data) { - root.right = deleteRec(root.right, key); + root.right = deleteRec(root.right, data); } else { - // Node with only one child or no child if (root.left == null) { return root.right; } else if (root.right == null) { return root.left; } - // Node with two children: Get the inorder successor (smallest in the right subtree) root.data = minValue(root.right); - - // Delete the inorder successor root.right = deleteRec(root.right, root.data); - } - return root; } - // Helper function to find the minimum value node in a BST private int minValue(Node root) { int minValue = root.data; while (root.left != null) { minValue = root.left.data; - root = (Node) root.left; + root = root.left; } return minValue; } - // --- 3. Traversal (Can call BinaryTree methods, but re-implementing for completeness) --- - + // Inorder traversal public void inorderTraversal() { System.out.print("Inorder Traversal: "); inorderRec(root); @@ -172,23 +85,9 @@ public void inorderTraversal() { private void inorderRec(Node root) { if (root != null) { - inorderRec((Node) root.left); + inorderRec(root.left); System.out.print(root.data + " "); - inorderRec((Node) root.right); - } - - /** - * Finds the minimum value in a given subtree. - * @param root The root of the subtree. - * @return The minimum value. - */ - private int minValue(Node root) { - int minv = root.data; - while (root.left != null) { - minv = root.left.data; - root = root.left; + inorderRec(root.right); } - return minv; - } -} +} \ No newline at end of file diff --git a/java/BinarySearchTreeTest.java b/java/BinarySearchTreeTest.java new file mode 100644 index 00000000..76ebf5aa --- /dev/null +++ b/java/BinarySearchTreeTest.java @@ -0,0 +1,24 @@ +public class BinarySearchTreeTest { + public static void main(String[] args) { + BinarySearchTree bst = new BinarySearchTree(); + + bst.insert(50); + bst.insert(30); + bst.insert(70); + bst.insert(20); + bst.insert(40); + bst.insert(60); + bst.insert(80); + + bst.inorderTraversal(); + + bst.delete(20); + bst.inorderTraversal(); + + bst.delete(30); + bst.inorderTraversal(); + + bst.delete(50); + bst.inorderTraversal(); + } +} \ No newline at end of file diff --git a/java/BinaryTree$Node.class b/java/BinaryTree$Node.class new file mode 100644 index 00000000..e2fba943 Binary files /dev/null and b/java/BinaryTree$Node.class differ diff --git a/java/BinaryTree$Pair.class b/java/BinaryTree$Pair.class new file mode 100644 index 00000000..b2f76c0b Binary files /dev/null and b/java/BinaryTree$Pair.class differ diff --git a/java/BinaryTree.class b/java/BinaryTree.class new file mode 100644 index 00000000..d6e6e2ff Binary files /dev/null and b/java/BinaryTree.class differ diff --git a/java/BinaryTree.java b/java/BinaryTree.java index f406218a..5eed80e7 100644 --- a/java/BinaryTree.java +++ b/java/BinaryTree.java @@ -1,5 +1,6 @@ import java.util.*; - +import java.util.LinkedList; +import java.util.Queue; /** * BinaryTree class: Implements generic Binary Tree operations, including @@ -50,337 +51,352 @@ public void postorder(Node node) { postorder(node.left); postorder(node.right); - * Represents a single node in a binary tree. - */ -class Node { - int data; - Node left; - Node right; - - /** - * Constructor to create a new node. - * @param data The data to be stored in the node. - */ - public Node(int data) { - this.data = data; - left = null; - right = null; - } -} + /* Represents a single node in a binary tree. + */ + class Node { + int data; + Node left; + Node right; + + /** + * Constructor to create a new node. + * + * @param data The data to be stored in the node. + */ + public Node(int data) { + this.data = data; + left = null; + right = null; + } + } /** * Implements a Binary Tree and includes methods for traversal and different views. */ -public class BinaryTree { - Node root; - - public BinaryTree() { - root = null; - } - - /** - * Performs an in-order traversal of the binary tree. - * @param node The current node in the traversal. - */ - public void inOrder(Node node) { - if (node != null) { - inOrder(node.left); - System.out.print(node.data + " "); - inOrder(node.right); - } - } - - /** - * Performs a pre-order traversal of the binary tree. - * @param node The current node in the traversal. - */ - public void preOrder(Node node) { - if (node != null) { - System.out.print(node.data + " "); - preOrder(node.left); - preOrder(node.right); - } - } - - /** - * Performs a post-order traversal of the binary tree. - * @param node The current node in the traversal. - */ - public void postOrder(Node node) { - if (node != null) { - postOrder(node.left); - postOrder(node.right); - - System.out.print(node.data + " "); - } - } - - // --- 3. View Methods (Utility) --- + public class BinaryTree { + Node root; - // Top View: Nodes visible when looking from the top (first node encountered at each Horizontal Distance) - public List topView() { - List result = new ArrayList<>(); - if (root == null) return result; - - // Map stores - Map map = new TreeMap<>(); - // Queue stores - Queue> queue = new LinkedList<>(); - - queue.add(new Pair<>(root, 0)); - - while (!queue.isEmpty()) { - Pair current = queue.poll(); - Node node = current.key; - int hd = current.value; - - // Only update if this HD is encountered for the first time (this is the 'top' node) - if (!map.containsKey(hd)) { - map.put(hd, node.data); - } - - if (node.left != null) { - queue.add(new Pair<>(node.left, hd - 1)); - } - if (node.right != null) { - queue.add(new Pair<>(node.right, hd + 1)); - } - } - - // Add all values from the sorted map (TreeMap ensures HD is sorted) to the result list - result.addAll(map.values()); - return result; - } - - // Bottom View: Nodes visible when looking from the bottom (last node encountered at each Horizontal Distance) - public List bottomView() { - List result = new ArrayList<>(); - if (root == null) return result; - - // Map stores - Map map = new TreeMap<>(); - // Queue stores - Queue> queue = new LinkedList<>(); - - queue.add(new Pair<>(root, 0)); - - while (!queue.isEmpty()) { - Pair current = queue.poll(); - Node node = current.key; - int hd = current.value; - - // Always update the map. The last node processed for a given HD in BFS - // will be the lowest/closest to the bottom at that HD. - map.put(hd, node.data); - - if (node.left != null) { - queue.add(new Pair<>(node.left, hd - 1)); - } - if (node.right != null) { - queue.add(new Pair<>(node.right, hd + 1)); - } - } - - result.addAll(map.values()); - return result; - } - - // Left View: The first node of every level - public List leftView() { - List result = new ArrayList<>(); - leftView(root, 1, new int[]{0}, result); - return result; - } + public void BinaryTree(Node root) { + root = null; + } - // Recursive helper for Left View - private void leftView(Node node, int level, int[] maxLevel, List result) { - if (node == null) return; + /** + * Performs an in-order traversal of the binary tree. + * + * @param node The current node in the traversal. + */ + public void inOrder(Node node) { + if (node != null) { + inOrder(node.left); + System.out.print(node.data + " "); + inOrder(node.right); + } + } - // If this is the first node at the current level, add it to the view - if (maxLevel[0] < level) { - result.add(node.data); - maxLevel[0] = level; - } + /** + * Performs a pre-order traversal of the binary tree. + * + * @param node The current node in the traversal. + */ + public void preOrder(Node node) { + if (node != null) { + System.out.print(node.data + " "); + preOrder(node.left); + preOrder(node.right); + } + } - // Recurse left first to ensure the leftmost node is processed first - leftView(node.left, level + 1, maxLevel, result); - leftView(node.right, level + 1, maxLevel, result); - } + /** + * Performs a post-order traversal of the binary tree. + * + * @param node The current node in the traversal. + */ + public void postOrder(Node node) { + if (node != null) { + postOrder(node.left); + postOrder(node.right); + + System.out.print(node.data + " "); + } + } - // Right View: The last node of every level - public List rightView() { - List result = new ArrayList<>(); - rightView(root, 1, new int[]{0}, result); - return result; - } - - // Recursive helper for Right View - private void rightView(Node node, int level, int[] maxLevel, List result) { - if (node == null) return; - - // If this is the first node at the current level, add it to the view - if (maxLevel[0] < level) { - result.add(node.data); - maxLevel[0] = level; - } + // --- 3. View Methods (Utility) --- + + // Top View: Nodes visible when looking from the top (first node encountered at each Horizontal Distance) + public List topView() { + List result = new ArrayList<>(); + if (root == null) return result; + + // Map stores + Map map = new TreeMap<>(); + // Queue stores + Queue> queue = new LinkedList<>(); + + queue.add(new Pair<>(root, 0)); + + while (!queue.isEmpty()) { + Pair current = queue.poll(); + Node node = current.key; + int hd = current.value; + + // Only update if this HD is encountered for the first time (this is the 'top' node) + if (!map.containsKey(hd)) { + map.put(hd, node.data); + } + + if (node.left != null) { + queue.add(new Pair<>(node.left, hd - 1)); + } + if (node.right != null) { + queue.add(new Pair<>(node.right, hd + 1)); + } + } + + // Add all values from the sorted map (TreeMap ensures HD is sorted) to the result list + result.addAll(map.values()); + return result; + } - // Recurse right first to ensure the rightmost node is processed first - rightView(node.right, level + 1, maxLevel, result); - rightView(node.left, level + 1, maxLevel, result); - } + // Bottom View: Nodes visible when looking from the bottom (last node encountered at each Horizontal Distance) + public List bottomView() { + List result = new ArrayList<>(); + if (root == null) return result; + + // Map stores + Map map = new TreeMap<>(); + // Queue stores + Queue> queue = new LinkedList<>(); + + queue.add(new Pair<>(root, 0)); + + while (!queue.isEmpty()) { + Pair current = queue.poll(); + Node node = current.key; + int hd = current.value; + + // Always update the map. The last node processed for a given HD in BFS + // will be the lowest/closest to the bottom at that HD. + map.put(hd, node.data); + + if (node.left != null) { + queue.add(new Pair<>(node.left, hd - 1)); + } + if (node.right != null) { + queue.add(new Pair<>(node.right, hd + 1)); + } + } + + result.addAll(map.values()); + return result; + } - // Helper class for combining Node and Horizontal Distance in the Queue (for Top/Bottom View) - private static class Pair { - K key; - V value; + // Left View: The first node of every level + public List leftView() { + List result = new ArrayList<>(); + leftView(root, 1, new int[]{0}, result); + return result; + } - public Pair(K key, V value) { - this.key = key; - this.value = value; - } + // Recursive helper for Left View + private void leftView(Node node, int level, int[] maxLevel, List result) { + if (node == null) return; - /** - * Computes and prints the top view of the binary tree. - * The top view consists of the nodes that are visible from the top. - */ - public void topView() { - if (root == null) { - return; - } + // If this is the first node at the current level, add it to the view + if (maxLevel[0] < level) { + result.add(node.data); + maxLevel[0] = level; + } - class QueueObj { - Node node; - int hd; // Horizontal Distance + // Recurse left first to ensure the leftmost node is processed first + leftView(node.left, level + 1, maxLevel, result); + leftView(node.right, level + 1, maxLevel, result); + } - QueueObj(Node node, int hd) { - this.node = node; - this.hd = hd; - } - } + // Right View: The last node of every level + public List rightView() { + List result = new ArrayList<>(); + rightView(root, 1, new int[]{0}, result); + return result; + } - Queue q = new LinkedList<>(); - Map topViewMap = new TreeMap<>(); + // Recursive helper for Right View + private void rightView(Node node, int level, int[] maxLevel, List result) { + if (node == null) return; - q.add(new QueueObj(root, 0)); + // If this is the first node at the current level, add it to the view + if (maxLevel[0] < level) { + result.add(node.data); + maxLevel[0] = level; + } - while (!q.isEmpty()) { - QueueObj tmpNode = q.poll(); - if (!topViewMap.containsKey(tmpNode.hd)) { - topViewMap.put(tmpNode.hd, tmpNode.node); - } + // Recurse right first to ensure the rightmost node is processed first + rightView(node.right, level + 1, maxLevel, result); + rightView(node.left, level + 1, maxLevel, result); + } - if (tmpNode.node.left != null) { - q.add(new QueueObj(tmpNode.node.left, tmpNode.hd - 1)); - } - if (tmpNode.node.right != null) { - q.add(new QueueObj(tmpNode.node.right, tmpNode.hd + 1)); - } - } + // Helper class for combining Node and Horizontal Distance in the Queue (for Top/Bottom View) + private static class Pair { + K key; + V value; + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + /** + * Computes and prints the top view of the binary tree. + * The top view consists of the nodes that are visible from the top. + */ + public void topView() { + if (root == null) { + return; + } + } + + class QueueObj { + Node node; + int hd; // Horizontal Distance + + QueueObj(Node node, int hd) { + this.node = node; + this.hd = hd; + } + } + + Queue q = new LinkedList<>(); + Map topViewMap = new TreeMap<>(); + + q.add(new + + QueueObj(root, 0)); + + while(!q.isEmpty()) + + { + QueueObj tmpNode = q.poll(); + if (!topViewMap.containsKey(tmpNode.hd)) { + topViewMap.put(tmpNode.hd, tmpNode.node); + } + + if (tmpNode.node.left != null) { + q.add(new QueueObj(tmpNode.node.left, tmpNode.hd - 1)); + } + if (tmpNode.node.right != null) { + q.add(new QueueObj(tmpNode.node.right, tmpNode.hd + 1)); + } + } System.out.println("Top View:"); - for (Map.Entry entry : topViewMap.entrySet()) { - System.out.print(entry.getValue().data + " "); - } - System.out.println(); - } - - /** - * Computes and prints the bottom view of the binary tree. - * The bottom view consists of the nodes that are visible from the bottom. - */ - public void bottomView() { - if (root == null) { - return; - } - - class QueueObj { - Node node; - int hd; // Horizontal Distance + for( + Map.Entry entry :topViewMap.entrySet()) - QueueObj(Node node, int hd) { - this.node = node; - this.hd = hd; - } - } - - Queue q = new LinkedList<>(); - Map bottomViewMap = new TreeMap<>(); - - q.add(new QueueObj(root, 0)); - - while (!q.isEmpty()) { - QueueObj tmpNode = q.poll(); - bottomViewMap.put(tmpNode.hd, tmpNode.node); - - if (tmpNode.node.left != null) { - q.add(new QueueObj(tmpNode.node.left, tmpNode.hd - 1)); - } - if (tmpNode.node.right != null) { - q.add(new QueueObj(tmpNode.node.right, tmpNode.hd + 1)); - } - } - System.out.println("Bottom View:"); - for (Map.Entry entry : bottomViewMap.entrySet()) { - System.out.print(entry.getValue().data + " "); - } + { + System.out.print(entry.getValue().data + " "); + } System.out.println(); - } - - /** - * Computes and prints the left view of the binary tree. - * The left view consists of the first node at each level. - */ - public void leftView() { - if (root == null) { - return; - } - Queue queue = new LinkedList<>(); - queue.add(root); - System.out.println("Left View:"); - while (!queue.isEmpty()) { - int n = queue.size(); - for (int i = 1; i <= n; i++) { - Node temp = queue.poll(); - if (i == 1) { - System.out.print(temp.data + " "); } - if (temp.left != null) { - queue.add(temp.left); - } - if (temp.right != null) { - queue.add(temp.right); - } - } - } - System.out.println(); - } - /** - * Computes and prints the right view of the binary tree. - * The right view consists of the last node at each level. - */ - public void rightView() { - if (root == null) { - return; - } - Queue queue = new LinkedList<>(); - queue.add(root); - System.out.println("Right View:"); - while (!queue.isEmpty()) { - int n = queue.size(); - for (int i = 1; i <= n; i++) { - Node temp = queue.poll(); - if (i == n) { - System.out.print(temp.data + " "); + /** + * Computes and prints the bottom view of the binary tree. + * The bottom view consists of the nodes that are visible from the bottom. + */ + public void bottomView() { + if (root == null) { + return; + } + + class QueueObj { + Node node; + int hd; // Horizontal Distance + + QueueObj(Node node, int hd) { + this.node = node; + this.hd = hd; + } + } + + Queue q = new LinkedList<>(); + Map bottomViewMap = new TreeMap<>(); + + q.add(new QueueObj(root, 0)); + + while (!q.isEmpty()) { + QueueObj tmpNode = q.poll(); + bottomViewMap.put(tmpNode.hd, tmpNode.node); + + if (tmpNode.node.left != null) { + q.add(new QueueObj(tmpNode.node.left, tmpNode.hd - 1)); + } + if (tmpNode.node.right != null) { + q.add(new QueueObj(tmpNode.node.right, tmpNode.hd + 1)); + } + } + System.out.println("Bottom View:"); + for (Map.Entry entry : bottomViewMap.entrySet()) { + System.out.print(entry.getValue().data + " "); + } + System.out.println(); } - if (temp.left != null) { - queue.add(temp.left); + + /** + * Computes and prints the left view of the binary tree. + * The left view consists of the first node at each level. + */ + public void leftView() { + if (root == null) { + return; + } + Queue queue = new LinkedList<>(); + queue.add(root); + System.out.println("Left View:"); + while (!queue.isEmpty()) { + int n = queue.size(); + for (int i = 1; i <= n; i++) { + Node temp = queue.poll(); + if (i == 1) { + System.out.print(temp.data + " "); + } + if (temp.left != null) { + queue.add(temp.left); + } + if (temp.right != null) { + queue.add(temp.right); + } + } + } + System.out.println(); } - if (temp.right != null) { - queue.add(temp.right); + + /** + * Computes and prints the right view of the binary tree. + * The right view consists of the last node at each level. + */ + public void rightView() { + if (root == null) { + return; + } + Queue queue = new LinkedList<>(); + queue.add(root); + System.out.println("Right View:"); + while (!queue.isEmpty()) { + int n = queue.size(); + for (int i = 1; i <= n; i++) { + Node temp = queue.poll(); + if (i == n) { + System.out.print(temp.data + " "); + } + if (temp.left != null) { + queue.add(temp.left); + } + if (temp.right != null) { + queue.add(temp.right); + } + } + } + System.out.println(); + } } } - System.out.println(); - } -} +} \ No newline at end of file diff --git a/java/BinaryTreeDemo.java b/java/BinaryTreeDemo.java new file mode 100644 index 00000000..62f9f0e9 --- /dev/null +++ b/java/BinaryTreeDemo.java @@ -0,0 +1,161 @@ +import java.util.*; + +// Node class +class Node { + int data; + Node left, right; + + Node(int value) { + data = value; + left = right = null; + } + + Node(int i) { + throw new UnsupportedOperationException("Not supported yet."); + } + + Node(int i) { + throw new UnsupportedOperationException("Not supported yet."); + } +} + +class BinaryTreeViews { + Node root; + + BinaryTreeViews() { + root = null; + } + + // Preorder + void preorder(Node node) { + if (node == null) return; + System.out.print(node.data + " "); + preorder(node.left); + preorder(node.right); + } + + // Inorder + void inorder(Node node) { + if (node == null) return; + inorder(node.left); + System.out.print(node.data + " "); + inorder(node.right); + } + + // Postorder + void postorder(Node node) { + if (node == null) return; + postorder(node.left); + postorder(node.right); + System.out.print(node.data + " "); + } + + // Level-order + void levelOrder() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + Node temp = q.poll(); + System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + + // Left View + void leftView() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + int n = q.size(); + for (int i = 1; i <= n; i++) { + Node temp = q.poll(); + if (i == 1) System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + } + + // Right View + void rightView() { + if (root == null) return; + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + int n = q.size(); + for (int i = 1; i <= n; i++) { + Node temp = q.poll(); + if (i == n) System.out.print(temp.data + " "); + if (temp.left != null) q.add(temp.left); + if (temp.right != null) q.add(temp.right); + } + } + } + + // Top View + void topView() { + if (root == null) return; + class Pair { + Node node; + int hd; + Pair(Node n, int h) { node = n; hd = h; } + } + Queue q = new LinkedList<>(); + Map map = new TreeMap<>(); + q.add(new Pair(root, 0)); + while (!q.isEmpty()) { + Pair p = q.poll(); + if (!map.containsKey(p.hd)) map.put(p.hd, p.node.data); + if (p.node.left != null) q.add(new Pair(p.node.left, p.hd - 1)); + if (p.node.right != null) q.add(new Pair(p.node.right, p.hd + 1)); + } + for (int val : map.values()) System.out.print(val + " "); + } + + // Bottom View + void bottomView() { + if (root == null) return; + class Pair { + Node node; + int hd; + Pair(Node n, int h) { node = n; hd = h; } + } + Queue q = new LinkedList<>(); + Map map = new TreeMap<>(); + q.add(new Pair(root, 0)); + while (!q.isEmpty()) { + Pair p = q.poll(); + map.put(p.hd, p.node.data); + if (p.node.left != null) q.add(new Pair(p.node.left, p.hd - 1)); + if (p.node.right != null) q.add(new Pair(p.node.right, p.hd + 1)); + } + for (int val : map.values()) System.out.print(val + " "); + } +} + +// Demo +public class BinaryTreeDemo { + public static void main(String[] args) { + BinaryTreeViews bt = new BinaryTreeViews(); + bt.root = new Node(1); + bt.root.left = new Node(2); + bt.root.right = new Node(3); + bt.root.left.left = new Node(4); + bt.root.left.right = new Node(5); + bt.root.right.right = new Node(6); + bt.root.right.left = new Node(7); + + System.out.println("Binary Tree Views:"); + System.out.print("Preorder: "); bt.preorder(bt.root); System.out.println(); + System.out.print("Inorder: "); bt.inorder(bt.root); System.out.println(); + System.out.print("Postorder: "); bt.postorder(bt.root); System.out.println(); + System.out.print("Level-order: "); bt.levelOrder(); System.out.println(); + System.out.print("Left View: "); bt.leftView(); System.out.println(); + System.out.print("Right View: "); bt.rightView(); System.out.println(); + System.out.print("Top View: "); bt.topView(); System.out.println(); + System.out.print("Bottom View: "); bt.bottomView(); System.out.println(); + } +} diff --git a/java/BinaryTreeLevelOrderTraversal.java b/java/BinaryTreeLevelOrderTraversal.java new file mode 100644 index 00000000..007b7905 --- /dev/null +++ b/java/BinaryTreeLevelOrderTraversal.java @@ -0,0 +1,70 @@ +// LeetCode 102. Binary Tree Level Order Traversal + +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; +import java.util.Queue; + +public class BinaryTreeLevelOrderTraversal { + + public class TreeNode { + int val; + TreeNode left; + TreeNode right; + TreeNode() {} + TreeNode(int val) { this.val = val; } + TreeNode(int val, TreeNode left, TreeNode right) { + this.val = val; + this.left = left; + this.right = right; + } + + } + + public List> levelOrder(TreeNode root) { + List> res=new ArrayList<>(); + if(root==null) return res; + + Queue q=new LinkedList<>(); + q.add(root); + TreeNode temp=null; + + while(!q.isEmpty()){ + int levelSize=q.size(); + List inlist=new ArrayList<>(); + + for(int i=0;i= a.length){ + return 0; + } + // Return cached result if already computed + if(dp[i][buy] != -1){ + return dp[i][buy]; + } + int profit = 0; + if(buy == 1){ + // Option 1: Buy at current day, move to next day with buy=0 (must sell next) + // Option 2: Skip buying, move to next day with buy=1 (still can buy) + profit = Math.max(f(i+1,0,a,dp)-a[i], f(i+1,1,a,dp)); + } + else{ + // Option 1: Sell at current day, move to day after next (cooldown), can buy again + // Option 2: Skip selling, move to next day with buy=0 (still holding) + profit = Math.max(f(i+2, 1, a, dp) + a[i], f(i+1,0,a,dp)); + } + // Store result in dp table and return + return dp[i][buy] = profit; + } + + /** + * Calculates the maximum profit with cooldown after selling. + * @param a Prices array + * @return Maximum profit + */ + public int maxProfit(int[] a) { + int n = a.length; + // dp[i][buy]: Max profit at day i, buy/sell state + int[][] dp = new int[n+1][3]; + + // Initialize dp table with -1 (uncomputed) + for(int[] r: dp) { + Arrays.fill(r,-1); + } + + // Start from day 0, can buy + return f(0,1,a,dp); + } +} diff --git a/java/BuyAndSellStock2Onwards/BestTimeToBuyAndSellStockWithTransactionFee.java b/java/BuyAndSellStock2Onwards/BestTimeToBuyAndSellStockWithTransactionFee.java new file mode 100644 index 00000000..0dc7c87e --- /dev/null +++ b/java/BuyAndSellStock2Onwards/BestTimeToBuyAndSellStockWithTransactionFee.java @@ -0,0 +1,86 @@ +package BuyAndSellStock2Onwards; + +// You are given an array prices where prices[i] is the price of a given stock on the ith day, and an integer fee representing a transaction fee. +// Find the maximum profit you can achieve. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. +// +// Note: +// You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). +// The transaction fee is only charged once for each stock purchase and sale. +// +// Example 1: +// Input: prices = [1,3,2,8,4,9], fee = 2 +// Output: 8 +// Explanation: The maximum profit can be achieved by: +// - Buying at prices[0] = 1 +// - Selling at prices[3] = 8 +// - Buying at prices[4] = 4 +// - Selling at prices[5] = 9 +// The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8. +// +// Example 2: +// Input: prices = [1,3,7,5,10,3], fee = 3 +// Output: 6 + +import java.util.Arrays; + +public class BestTimeToBuyAndSellStockWithTransactionFee { + public static void main(String[] args) { + BestTimeToBuyAndSellStockWithTransactionFee bss = new BestTimeToBuyAndSellStockWithTransactionFee(); + int[] a = {1,3,2,8,4,9}; + int fee = 2; + System.out.println(bss.maxProfit(a,fee)); + } + + /** + * Recursive helper function to calculate max profit with transaction fee. + * @param i Current day index + * @param buy 1 if we can buy, 0 if we must sell + * @param fee Transaction fee per transaction + * @param a Prices array + * @param dp Memoization table + * @return Maximum profit from day i with given state + */ + private int f(int i, int buy, int fee, int[] a, int[][] dp) { + // Base case: If we've reached the end, no more profit can be made + if(i>=a.length){ + return 0; + } + // Return cached result if already computed + if(dp[i][buy] != -1){ + return dp[i][buy]; + } + + int profit = 0; + if(buy == 1) { + // Option 1: Buy at current day, move to next day with buy=0 (must sell next) + // Option 2: Skip buying, move to next day with buy=1 (still can buy) + profit = Math.max(f(i+1,0,fee,a,dp)-a[i] , f(i+1,1,fee,a,dp)); + } + else { + // Option 1: Sell at current day, pay fee, move to next day with buy=1 (can buy again) + // Option 2: Skip selling, move to next day with buy=0 (still holding) + profit = Math.max(f(i+1,1,fee,a,dp)+a[i]-fee , f(i+1,0,fee,a,dp)); + } + // Store result in dp table and return + return dp[i][buy] = profit; + } + + /** + * Calculates the maximum profit with unlimited transactions and a transaction fee. + * @param a Prices array + * @param fee Transaction fee per transaction + * @return Maximum profit + */ + public int maxProfit(int[] a, int fee) { + int n = a.length; + // dp[i][buy]: Max profit at day i, buy/sell state + int[][] dp = new int[n+1][3]; + // Initialize dp table with -1 (uncomputed) + for(int[] r : dp){ + Arrays.fill(r,-1); + } + // Start from day 0, can buy + return f(0,1,fee,a,dp); + } +} + diff --git a/java/BuyAndSellStock2Onwards/BuyAndSellStock2.java b/java/BuyAndSellStock2Onwards/BuyAndSellStock2.java new file mode 100644 index 00000000..fa546666 --- /dev/null +++ b/java/BuyAndSellStock2Onwards/BuyAndSellStock2.java @@ -0,0 +1,77 @@ +package BuyAndSellStock2Onwards; + +// You are given an integer array prices where prices[i] is the price of a given stock on the ith day. +// +// On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. +// However, you can sell and buy the stock multiple times on the same day, ensuring you never hold more than one share of the stock. +// +// Find and return the maximum profit you can achieve. +// +// Example 1: +// Input: prices = [7,1,5,3,6,4] +// Output: 7 +// Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. +// Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. +// Total profit is 4 + 3 = 7. + +import java.util.Arrays; + +class BuyAndSellStock2 { + public static void main(String[] args) { + BuyAndSellStock2 bss = new BuyAndSellStock2(); + int[] a = {7,1,5,3,6,4}; + System.out.println(bss.maxProfit(a)); // Example usage + } + + /** + * Recursive helper function to calculate max profit. + * @param i Current day index + * @param buy 1 if we can sell (currently holding), 0 if we can buy (not holding) + * @param a Prices array + * @param dp Memoization table + * @return Maximum profit from day i with given state + */ + private int f(int i, int buy, int[] a, int[][] dp) { + // Base case: If we've reached the end, no more profit can be made + if(i == a.length){ + return 0; + } + // Return cached result if already computed + if(dp[i][buy] != -1){ + return dp[i][buy]; + } + + int profit = 0; + if(buy == 1) { + // Option 1: Sell at current day, move to next day with buy=0 (can buy again) + // Option 2: Skip selling, move to next day with buy=1 (still holding) + profit = Math.max(f(i+1,0,a,dp)+a[i], f(i+1,1,a,dp)); + } + else{ + // Option 1: Buy at current day, move to next day with buy=1 (must sell next) + // Option 2: Skip buying, move to next day with buy=0 (still not holding) + profit = Math.max(f(i+1,1,a,dp)-a[i], f(i+1,0,a,dp)); + } + // Store result in dp table and return + return dp[i][buy] = profit; + } + + /** + * Calculates the maximum profit with unlimited transactions. + * @param a Prices array + * @return Maximum profit + */ + public int maxProfit(int[] a) { + int n = a.length; + // dp[i][buy]: Max profit at day i, buy/sell state + int[][] dp = new int[n][3]; + + // Initialize dp table with -1 (uncomputed) + for(int[] r:dp){ + Arrays.fill(r,-1); + } + + // Start from day 0, not holding any stock (can buy) + return f(0,0,a,dp); + } +} diff --git a/java/BuyAndSellStock2Onwards/BuyAndSellStock3.java b/java/BuyAndSellStock2Onwards/BuyAndSellStock3.java new file mode 100644 index 00000000..fc31fdc2 --- /dev/null +++ b/java/BuyAndSellStock2Onwards/BuyAndSellStock3.java @@ -0,0 +1,71 @@ +package BuyAndSellStock2Onwards; + +// You are given an array prices where prices[i] is the price of a given stock on the ith day. +// Find the maximum profit you can achieve. You may complete at most two transactions. +// Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). + +import java.util.Arrays; + +public class BuyAndSellStock3 { + public static void main(String[] args) { + BuyAndSellStock3 bss = new BuyAndSellStock3(); + int[] a = {3,3,5,0,0,3,1,4}; + System.out.println(bss.maxProfit(a)); // Example usage + } + + /** + * Recursive helper function to calculate max profit. + * @param i Current day index + * @param buy 1 if we can buy, 0 if we must sell + * @param t Number of completed transactions + * @param a Prices array + * @param dp Memoization table + * @return Maximum profit from day i with given state + */ + private int f(int i, int buy, int t, int[] a, int[][][] dp) { + // Base case: If we've reached the end or completed 2 transactions, no more profit can be made + if(i >= a.length || t >= 2){ + return 0; + } + // Return cached result if already computed + if(dp[i][buy][t] != -1){ + return dp[i][buy][t]; + } + + int profit = 0; + if(buy == 1) { + // Option 1: Buy at current day, move to next day with buy=0 (must sell next) + // Option 2: Skip buying, move to next day with buy=1 + profit = Math.max(f(i+1,0,t,a,dp)-a[i], f(i+1,1,t,a,dp)); + } + else{ + // Option 1: Sell at current day, increment transaction count, move to next day with buy=1 + // Option 2: Skip selling, move to next day with buy=0 + profit = Math.max(f(i+1,1,t+1,a,dp)+a[i], f(i+1,0,t,a,dp)); + } + // Store result in dp table and return + return dp[i][buy][t] = profit; + } + + /** + * Calculates the maximum profit with at most two transactions. + * @param a Prices array + * @return Maximum profit + */ + public int maxProfit(int[] a) { + int n = a.length; + // dp[i][buy][t]: Max profit at day i, buy/sell state, t transactions done + int[][][] dp = new int[n][3][3]; + + // Initialize dp table with -1 (uncomputed) + for(int[][] r:dp){ + for(int[] rr:r){ + Arrays.fill(rr,-1); + } + } + + // Start from day 0, can buy, 0 transactions done + return f(0,1,0,a,dp); + } +} + diff --git a/java/BuyAndSellStock2Onwards/BuyAndSellStock4.java b/java/BuyAndSellStock2Onwards/BuyAndSellStock4.java new file mode 100644 index 00000000..34da55b8 --- /dev/null +++ b/java/BuyAndSellStock2Onwards/BuyAndSellStock4.java @@ -0,0 +1,72 @@ +package BuyAndSellStock2Onwards; + +// You are given an integer array prices where prices[i] is the price of a given stock on the ith day, and an integer k. +// Find the maximum profit you can achieve. You may complete at most k transactions: i.e. you may buy at most k times and sell at most k times. +// Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again). + +import java.util.Arrays; + +public class BuyAndSellStock4 { + public static void main(String[] args) { + BuyAndSellStock4 bss = new BuyAndSellStock4(); + int[] a = {2,4,1}; + int k = 2; + System.out.println(bss.maxProfit(k, a)); // Example usage + } + + /** + * Recursive helper function to calculate max profit. + * @param i Current day index + * @param buy 1 if we can buy, 0 if we must sell + * @param t Number of transactions remaining + * @param a Prices array + * @param dp Memoization table + * @return Maximum profit from day i with given state + */ + private int f(int i, int buy, int t, int[] a, int[][][] dp) { + // Base case: If we've reached the end or have no transactions left, no more profit can be made + if(i == a.length || t == 0){ + return 0; + } + // Return cached result if already computed + if(dp[i][buy][t] != -1){ + return dp[i][buy][t]; + } + + int profit = 0; + if(buy == 1) { + // Option 1: Buy at current day, move to next day with buy=0 (must sell next) + // Option 2: Skip buying, move to next day with buy=1 + profit = Math.max(f(i+1,0,t,a,dp)-a[i], f(i+1,1,t,a,dp)); + } + else { + // Option 1: Sell at current day, decrement transaction count, move to next day with buy=1 + // Option 2: Skip selling, move to next day with buy=0 + profit = Math.max(f(i+1,1,t-1,a,dp)+a[i], f(i+1,0,t,a,dp)); + } + // Store result in dp table and return + return dp[i][buy][t] = profit; + } + + /** + * Calculates the maximum profit with at most k transactions. + * @param k Maximum number of transactions allowed + * @param a Prices array + * @return Maximum profit + */ + public int maxProfit(int k, int[] a) { + int n = a.length; + // dp[i][buy][t]: Max profit at day i, buy/sell state, t transactions remaining + int[][][] dp = new int[n+1][3][k+1]; + + // Initialize dp table with -1 (uncomputed) + for(int[][] r:dp){ + for(int[] rr: r){ + Arrays.fill(rr,-1); + } + } + + // Start from day 0, can buy, k transactions remaining + return f(0,1,k,a,dp); + } +} diff --git a/java/BuyAndSellStock2Onwards/QuestionLinks b/java/BuyAndSellStock2Onwards/QuestionLinks new file mode 100644 index 00000000..be963a4c --- /dev/null +++ b/java/BuyAndSellStock2Onwards/QuestionLinks @@ -0,0 +1,11 @@ +714. Best Time to Buy and Sell Stock with Transaction Fee :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/description/ + +309. Best Time to Buy and Sell Stock with Cooldown :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/ + +188. Best Time to Buy and Sell Stock IV :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/ + +123. Best Time to Buy and Sell Stock III :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/ + +122. Best Time to Buy and Sell Stock II :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + + diff --git a/java/Chatbot.class b/java/Chatbot.class new file mode 100644 index 00000000..3185eaf8 Binary files /dev/null and b/java/Chatbot.class differ diff --git a/java/Chatbot.java b/java/Chatbot.java new file mode 100644 index 00000000..6482f91e --- /dev/null +++ b/java/Chatbot.java @@ -0,0 +1,51 @@ +import java.util.HashMap; +import java.util.Scanner; +import java.util.Set; + +public class Chatbot { + + private static final HashMap Siri = new HashMap<>(); + static { + Siri.put("good evening", "good evening , Hope all is well!!"); + Siri.put("hello", "Hello! I am a simple rule-based bot. How can I help you today?"); + Siri.put("hi", "Hello there! Ask me about our operating hours or services."); + Siri.put("hours", "Our operating hours are Monday to Friday, 9:00 AM to 5:00 PM."); + Siri.put("service", "We offer customer support, technical assistance, and product demos."); + Siri.put("bye", "Goodbye! Have a great day."); + Siri.put("thank", "You're welcome! Feel free to ask anything else."); + } + + private static String preprocessInput(String In) { + return In.toLowerCase().trim(); + } + + private static String getResponse(String Cli) { + Set key = Siri.keySet(); + for (String keys : key) { + if (Cli.contains(keys)) { + return Siri.get(keys); + } + } + return "I'm sorry, I don't understand that. Could you please rephrase your question?"; + } + + public static void main(String[] args) { + System.out.println("Siri Initialized"); + Scanner sc = new Scanner(System.in); + String UsI; + while (true) { + System.out.print("You : "); + UsI = sc.nextLine(); + if (UsI.equalsIgnoreCase("bye")) { + String farewell = getResponse(preprocessInput(UsI)); + System.out.println("Bot: " + farewell); + break; + } + String cleanedInput = preprocessInput(UsI); + String botResponse = getResponse(cleanedInput); + System.out.println("Bot: " + botResponse); + } + sc.close(); + System.out.println("Siri session ended."); + } +} diff --git a/java/CircularArrayjava.java b/java/CircularArrayjava.java new file mode 100644 index 00000000..0360adf7 --- /dev/null +++ b/java/CircularArrayjava.java @@ -0,0 +1,31 @@ +import java.util.Scanner; + +public class CircularArray { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Read array size + int n = sc.nextInt(); + + // Validate array size + if (n <= 1 || n >= 11) { + System.out.println("Invalid Array Size"); + return; + } + + int[] arr = new int[n]; + + // Read array elements + for (int i = 0; i < n; i++) { + arr[i] = sc.nextInt(); + } + + // Print all circular rotations + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + System.out.print(arr[(i + j) % n] + " "); + } + System.out.println(); + } + } +} diff --git a/java/Circular_array.java b/java/Circular_array.java new file mode 100644 index 00000000..64b226fe --- /dev/null +++ b/java/Circular_array.java @@ -0,0 +1,31 @@ + +import java.util.Scanner; + +class CircularArray { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + int n = sc.nextInt(); + + // Constraint check + if (n <= 1 || n >= 11) { + System.out.println("Invalid Array Size"); + return; + } + + int[] arr = new int[n]; + for (int i = 0; i < n; i++) { + arr[i] = sc.nextInt(); + } + + // Print all circular rotations + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + System.out.print(arr[(i + j) % n] + " "); + } + System.out.println(); + } + + sc.close(); + } +} diff --git a/java/Climbing Stairs.java b/java/ClimbingStairs.java similarity index 96% rename from java/Climbing Stairs.java rename to java/ClimbingStairs.java index 9500e11d..b26ebfec 100644 --- a/java/Climbing Stairs.java +++ b/java/ClimbingStairs.java @@ -1,17 +1,17 @@ -public class ClimbingStairs { - public int climbStairs(int n) { - if (n <= 2) return n; - int first = 1, second = 2; - for (int i = 3; i <= n; i++) { - int temp = first + second; - first = second; - second = temp; - } - return second; - } - - public static void main(String[] args) { - ClimbingStairs obj = new ClimbingStairs(); - System.out.println(obj.climbStairs(5)); // 8 - } -} +public class ClimbingStairs { + public int climbStairs(int n) { + if (n <= 2) return n; + int first = 1, second = 2; + for (int i = 3; i <= n; i++) { + int temp = first + second; + first = second; + second = temp; + } + return second; + } + + public static void main(String[] args) { + ClimbingStairs obj = new ClimbingStairs(); + System.out.println(obj.climbStairs(5)); // 8 + } +} diff --git a/java/Container With Most Water.java b/java/ContainerWithMostWater.java similarity index 96% rename from java/Container With Most Water.java rename to java/ContainerWithMostWater.java index 3f206727..af6ae484 100644 --- a/java/Container With Most Water.java +++ b/java/ContainerWithMostWater.java @@ -1,24 +1,24 @@ -public class ContainerWithMostWater { - public int maxArea(int[] height) { - int left = 0, right = height.length - 1; - int maxArea = 0; - - while (left < right) { - int area = Math.min(height[left], height[right]) * (right - left); - maxArea = Math.max(maxArea, area); - - if (height[left] < height[right]) { - left++; - } else { - right--; - } - } - - return maxArea; - } - - public static void main(String[] args) { - ContainerWithMostWater obj = new ContainerWithMostWater(); - System.out.println(obj.maxArea(new int[]{1,8,6,2,5,4,8,3,7})); // 49 - } -} +public class ContainerWithMostWater { + public int maxArea(int[] height) { + int left = 0, right = height.length - 1; + int maxArea = 0; + + while (left < right) { + int area = Math.min(height[left], height[right]) * (right - left); + maxArea = Math.max(maxArea, area); + + if (height[left] < height[right]) { + left++; + } else { + right--; + } + } + + return maxArea; + } + + public static void main(String[] args) { + ContainerWithMostWater obj = new ContainerWithMostWater(); + System.out.println(obj.maxArea(new int[]{1,8,6,2,5,4,8,3,7})); // 49 + } +} diff --git a/java/CountSubArrays2962.java b/java/CountSubArrays2962.java new file mode 100644 index 00000000..61a5b426 --- /dev/null +++ b/java/CountSubArrays2962.java @@ -0,0 +1,45 @@ +import java.util.*; + +class Solution { + public long countSubarrays(int[] nums, int k) { + long maxNum = Long.MIN_VALUE, count = 0; + long left = 0, right = 0, ans = 0; + for (int num : nums) { + maxNum = Math.max(maxNum, num); + } + while (right < nums.length || left > right) { + if (nums[(int)right] == maxNum) { + count++; + } + while (count >= k) { + if (nums[(int)left] == maxNum) { + count--; + } + left++; + ans += nums.length - right; + } + right++; + } + return ans; + } + public static void main(String args[]) { + Solution find = new Solution(); + Scanner sc = new Scanner(System.in); + + //enter array length + int n = sc.nextInt(); + + //array created + int nums[] = new int[n]; + + //taking inputs + for(int i = 0; i < n; i++) { + nums[i] = sc.nextInt(); + } + //taking k elemnt(k times condition) + int k = sc.nextInt(); + + //output on screen + System.out.println(find.countSubarrays(nums, k)); + } +} \ No newline at end of file diff --git a/java/CountVowels.java b/java/CountVowels.java new file mode 100644 index 00000000..8249d847 --- /dev/null +++ b/java/CountVowels.java @@ -0,0 +1,17 @@ +import java.util.Scanner; + +public class CountVowels { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter a string: "); + String str = sc.nextLine().toLowerCase(); + + int count = 0; + for (char ch : str.toCharArray()) { + if ("aeiou".indexOf(ch) != -1) + count++; + } + + System.out.println("Number of vowels: " + count); + } +} diff --git a/java/CurrentAccount.class b/java/CurrentAccount.class new file mode 100644 index 00000000..24274e70 Binary files /dev/null and b/java/CurrentAccount.class differ diff --git a/java/Customer.class b/java/Customer.class new file mode 100644 index 00000000..0b6d8ec8 Binary files /dev/null and b/java/Customer.class differ diff --git a/java/DP(Lavi)/01Knapsack.java b/java/DP(Lavi)/01Knapsack.java new file mode 100644 index 00000000..db3dfcdc --- /dev/null +++ b/java/DP(Lavi)/01Knapsack.java @@ -0,0 +1,68 @@ +import java.util.Scanner; + +/** + * Demonstrates the 0/1 Knapsack problem using dynamic programming. + */ +public final class KnapsackSolver { + + private KnapsackSolver() { + // Private constructor to prevent instantiation. + } + + /** + * Solves the 0/1 Knapsack problem. + * + * @param weights an array of item weights + * @param values an array of item values + * @param capacity the maximum weight capacity of the knapsack + * @return the maximum value achievable + */ + public static int knapsack(int[] weights, int[] values, int capacity) { + int n = weights.length; + int[][] dp = new int[n + 1][capacity + 1]; + + // Build the DP table + for (int i = 1; i <= n; i++) { + for (int w = 0; w <= capacity; w++) { + if (weights[i - 1] <= w) { + dp[i][w] = Math.max(values[i - 1] + dp[i - 1][w - weights[i - 1]], dp[i - 1][w]); + } else { + dp[i][w] = dp[i - 1][w]; + } + } + } + + return dp[n][capacity]; + } + + /** + * Main method to read input and execute the knapsack solver. + * + * Input format: + * First line: number of items n + * Second line: weights of n items + * Third line: values of n items + * Fourth line: capacity of the knapsack + */ + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + int n = scanner.nextInt(); + int[] weights = new int[n]; + int[] values = new int[n]; + + for (int i = 0; i < n; i++) { + weights[i] = scanner.nextInt(); + } + for (int i = 0; i < n; i++) { + values[i] = scanner.nextInt(); + } + + int capacity = scanner.nextInt(); + + int maxValue = knapsack(weights, values, capacity); + System.out.println(maxValue); + + scanner.close(); + } +} diff --git a/java/DecodetheMessage.java b/java/DecodetheMessage.java new file mode 100644 index 00000000..150f6eeb --- /dev/null +++ b/java/DecodetheMessage.java @@ -0,0 +1,56 @@ +// LeetCode 2325. Decode the Message +import java.util.HashMap; + +public class DecodetheMessage { + public String decodeMessage(String key, String message) { + String Cleankey=key.replaceAll("\\s+",""); + + HashMap map=new HashMap<>(); + StringBuilder sb=new StringBuilder(); + + int alphacount=0; + + // this to maping the letters + for(char c: Cleankey.toCharArray()){ + if(!map.containsKey(c)){ + map.put(c,(char)('a'+ alphacount++)); + } + else if(alphacount==26){ + break; + } + } + + // to assign the values + for(char c :message.toCharArray()){ + if(c == ' '){ + sb.append(c); + } + else{ + sb.append(map.get(c)); + } + } + return sb.toString(); + } +} + +// Example 1: + +// Input: key = "the quick brown fox jumps over the lazy dog", message = "vkbs bs t suepuv" +// Output: "this is a secret" +// Explanation: The diagram above shows the substitution table. +// It is obtained by taking the first appearance of each letter in "the quick brown fox jumps over the lazy dog". + +// Example 2: + +// Input: key = "eljuxhpwnyrdgtqkviszcfmabo", message = "zwx hnfx lqantp mnoeius ycgk vcnjrdb" +// Output: "the five boxing wizards jump quickly" +// Explanation: The diagram above shows the substitution table. +// It is obtained by taking the first appearance of each letter in "eljuxhpwnyrdgtqkviszcfmabo". + +// Constraints: + +// 26 <= key.length <= 2000 +// key consists of lowercase English letters and ' '. +// key contains every letter in the English alphabet ('a' to 'z') at least once. +// 1 <= message.length <= 2000 +// message consists of lowercase English letters and ' '. \ No newline at end of file diff --git a/java/DeleteMiddleNode.java b/java/DeleteMiddleNode.java new file mode 100644 index 00000000..1f6e25b0 --- /dev/null +++ b/java/DeleteMiddleNode.java @@ -0,0 +1,61 @@ +// Definition for singly-linked list +class ListNode { + int val; + ListNode next; + + ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class DeleteMiddleNode { + + // Function to delete the middle node + public static ListNode deleteMiddle(ListNode head) { + if (head == null || head.next == null) { + return null; // if list has 0 or 1 node, result is empty + } + + ListNode slow = head; + ListNode fast = head; + ListNode prev = null; // to keep track of node before slow + + while (fast != null && fast.next != null) { + fast = fast.next.next; + prev = slow; + slow = slow.next; + } + + // delete the middle node + prev.next = slow.next; + return head; + } + + // Helper function to print the linked list + public static void printList(ListNode head) { + ListNode current = head; + while (current != null) { + System.out.print(current.val + " "); + current = current.next; + } + System.out.println(); + } + + public static void main(String[] args) { + // Create a linked list: 1 -> 2 -> 3 -> 4 -> 5 + ListNode head = new ListNode(1); + head.next = new ListNode(2); + head.next.next = new ListNode(3); + head.next.next.next = new ListNode(4); + head.next.next.next.next = new ListNode(5); + + System.out.println("Original list:"); + printList(head); + + head = deleteMiddle(head); + + System.out.println("After deleting middle node:"); + printList(head); + } +} diff --git a/java/DeleteMiddleStack.java b/java/DeleteMiddleStack.java new file mode 100644 index 00000000..aa87f569 --- /dev/null +++ b/java/DeleteMiddleStack.java @@ -0,0 +1,44 @@ +import java.util.*; + +/** + * Delete Middle Element from Stack - Recursive Approach + * Remove middle element without using additional data structure. + */ +public class DeleteMiddleStack { + + // Delete middle element using recursion + public void deleteMiddle(Stack stack) { + int size = stack.size(); + int middle = size / 2; + deleteMiddleHelper(stack, middle); + } + + private void deleteMiddleHelper(Stack stack, int index) { + if (index == 0) { + stack.pop(); // Remove middle element + return; + } + + int temp = stack.pop(); + deleteMiddleHelper(stack, index - 1); + stack.push(temp); + } + + public static void main(String[] args) { + DeleteMiddleStack solution = new DeleteMiddleStack(); + + // Test case 1 + Stack stack1 = new Stack<>(); + stack1.addAll(Arrays.asList(10, 20, 30, 40, 50)); + System.out.println("Original: " + stack1); + solution.deleteMiddle(stack1); + System.out.println("After deletion: " + stack1); // [10, 20, 40, 50] + + // Test case 2 + Stack stack2 = new Stack<>(); + stack2.addAll(Arrays.asList(5, 8, 6, 7, 6, 6, 5, 10, 12, 9)); + System.out.println("\nOriginal: " + stack2); + solution.deleteMiddle(stack2); + System.out.println("After deletion: " + stack2); // [5, 8, 6, 7, 6, 5, 10, 12, 9] + } +} \ No newline at end of file diff --git a/java/DetectCycle.class b/java/DetectCycle.class new file mode 100644 index 00000000..8ec18bcb Binary files /dev/null and b/java/DetectCycle.class differ diff --git a/java/DetectCycle.java b/java/DetectCycle.java new file mode 100644 index 00000000..c02ff4cc --- /dev/null +++ b/java/DetectCycle.java @@ -0,0 +1,44 @@ +// Definition for singly-linked list +class ListNode { + int val; + ListNode next; + + ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class DetectCycle { + + // Function to detect cycle in a linked list + public static boolean hasCycle(ListNode head) { + if (head == null) return false; + + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; // move slow by 1 + fast = fast.next.next; // move fast by 2 + + if (slow == fast) { // cycle detected + return true; + } + } + + return false; // no cycle + } + + public static void main(String[] args) { + // Create a linked list: 1 -> 2 -> 3 -> 4 -> 5 + ListNode head = new ListNode(1); + head.next = new ListNode(2); + head.next.next = new ListNode(3); + head.next.next.next = new ListNode(4); + head.next.next.next.next = new ListNode(5); + + boolean result = hasCycle(head); + System.out.println(result ? "Cycle detected." : "No cycle."); + } +} diff --git a/java/DetectCycleInDirectedGraph.class b/java/DetectCycleInDirectedGraph.class new file mode 100644 index 00000000..3476b752 Binary files /dev/null and b/java/DetectCycleInDirectedGraph.class differ diff --git a/java/DetectCycleInDirectedGraph.java b/java/DetectCycleInDirectedGraph.java new file mode 100644 index 00000000..c40af800 --- /dev/null +++ b/java/DetectCycleInDirectedGraph.java @@ -0,0 +1,59 @@ +import java.util.*; + +public class DetectCycleInDirectedGraph { + private final int vertices; + private final List> adjList; + + DetectCycleInDirectedGraph(int v) { + vertices = v; + adjList = new ArrayList<>(); + for (int i = 0; i < v; i++) + adjList.add(new ArrayList<>()); + } + + void addEdge(int u, int v) { + adjList.get(u).add(v); + } + + boolean isCyclicUtil(int node, boolean[] visited, boolean[] recStack) { + if (recStack[node]) + return true; + if (visited[node]) + return false; + + visited[node] = true; + recStack[node] = true; + + for (Integer neighbor : adjList.get(node)) { + if (isCyclicUtil(neighbor, visited, recStack)) + return true; + } + + recStack[node] = false; + return false; + } + + boolean isCyclic() { + boolean[] visited = new boolean[vertices]; + boolean[] recStack = new boolean[vertices]; + + for (int i = 0; i < vertices; i++) { + if (isCyclicUtil(i, visited, recStack)) + return true; + } + return false; + } + + public static void main(String[] args) { + DetectCycleInDirectedGraph graph = new DetectCycleInDirectedGraph(4); + graph.addEdge(0, 1); + graph.addEdge(1, 2); + graph.addEdge(2, 0); // cycle + graph.addEdge(2, 3); + + if (graph.isCyclic()) + System.out.println("Graph contains a cycle"); + else + System.out.println("Graph does not contain a cycle"); + } +} diff --git a/java/DijkstraAlgorithm$Node.class b/java/DijkstraAlgorithm$Node.class new file mode 100644 index 00000000..ff7fd998 Binary files /dev/null and b/java/DijkstraAlgorithm$Node.class differ diff --git a/java/DijkstraAlgorithm.class b/java/DijkstraAlgorithm.class new file mode 100644 index 00000000..7f648dc4 Binary files /dev/null and b/java/DijkstraAlgorithm.class differ diff --git a/java/DijkstraAlgorithm.java b/java/DijkstraAlgorithm.java new file mode 100644 index 00000000..fa5a749b --- /dev/null +++ b/java/DijkstraAlgorithm.java @@ -0,0 +1,73 @@ +import java.util.*; + +public class DijkstraAlgorithm { + + // A utility class to represent a node in the priority queue + static class Node implements Comparable { + int vertex; + int distance; + + Node(int vertex, int distance) { + this.vertex = vertex; + this.distance = distance; + } + + @Override + public int compareTo(Node other) { + return Integer.compare(this.distance, other.distance); + } + } + + // Function to implement Dijkstra's algorithm + public static void dijkstra(int[][] graph, int source) { + int n = graph.length; + int[] dist = new int[n]; + boolean[] visited = new boolean[n]; + PriorityQueue pq = new PriorityQueue<>(); + + // Initialize distances + Arrays.fill(dist, Integer.MAX_VALUE); + dist[source] = 0; + pq.add(new Node(source, 0)); + + while (!pq.isEmpty()) { + Node current = pq.poll(); + int u = current.vertex; + + if (visited[u]) continue; + visited[u] = true; + + // Update distances of adjacent vertices + for (int v = 0; v < n; v++) { + if (graph[u][v] != 0 && !visited[v]) { + int newDist = dist[u] + graph[u][v]; + if (newDist < dist[v]) { + dist[v] = newDist; + pq.add(new Node(v, newDist)); + } + } + } + } + + // Print the shortest distances + System.out.println("Shortest distances from vertex " + source + ":"); + for (int i = 0; i < n; i++) { + System.out.println("Vertex " + i + " : " + (dist[i] == Integer.MAX_VALUE ? "Infinity" : dist[i])); + } + } + + public static void main(String[] args) { + // Sample graph represented as adjacency matrix + // 0: A, 1: B, 2: C, 3: D, 4: E + int[][] graph = { + {0, 4, 0, 0, 0}, // A to B: 4 + {4, 0, 8, 0, 0}, // B to A: 4, B to C: 8 + {0, 8, 0, 7, 0}, // C to B: 8, C to D: 7 + {0, 0, 7, 0, 9}, // D to C: 7, D to E: 9 + {0, 0, 0, 9, 0} // E to D: 9 + }; + + int source = 0; // Starting from vertex A (0) + dijkstra(graph, source); + } +} diff --git a/java/DisjointSet.java b/java/DisjointSet.java new file mode 100644 index 00000000..9c35d413 --- /dev/null +++ b/java/DisjointSet.java @@ -0,0 +1,74 @@ +/* + Disjoint Set Union (Union-Find) in Java + ---------------------------------------- + Features: + - Path Compression (optimizes find operation) + - Union by Rank (balances tree height) + + Time Complexity: + - find(): O(α(N)) ~ constant + - union(): O(α(N)) ~ constant +*/ + +class DisjointSet { + int[] parent; + int[] rank; + + // Constructor: initialize DSU for 'n' elements + DisjointSet(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + rank[i] = 0; + } + } + + // Find with path compression + int find(int x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); // compress path + } + return parent[x]; + } + + // Union by rank + void union(int x, int y) { + int rootX = find(x); + int rootY = find(y); + + if (rootX == rootY) return; // already in same set + + if (rank[rootX] < rank[rootY]) { + parent[rootX] = rootY; + } else if (rank[rootX] > rank[rootY]) { + parent[rootY] = rootX; + } else { + parent[rootY] = rootX; + rank[rootX]++; + } + } + + // Example usage + public static void main(String[] args) { + DisjointSet dsu = new DisjointSet(5); + + dsu.union(0, 2); + dsu.union(4, 2); + dsu.union(3, 1); + + // Should print "Connected" + if (dsu.find(4) == dsu.find(0)) { + System.out.println("Connected"); + } else { + System.out.println("Not Connected"); + } + + // Should print "Not Connected" + if (dsu.find(1) == dsu.find(0)) { + System.out.println("Connected"); + } else { + System.out.println("Not Connected"); + } + } +} diff --git a/java/DivideAndConquer/MergeSort.class b/java/DivideAndConquer/MergeSort.class new file mode 100644 index 00000000..3608fe25 Binary files /dev/null and b/java/DivideAndConquer/MergeSort.class differ diff --git a/java/DivideAndConquer/MergeSort.java b/java/DivideAndConquer/MergeSort.java new file mode 100644 index 00000000..e962643f --- /dev/null +++ b/java/DivideAndConquer/MergeSort.java @@ -0,0 +1,64 @@ +public class MergeSort{ + public static void main(String args[]){ + int arr[] = {6, 3, 9, 5, 2, 8}; + mergeSort(arr, 0, arr.length-1); + printArr(arr); + } + + public static void printArr(int arr[]){ + for(int i=0; i= ei){ + return; + } + int mid = si+(ei-si)/2; + mergeSort(arr, si, mid); //left part + mergeSort(arr, mid+1, ei); //right part + merge(arr, si, mid, ei); // merge function called after sorting + + } + + public static void merge(int arr[], int si, int mid, int ei){ + + // left(0, 3) = 3-0+1 => 4 (bec we started from 0 idx) + // right(4, 6) = 6-4+1 => 4 + int temp[] = new int[ei-si+1]; + int i = si; // iterator for left part + int j = mid+1; // iterator for right part + int k = 0; // iterator for temp arr + + + while(i <= mid && j <= ei){ + if(arr[i] < arr[j]){ + temp[k] = arr[i]; + i++; + }else{ + temp[k] = arr[j]; + j++; + } + k++; + } + + // for leftover elements (if exists) of left side + while(i <= mid){ + temp[k++] = arr[i++]; + } + + // for leftover elements (if exists) of right + while(j <= ei){ + temp[k++] = arr[j++]; + } + + // copy temp to og array + for(k=0, i=si; k= ei){ + return; + } + + // select a pivot (we take left here) + + // partitioning recursion + int partitionIdx = partition(arr, si, ei); + quickSort(arr, si, partitionIdx-1); // left array + quickSort(arr, partitionIdx+1, ei); // right array + } + + public static int partition(int arr[], int si, int ei){ + + // we select the pivot as last element + int pivot = arr[ei]; + int i = si-1; // makes space for elements smaller than pivot + + for(int j=si; j= arr[j]){ + i++; + // swap i and j + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + + } + } + + // incremented i again for maiking space for pivot + i++; + int temp = pivot; + arr[ei] = arr[i]; + arr[i] = temp; + return i; + } +} \ No newline at end of file diff --git a/java/DivideAndConquer/SortedAndRotatedArray.class b/java/DivideAndConquer/SortedAndRotatedArray.class new file mode 100644 index 00000000..41241c7e Binary files /dev/null and b/java/DivideAndConquer/SortedAndRotatedArray.class differ diff --git a/java/DivideAndConquer/SortedAndRotatedArray.java b/java/DivideAndConquer/SortedAndRotatedArray.java new file mode 100644 index 00000000..fe92d6f1 --- /dev/null +++ b/java/DivideAndConquer/SortedAndRotatedArray.java @@ -0,0 +1,48 @@ +public class SortedAndRotatedArray{ + public static void main(String args[]){ + + int arr[] = {4, 5, 6, 7, 0, 1, 2}; + int target = 0; // output should be idx of target(4) + int targetIdx = search(arr, target, 0, arr.length-1); + System.out.println(targetIdx); + } + + public static int search(int arr[], int target, int si, int ei){ + + // base case + if(si > ei){ + return -1; + } + + // sabse pehle mid nikal lete hai + int mid = si+(ei-si)/2; + + // sabse basic case + if(target == arr[mid]){ + return mid; + } + + // case 2: mid may lie of Line1 + if(arr[si] <= arr[mid]){ + + // case a: + if(target >= arr[si] && target <= arr[mid]){ + return search(arr, target, si, mid-1); + }else{ // case b: + return search(arr, target, mid+1, ei); + } + } + + else{ // arr[mid] <= arr[ei] + + // case a: + if(target >= arr[mid] && target <= arr[ei]){ + return search(arr, target, mid+1, ei); + }else{ // case b: + return search(arr, target, si, mid-1); + } + + } + + } +} \ No newline at end of file diff --git a/java/DivideAndConquer/SortedAndRotatedArray_Iteration.class b/java/DivideAndConquer/SortedAndRotatedArray_Iteration.class new file mode 100644 index 00000000..d677edf8 Binary files /dev/null and b/java/DivideAndConquer/SortedAndRotatedArray_Iteration.class differ diff --git a/java/DivideAndConquer/SortedAndRotatedArray_Iteration.java b/java/DivideAndConquer/SortedAndRotatedArray_Iteration.java new file mode 100644 index 00000000..6b476726 --- /dev/null +++ b/java/DivideAndConquer/SortedAndRotatedArray_Iteration.java @@ -0,0 +1,36 @@ +public class SortedAndRotatedArray_Iteration{ + public static void main(String args[]){ + int arr[] = {4, 5, 6, 7, 0, 1, 2}; + int target = 0; + System.out.println(search(arr, target, 0, arr.length-1)); + + } + + public static int search(int arr[], int target,int si,int ei){ + + while(si<=ei){ + int mid = si+(ei-si)/2; + // case 1: sabse basic case + if(target == arr[mid]){ + return mid; + } + + // case2: if target is less than mid (Lies on Line1) + if(arr[si] <= arr[mid]){ + if(target >= arr[si] && target <= arr[mid]){ + ei = mid-1; + }else{ + si = mid+1; + } + } + else{ // case 3: if(arr[mid] <= arr[ei]) + if(target >= arr[mid] && target <= arr[ei]){ + si = mid+1; + }else{ + ei = mid-1; + } + } + } + return -1; + } +} \ No newline at end of file diff --git a/java/DivideAndConquer/tempCodeRunnerFile.java b/java/DivideAndConquer/tempCodeRunnerFile.java new file mode 100644 index 00000000..2f259b79 --- /dev/null +++ b/java/DivideAndConquer/tempCodeRunnerFile.java @@ -0,0 +1 @@ +s \ No newline at end of file diff --git a/java/EditDistance.java b/java/EditDistance.java new file mode 100644 index 00000000..c30323f5 --- /dev/null +++ b/java/EditDistance.java @@ -0,0 +1,34 @@ +public class EditDistance { + public static void main(String[] args) { + String str1 = "intention"; + String str2 = "execution"; + + int ans = editDistance(str1, str2); + System.out.println("Min operations to convert str1 into str2 is: " + ans); + } + + public static int editDistance(String str1, String str2) { + int n1 = str1.length(); + int n2 = str2.length(); + + int[][] dp = new int[n1+1][n2+1]; + + for(int i=0;i<=n1;i++) dp[i][0] = i; + for(int i=0;i<=n2;i++) dp[0][i] = i; + + for(int i=1;i<=n1;i++) { + for(int j=1;j<=n2;j++) { + int ch1 = str1.charAt(i-1); + int ch2 = str2.charAt(j-1); + + if(ch1 == ch2) + dp[i][j] = dp[i-1][j-1]; + else + dp[i][j] = 1 + Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1])); + + } + } + + return dp[n1][n2]; + } +} diff --git a/java/ExpressionAddOperator.java b/java/ExpressionAddOperator.java new file mode 100644 index 00000000..44f6319a --- /dev/null +++ b/java/ExpressionAddOperator.java @@ -0,0 +1,112 @@ +// Given a string s that contains only digits (0-9) and an integer target, return all possible strings by inserting the binary operator ' + ', ' - ', and/or ' * ' between the digits of s such that the resultant expression evaluates to the target value. + +// Note: + +// Operands in the returned expressions should not contain leading zeros. For example, 2 + 03 is not allowed whereas 20 + 3 is fine. +// It is allowed to not insert any of the operators. +// Driver code will print the final list of strings in lexicographically smallest order. +// Examples: + +// Input: s = "124", target = 9 +// Output: ["1+2*4"] +// Explanation: The valid expression that evaluate to 9 is 1 + 2 * 4 +// Input: s = "125", target = 7 +// Output: ["1*2+5", "12-5"] +// Explanation: The two valid expressions that evaluate to 7 are 1 * 2 + 5 and 12 - 5. +// Input: s = "12", target = 12 +// Output: ["12"] +// Explanation: s itself matches the target. No other expressions are possible. +// Input: s = "987612", target = 200 +// Output: [] +// Explanation: There are no expressions that can be created from "987612" to evaluate to 200. +// Constraints: +// 1 ≤ s.size() ≤ 9 +// s consists of only digits (0-9). +// -231 ≤ target ≤ 231-1 + +/* + * Problem: Generate all possible expressions by inserting +, -, * operators + * between digits of a string such that the expression evaluates + * to a given target value. + * + * Approach: Backtracking / DFS (Depth-First Search) + * + * Key idea: + * - We recursively try all possible placements of operators between digits. + * - Maintain running evaluation (`currVal`), previous operand (`prevOpr`), + * and the current expression string. + * - Use backtracking to explore all combinations. + * + * Time Complexity: O(4^n) (in worst case, for each position we try 3 operators) + * Space Complexity: O(n) (recursion stack depth) + */ + +import java.util.*; + +class Solution { + + /** + * Recursive helper function to explore all possible expressions. + * + * @param s The numeric string input. + * @param target The target value we want to achieve. + * @param idx Current index in the string. + * @param currVal Current evaluated result of the formed expression so far. + * @param prevOpr The last operand used (to handle multiplication precedence). + * @param expression Current expression string being built. + * @param result List to store valid expressions that match the target. + */ + public void solve(String s, int target, int idx, long currVal, long prevOpr, String expression, ArrayList result) { + // Base Case: If we've reached the end of the string + if (idx == s.length()) { + // If the current expression evaluates to the target, add it to the result + if (currVal == target) { + result.add(expression); + } + return; + } + + // Try all possible partitions of the remaining string + for (int i = idx; i < s.length(); i++) { + + // Skip invalid numbers with leading zeros (e.g., "05", "00") + if (i > idx && s.charAt(idx) == '0') { + break; + } + + // Extract current number from substring + long currNum = Long.parseLong(s.substring(idx, i + 1)); + + // Case 1: First number (no operator needed before it) + if (idx == 0) { + // Start the expression with the first number + solve(s, target, i + 1, currNum, currNum, expression + currNum, result); + } else { + // Case 2: Addition + solve(s, target, i + 1, currVal + currNum, currNum, expression + "+" + currNum, result); + + // Case 3: Subtraction + solve(s, target, i + 1, currVal - currNum, -currNum, expression + "-" + currNum, result); + + // Case 4: Multiplication + // To handle operator precedence, adjust current value: + // Remove the effect of previous operand and multiply it with current number. + long newVal = currVal - prevOpr + (prevOpr * currNum); + solve(s, target, i + 1, newVal, prevOpr * currNum, expression + "*" + currNum, result); + } + } + } + + /** + * Public method to initiate the recursive expression generation. + * + * @param s The input string of digits. + * @param target The target value to achieve. + * @return A list of all valid expressions that evaluate to the target. + */ + public ArrayList findExpr(String s, int target) { + ArrayList result = new ArrayList<>(); + solve(s, target, 0, 0, 0, "", result); + return result; + } +} diff --git a/java/FactorialExample.class b/java/FactorialExample.class new file mode 100644 index 00000000..17f1d9fa Binary files /dev/null and b/java/FactorialExample.class differ diff --git a/java/FactorialExample.java b/java/FactorialExample.java new file mode 100644 index 00000000..605d2eb0 --- /dev/null +++ b/java/FactorialExample.java @@ -0,0 +1,21 @@ +import java.util.*; + +public class FactorialExample { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter a non-negative integer: "); + int num = sc.nextInt(); + long factorial = 1; + + if (num < 0) { + System.out.println("Factorial is not defined for negative numbers."); + } else { + for (int i = 1; i <= num; i++) { + factorial *= i; + } + System.out.println("Factorial of " + num + " = " + factorial); + } + + sc.close(); + } +} diff --git a/java/Fibonacci.java b/java/Fibonacci.java new file mode 100644 index 00000000..277a10aa --- /dev/null +++ b/java/Fibonacci.java @@ -0,0 +1,12 @@ +public class Fibonacci { + public static void main(String[] args) { + int n = 10, first = 0, second = 1; + System.out.print("Fibonacci Series: "); + for (int i = 0; i < n; i++) { + System.out.print(first + " "); + int next = first + second; + first = second; + second = next; + } + } +} diff --git a/java/FindMiddleNode.java b/java/FindMiddleNode.java new file mode 100644 index 00000000..7f64c791 --- /dev/null +++ b/java/FindMiddleNode.java @@ -0,0 +1,44 @@ +// Definition for singly-linked list +class ListNode { + int val; + ListNode next; + + ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class FindMiddleNode { + + // Function to find the middle node + public static ListNode findMiddle(ListNode head) { + if (head == null) return null; + + ListNode slow = head; + ListNode fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; // move slow by 1 + fast = fast.next.next; // move fast by 2 + } + + return slow; // slow is now at the middle + } + + public static void main(String[] args) { + // Create a linked list: 1 -> 2 -> 3 -> 4 -> 5 + ListNode head = new ListNode(1); + head.next = new ListNode(2); + head.next.next = new ListNode(3); + head.next.next.next = new ListNode(4); + head.next.next.next.next = new ListNode(5); + + ListNode middle = findMiddle(head); + if (middle != null) { + System.out.println("Middle node value: " + middle.val); + } else { + System.out.println("The list is empty."); + } + } +} diff --git a/java/FloydCycleDetectionLinkedList.java b/java/FloydCycleDetectionLinkedList.java new file mode 100644 index 00000000..12389208 --- /dev/null +++ b/java/FloydCycleDetectionLinkedList.java @@ -0,0 +1,30 @@ +import java.util.*; +public class FloydCycleDetectionLinkedList { + static class Node { + int data; + Node next; + Node(int d) { data = d; next = null; } + } + + public static boolean hasCycle(Node head) { + if (head == null) return false; + Node slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) + return true; + } + return false; + } + + public static void main(String[] args) { + Node head = new Node(1); + head.next = new Node(2); + head.next.next = new Node(3); + head.next.next.next = head.next; + + System.out.println("Contains Cycle? " + hasCycle(head)); + } +} + diff --git a/java/FourSum.java b/java/FourSum.java new file mode 100644 index 00000000..8cb84829 --- /dev/null +++ b/java/FourSum.java @@ -0,0 +1,58 @@ +import java.util.*; + +public class FourSum { + public static List> fourSum(int[] nums, int target) { + List> result = new ArrayList<>(); + if (nums == null || nums.length < 4) return result; + + Arrays.sort(nums); + int n = nums.length; + + for (int i = 0; i < n - 3; i++) { + // Skip duplicates for i + if (i > 0 && nums[i] == nums[i - 1]) continue; + + for (int j = i + 1; j < n - 2; j++) { + + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + int left = j + 1; + int right = n - 1; + + while (left < right) { + long sum = (long) nums[i] + nums[j] + nums[left] + nums[right]; + + if (sum == target) { + result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right])); + + + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + + return result; + } + + public static void main(String[] args) { + int[] nums = {1, 0, -1, 0, -2, 2}; + int target = 0; + + List> result = fourSum(nums, target); + System.out.println("Quadruplets that sum to " + target + ": " + result); + + // Example 2 + int[] nums2 = {2, 2, 2, 2, 2}; + target = 8; + System.out.println("Quadruplets that sum to " + target + ": " + fourSum(nums2, target)); + } +} diff --git a/java/GenerateParentheses.java b/java/GenerateParentheses.java new file mode 100644 index 00000000..d36c0642 --- /dev/null +++ b/java/GenerateParentheses.java @@ -0,0 +1,64 @@ +// LeetCode 22. Generate Parentheses +import java.util.ArrayList; +import java.util.List; + +public class GenerateParentheses { + + public List generateParenthesis(int n) { + List list=new ArrayList<>(); + BackTrack(list,new StringBuilder(),0,0,n); + return list; + } + + static void BackTrack(List l,StringBuilder sb,int open ,int close,int n){ + if(sb.length() == n*2){ + if(isValid(sb)){ + l.add(sb.toString()); + } + return; + } + if(openocnt){ + return false; + } + } + if(ccnt!=ocnt) return false; + + return true; + } +} + +// Given n pairs of parentheses, write a function to generate all combinations of well-formed +// parentheses. + + + +// Example 1: + +// Input: n = 3 +// Output: ["((()))","(()())","(())()","()(())","()()()"] +// Example 2: + +// Input: n = 1 +// Output: ["()"] \ No newline at end of file diff --git a/java/GreedyAlgorithm/ActivitySelection.class b/java/GreedyAlgorithm/ActivitySelection.class new file mode 100644 index 00000000..1ddcdbe3 Binary files /dev/null and b/java/GreedyAlgorithm/ActivitySelection.class differ diff --git a/java/GreedyAlgorithm/ActivitySelection.java b/java/GreedyAlgorithm/ActivitySelection.java new file mode 100644 index 00000000..3673b744 --- /dev/null +++ b/java/GreedyAlgorithm/ActivitySelection.java @@ -0,0 +1,84 @@ +import java.util.*; + +public class ActivitySelection{ + public static void main(String args[]){ + + int start[] = {0, 1, 3, 5, 5, 8}; + int end[] = {6, 2, 4, 7, 9, 9}; + + System.out.println("MaxActivity code when end arr is sorted..."); + SortedEnd(start, end); + System.out.println("MaxActivity code when end arr is not sorted..."); + UnSortedEnd(start, end); + } + + public static void SortedEnd(int start[], int end[]){ + // end time basis sorted arr + + int maxActivity = 0; + ArrayList ans = new ArrayList<>(); + + // 1. always take the first activity (A0) bec it doesnt overlap with any other activity + maxActivity = 1; + ans.add(0); + + // initializing lastEnd with end of first activity + int lastEnd = end[0]; + + // taking a normal array for iteration bec start and end arrays are not ArrayList but arrays + for(int i=1; i= lastEnd){ + maxActivity++; + ans.add(i); + lastEnd = end[i]; + } + } + + System.out.println("max activities... " + maxActivity); + for(int i=0; i shortform of a big function + // in java, Comparator is an interface for sorting java objects + Arrays.sort(activities, Comparator.comparingDouble(o -> o[2])); + + // end time basis sorted + int maxActivity = 0; + ArrayList ans = new ArrayList<>(); + + // 1st activity is already added + maxActivity = 1; + + // adding that activity + ans.add(activities[0][0]); + int lastEnd = activities[0][2]; + for(int i=1; i= lastEnd){ + maxActivity++; + ans.add(activities[i][0]); + lastEnd = activities[i][2]; + } + } + + System.out.println("max activities... " + maxActivity); + for(int i=0; i stores idx + // 1st col -> stores ratio + + for(int i = 0; i o[1])); + + int capacity = maxWeight; + int finalVal = 0; + + // getting the elements in descending order + for(int i=ratio.length-1; i>=0; i--){ + int idx = (int)ratio[i][0]; + if(capacity >= weight[idx]){ + finalVal += val[idx]; + capacity -= weight[idx]; + }else{ + //include fractional item + finalVal += (ratio[i][1] * capacity); + capacity = 0; + break; + } + } + + System.out.println("final value = " + finalVal); + + } +} \ No newline at end of file diff --git a/java/GreedyAlgorithm/IndianCoins.class b/java/GreedyAlgorithm/IndianCoins.class new file mode 100644 index 00000000..b55c53da Binary files /dev/null and b/java/GreedyAlgorithm/IndianCoins.class differ diff --git a/java/GreedyAlgorithm/IndianCoins.java b/java/GreedyAlgorithm/IndianCoins.java new file mode 100644 index 00000000..011c3ce0 --- /dev/null +++ b/java/GreedyAlgorithm/IndianCoins.java @@ -0,0 +1,35 @@ +import java.util.*; + +public class IndianCoins{ + public static void main(String args[]){ + + Integer coins[] = {2000, 500, 100, 50, 20, 10, 5, 2, 1}; + + Arrays.sort(coins, Comparator.reverseOrder()); + + int coinsLength = 0; + int coinsToGive = 590; + ArrayList ans = new ArrayList<>(); + + for(int i=0; i= coins[i]){ + while(coins[i] <= coinsToGive){ + coinsToGive -= coins[i]; + ans.add(coins[i]); + coinsLength++; + } + } + } + + + System.out.println(coinsLength); + + // we can also get which which coins were selected + + System.out.print("The min number of coins to give: "); + for(int i=0; i jobs = new ArrayList<>(); + + // create Job objects + for (int i = 0; i < jobsInfo.length; i++) { + jobs.add(new Job(i, jobsInfo[i][0], jobsInfo[i][1])); + } + + // sort by profit in descending order + Collections.sort(jobs, (obj1, obj2) -> obj2.profit - obj1.profit); + + ArrayList seq = new ArrayList<>(); + int time = 0; + + for (int i = 0; i < jobs.size(); i++) { + Job curr = jobs.get(i); + if (curr.deadline > time) { + seq.add(curr.id); + time++; + } + } + + System.out.println("Max jobs = " + seq.size()); + for (int i = 0; i < seq.size(); i++) { + System.out.print(seq.get(i) + " "); + } + System.out.println(); + } +} diff --git a/java/GreedyAlgorithm/MaxLengthChainOfPairs.class b/java/GreedyAlgorithm/MaxLengthChainOfPairs.class new file mode 100644 index 00000000..28eb8e61 Binary files /dev/null and b/java/GreedyAlgorithm/MaxLengthChainOfPairs.class differ diff --git a/java/GreedyAlgorithm/MaxLengthChainOfPairs.java b/java/GreedyAlgorithm/MaxLengthChainOfPairs.java new file mode 100644 index 00000000..7eff2bb6 --- /dev/null +++ b/java/GreedyAlgorithm/MaxLengthChainOfPairs.java @@ -0,0 +1,33 @@ +import java.util.*; + +// DO THIS QUESTION AGAIN AND STORE ANOTHER COLUMN FOR STORING IDX AS WELL +// TC -> O(nlogn) +public class MaxLengthChainOfPairs{ + public static void main(String args[]){ + + int pairs[][] = { + {5, 24}, + {39, 60}, + {5, 28}, + {27, 40}, + {50, 90} + }; + + Arrays.sort(pairs, Comparator.comparingDouble(o -> o[1])); + + // always select the first chain + int chainLength = 1; + + // also store the last end, it will be used for comparison + int chainEnd = pairs[0][1]; + + for(int i = 1; i seen = new HashSet<>(); + while (n != 1 && !seen.contains(n)) { + seen.add(n); + n = getNext(n); + } + return n == 1; + } + + private static int getNext(int n) { + int totalSum = 0; + while (n > 0) { + int d = n % 10; + n = n / 10; + totalSum += d * d; + } + return totalSum; + } + + public static void main(String[] args) { + System.out.println(isHappy(19)); + System.out.println(isHappy(2)); + } +} diff --git a/java/HashMap/.DS_Store b/java/HashMap/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/java/HashMap/.DS_Store differ diff --git a/java/HashMap/Anagram.java b/java/HashMap/Anagram.java new file mode 100644 index 00000000..cd744d86 --- /dev/null +++ b/java/HashMap/Anagram.java @@ -0,0 +1,61 @@ +import java.util.HashMap; +import java.util.Map; + +public class Anagram { + public static void main(String[] args) { + String s= "aabbbb"; + String t= "aaaabb"; + + Map ss= new HashMap<>(); + Map tt= new HashMap<>(); + + if(s.length() != t.length()) + { + System.out.println("Not Anagram!"); + } + else{ + // hashmap of 1st string + // hashmap of 2nd string + + // mapping of string 1 + for(int i=0; i< s.length(); i++) + { + if(!ss.containsKey(s.charAt(i))) + { + ss.put(s.charAt(i), 1); + } + else{ + ss.put(s.charAt(i), ss.get(s.charAt(i))+1); + } + } + + // mapping of string 2 + for(int i=0; i< t.length(); i++) + { + if(!tt.containsKey(t.charAt(i))) + { + tt.put(t.charAt(i), 1); + } + else{ + tt.put(t.charAt(i), tt.get(t.charAt(i))+1); + } + } + System.out.println(ss); + System.out.println(tt); + + // check if ss and tt are equal? + if(ss.equals(tt)) + { + System.out.println("Yes! given string is Anagram"); + } + else + { + System.out.println("No! given string is not Anagram"); + } + + } + } + + + +} diff --git a/java/HashMap/Frequency.java b/java/HashMap/Frequency.java new file mode 100644 index 00000000..0efdc553 --- /dev/null +++ b/java/HashMap/Frequency.java @@ -0,0 +1,40 @@ +import java.util.HashMap; +import java.util.Map; + +public class Frequency { + public static void main(String[] args) { + Map mp = new HashMap<>(); + + int[] arr={1,3,5,3,4,3,1,4,5,7,8,5,3,2,4,6,7,8,8,6,5,4,3,2,2,5}; + int n= arr.length; + + for (int i : arr) { + if(!mp.containsKey(i)) + { + mp.put(i, 1); + } + else + { + mp.put(i, mp.get(i)+1); + } + + } + System.out.println("Frequency Map"); + System.out.println(mp.entrySet()); + + + // check for max freq + int maxFreq= -1; + int ansKey= -1; + + for (var dic : mp.entrySet()) { + if(dic.getValue() > maxFreq) + { + maxFreq= dic.getValue(); + ansKey= dic.getKey(); + } + } + + System.out.println("Key: "+ ansKey +" \nMax Frequency: "+maxFreq); + } +} diff --git a/java/HashMap/Isomorphic.java b/java/HashMap/Isomorphic.java new file mode 100644 index 00000000..4e88f970 --- /dev/null +++ b/java/HashMap/Isomorphic.java @@ -0,0 +1,39 @@ +import java.util.HashMap; + +public class Isomorphic { + public static void main(String[] args) { + String s= "abcdca"; + String t= "xywswz"; + + HashMap mp= new HashMap<>(); + + if(s.length() != t.length()) + { + System.out.println("Not Isomorphic"); + } + else + { + for(int i=0; i map = new HashMap<>(); + + map.put("A",10); + map.put("B",20); + map.put("C",30); + + System.out.println("Size of map is: "+ map.size()); + System.out.println(map); + + if(map.containsKey("A")) { + Integer A = map.get("A"); + System.out.println("Value for key A is: "+A); + } + + for(String key : map.keySet()) { + System.out.println("Key:"+key+", Value:"+map.get(key)); + } + + //alternative way + for(Entry entry : map.entrySet()) { + System.out.println("Key:"+entry.getKey()+", Value:"+entry.getValue()); + } + } +} diff --git a/java/HashSetDemo.java b/java/HashSetDemo.java new file mode 100644 index 00000000..6bfc3a1f --- /dev/null +++ b/java/HashSetDemo.java @@ -0,0 +1,23 @@ +import java.util.*; + +public class HashSetDemo { + public static void main(String[] args) { + HashSet hashSet = new HashSet(); + + hashSet.add("H"); + hashSet.add("M"); + hashSet.add("P"); + hashSet.add("H"); + + System.out.println(hashSet); + + System.out.println("List contains M or not? " + hashSet.contains("M")); + + hashSet.remove("P"); + System.out.println("Set after removing P: "+hashSet); + + for (String item : hashSet) { + System.out.println(item); + } + } +} diff --git a/java/HeapSort.class b/java/HeapSort.class new file mode 100644 index 00000000..3a5ac4c1 Binary files /dev/null and b/java/HeapSort.class differ diff --git a/java/HeapSort.java b/java/HeapSort.java new file mode 100644 index 00000000..466984f8 --- /dev/null +++ b/java/HeapSort.java @@ -0,0 +1,65 @@ +public class HeapSort { + // Function to heapify a subtree rooted with node i + static void heapify(int arr[], int n, int i) { + int largest = i; // Initialize largest as root + int left = 2 * i + 1; // left child index + int right = 2 * i + 2; // right child index + + // If left child is larger than root + if (left < n && arr[left] > arr[largest]) + largest = left; + + // If right child is larger than largest so far + if (right < n && arr[right] > arr[largest]) + largest = right; + + // If largest is not root + if (largest != i) { + int temp = arr[i]; + arr[i] = arr[largest]; + arr[largest] = temp; + + // Recursively heapify the affected sub-tree + heapify(arr, n, largest); + } + } + + // Main function to perform heap sort + static void heapSort(int arr[]) { + int n = arr.length; + + // Step 1: Build max heap + for (int i = n / 2 - 1; i >= 0; i--) + heapify(arr, n, i); + + // Step 2: Extract elements one by one + for (int i = n - 1; i >= 0; i--) { + // Move current root to end + int temp = arr[0]; + arr[0] = arr[i]; + arr[i] = temp; + + // Call max heapify on the reduced heap + heapify(arr, i, 0); + } + } + + // Utility function to print array + static void printArray(int arr[]) { + for (int value : arr) + System.out.print(value + " "); + System.out.println(); + } + + // Driver code + public static void main(String args[]) { + int arr[] = { 12, 11, 13, 5, 6, 7 }; + System.out.println("Original array:"); + printArray(arr); + + heapSort(arr); + + System.out.println("Sorted array:"); + printArray(arr); + } +} diff --git a/java/hellowordl.java b/java/Hello.java similarity index 79% rename from java/hellowordl.java rename to java/Hello.java index 2bf53004..a605554a 100644 --- a/java/hellowordl.java +++ b/java/Hello.java @@ -1,4 +1,4 @@ -public class hellowordl { +public class Hello { public static void main(String[] args) { System.out.println("Hello, World!"); } diff --git a/java/HouseRobber/houseRobber1.java b/java/HouseRobber/houseRobber1.java new file mode 100644 index 00000000..dbb6766f --- /dev/null +++ b/java/HouseRobber/houseRobber1.java @@ -0,0 +1,66 @@ +// You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night. + +// Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police. + + + +// Example 1: + +// Input: nums = [1,2,3,1] +// Output: 4 +// Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). +// Total amount you can rob = 1 + 3 = 4. +// Example 2: + +// Input: nums = [2,7,9,3,1] +// Output: 12 +// Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1). +// Total amount you can rob = 2 + 9 + 1 = 12. + + +package HouseRobber; + +import java.util.Arrays; + +public class houseRobber1 { + /** + * Recursive helper function to calculate the maximum amount that can be robbed starting from house i. + * @param i Current house index + * @param a Array of money in each house + * @param dp Memoization table to store results for subproblems + * @return Maximum money that can be robbed from house i onwards + */ + private int f(int i, int[] a, int[] dp) { + // If at the last house, rob it (base case) + if(i == a.length - 1){ + return a[i]; + } + // If out of bounds, no money can be robbed + if(i >= a.length){ + return 0; + } + // Return cached result if already computed + if(dp[i] != -1) { + return dp[i]; + } + + // Option 1: Rob current house and skip next (move to i+2) + int take = a[i]+f(i+2,a,dp); + // Option 2: Skip current house (move to i+1) + int notTake = f(i+1,a,dp); + // Store and return the maximum of both options + return dp[i] = Math.max(take,notTake); + } + + /** + * Calculates the maximum amount of money that can be robbed without alerting the police. + * @param a Array of money in each house + * @return Maximum money that can be robbed + */ + public int rob(int[] a) { + int n = a.length; + int[] dp = new int[n]; + Arrays.fill(dp,-1); // Initialize memoization table + return f(0,a,dp); // Start from the first house + } +} diff --git a/java/HouseRobber/houseRobber2.java b/java/HouseRobber/houseRobber2.java new file mode 100644 index 00000000..2dd7372c --- /dev/null +++ b/java/HouseRobber/houseRobber2.java @@ -0,0 +1,76 @@ +// You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night. + +// Given an integer array nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police. + + + +// Example 1: + +// Input: nums = [2,3,2] +// Output: 3 +// Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses. +// Example 2: + +// Input: nums = [1,2,3,1] +// Output: 4 +// Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3). +// Total amount you can rob = 1 + 3 = 4. + +package HouseRobber; + +import java.util.Arrays; + +public class houseRobber2 { + /** + * Recursive helper function to calculate the maximum amount that can be robbed up to house i. + * @param i Current house index (working backwards) + * @param a Array of money in each house + * @param dp Memoization table to store results for subproblems + * @return Maximum money that can be robbed up to house i + */ + private int f(int i, int[] a, int[] dp) { + // If out of bounds, no money can be robbed + if(i < 0) return 0; + // If at the first house, rob it (base case) + if(i == 0) return a[i]; + // Return cached result if already computed + if(dp[i] != -1) return dp[i]; + + // Option 1: Rob current house and skip previous (move to i-2) + // Option 2: Skip current house (move to i-1) + return dp[i] = Math.max(a[i] + f(i-2, a, dp), f(i-1,a,dp)); + } + + /** + * Calculates the maximum amount of money that can be robbed in a circular arrangement of houses. + * @param a Array of money in each house + * @return Maximum money that can be robbed + */ + public int rob(int[] a) { + int n = a.length; + // If only one house, rob it + if(n == 1)return a[0]; + int[] dp = new int[n+1]; + Arrays.fill(dp,-1); + + // Create two scenarios: + // 1. Exclude the first house (rob from 1 to n-1) + // 2. Exclude the last house (rob from 0 to n-2) + int arr1[] = new int[n - 1]; + int arr2[] = new int[n - 1]; + int t = 0; + for (int i = 1; i < n; i++) { + arr1[t++] = a[i]; + } + t = 0; + for (int i = 0; i < n - 1; i++) { + arr2[t++] = a[i]; + } + + // Compute max for both scenarios and return the best + int first = f(n-2,arr1,dp); + Arrays.fill(dp,-1); + int last = f(n-2,arr2,dp); + return Math.max(first,last); + } +} diff --git a/java/Implement_Trie_(Prefix__Tree).java b/java/Implement_Trie_(Prefix__Tree).java new file mode 100644 index 00000000..511e0409 --- /dev/null +++ b/java/Implement_Trie_(Prefix__Tree).java @@ -0,0 +1,61 @@ +class Trie { + TrieNode root; + public Trie() { + root = new TrieNode(); + } + + public void insert(String word) { + TrieNode temp = root; + + for (char c : word.toCharArray()) { + temp.children.putIfAbsent(c, new TrieNode()); + temp = temp.children.get(c); + } + + temp.isword = true; + } + + public boolean search(String word) { + TrieNode temp = root; + + for (char c : word.toCharArray()) { + + if (!temp.children.containsKey(c)) { + return false; + } + + temp = temp.children.get(c); + } + + return temp.isword; + + } + + public boolean startsWith(String prefix) { + TrieNode temp = root; + + for (char c : prefix.toCharArray()) { + + if (!temp.children.containsKey(c)) { + return false; + } + + temp = temp.children.get(c); + } + + return true; + } +} + +class TrieNode { + HashMap children = new HashMap<>(); + boolean isword = false; +} + +/** + * Your Trie object will be instantiated and called as such: + * Trie obj = new Trie(); + * obj.insert(word); + * boolean param_2 = obj.search(word); + * boolean param_3 = obj.startsWith(prefix); + */ \ No newline at end of file diff --git a/java/InsertionSort.java b/java/InsertionSort.java new file mode 100644 index 00000000..3899cc5d --- /dev/null +++ b/java/InsertionSort.java @@ -0,0 +1,27 @@ +public class InsertionSort { + public static void main(String[] args) { + int[] arr = {67, 25, 12, 21, 9}; + + insertionSort(arr); + + System.out.println("Sorted array:"); + for (int num : arr) { + System.out.print(num + " "); + } + } + + public static void insertionSort(int[] arr) { + int n = arr.length; + for (int i = 1; i < n; i++) { + int key = arr[i]; + int j = i - 1; + + while (j >= 0 && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } + } +} + diff --git a/java/JDBCEx.java b/java/JDBCEx.java new file mode 100644 index 00000000..c79f613a --- /dev/null +++ b/java/JDBCEx.java @@ -0,0 +1,35 @@ +import java.sql.*; + +public class JDBCEx { + public static void main(String[] args) { + try { + + // Load the driver + Class.forName("com.mysql.cj.jdbc.Driver"); + + // Establish the connection + Connection con = DriverManager.getConnection( + "jdbc:mysql://localhost:3306/world", "root", "12345"); + + // Create a statement + Statement st = con.createStatement(); + + // Execute a query + String sql = "SELECT * FROM people"; + ResultSet rs = st.executeQuery(sql); + + // Process the results + while (rs.next()) { + System.out.println("Name: " + rs.getString("name") + + ", Age: " + rs.getInt("age")); + } + + // Close resources + rs.close(); + st.close(); + con.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/java/JumpGame.java b/java/JumpGame.java new file mode 100644 index 00000000..1c967a31 --- /dev/null +++ b/java/JumpGame.java @@ -0,0 +1,41 @@ + +import java.util.*; + +// Rename class to JumpGame +public class JumpGame { + // Function to compute the minimum number of jumps to reach the last index + public int jump(int[] nums) { + // Edge case: if array has 1 or fewer elements, no jumps needed + if (nums == null || nums.length <= 1) return 0; + + int jumps = 0; + int currentEnd = 0; + int farthest = 0; + + // Loop through array up to second last index + for (int i = 0; i < nums.length - 1; i++) { + // Update the farthest index we can reach + farthest = Math.max(farthest, i + nums[i]); + + // If current index reaches the end of current range + if (i == currentEnd) { + jumps++; + currentEnd = farthest; + // If currentEnd has reached or passed the last index, break early + if (currentEnd >= nums.length - 1) break; + } + } + + return jumps; + } +} + +// Driver Code +class JumpGameTest { + public static void main(String[] args) { + JumpGame sol = new JumpGame(); + int[] nums = {2, 3, 1, 1, 4}; + + System.out.println("Minimum jumps required: " + sol.jump(nums)); + } +} \ No newline at end of file diff --git a/java/JumpGame1.java b/java/JumpGame1.java new file mode 100644 index 00000000..34ab50d5 --- /dev/null +++ b/java/JumpGame1.java @@ -0,0 +1,11 @@ +class Solution { + public boolean canJump(int[] nums) { + + int reach = 0; + for(int i=0; i reach)return false; + reach = Math.max(reach, i + nums[i]); + } + return true; + } +} \ No newline at end of file diff --git a/java/JumpGame2.java b/java/JumpGame2.java new file mode 100644 index 00000000..e69de29b diff --git a/java/KMPStringSearch.java b/java/KMPStringSearch.java new file mode 100644 index 00000000..470aa8d9 --- /dev/null +++ b/java/KMPStringSearch.java @@ -0,0 +1,58 @@ +import java.util.*; +public class KMPStringSearch { + + private static int[] computeLPS(String pattern) { + int[] lps = new int[pattern.length()]; + int len = 0; + int i = 1; + + while (i < pattern.length()) { + if (pattern.charAt(i) == pattern.charAt(len)) { + len++; + lps[i] = len; + i++; + } else { + if (len != 0) { + len = lps[len - 1]; + } else { + lps[i] = 0; + i++; + } + } + } + return lps; + } + + public static void KMPSearch(String text, String pattern) { + int n = text.length(); + int m = pattern.length(); + int[] lps = computeLPS(pattern); + + int i = 0; + int j = 0; + + while (i < n) { + if (pattern.charAt(j) == text.charAt(i)) { + i++; + j++; + } + + if (j == m) { + System.out.println("Pattern found at index " + (i - j)); + j = lps[j - 1]; + } else if (i < n && pattern.charAt(j) != text.charAt(i)) { + if (j != 0) + j = lps[j - 1]; + else + i++; + } + } + } + + public static void main(String[] args) { + String text = "ABABDABACDABABCABAB"; + String pattern = "ABABCABAB"; + KMPSearch(text, pattern); + } +} + diff --git a/java/K_closest_points_to_origin.java b/java/K_closest_points_to_origin.java new file mode 100644 index 00000000..48b7aa14 --- /dev/null +++ b/java/K_closest_points_to_origin.java @@ -0,0 +1,38 @@ +import java.util.*; + +class K_closest_points_to_origin { + public static int[][] kClosest(int[][] points, int k) { + + PriorityQueue queue = new PriorityQueue<>( + (a, b) -> (b[0]*b[0] + b[1]*b[1]) - (a[0]*a[0] + a[1]*a[1]) + ); + + for (int[] point : points) { + queue.add(point); + if (queue.size() > k) { + queue.poll(); + } + } + + int[][] result = new int[k][2]; + for (int i = 0; i < k; i++) { + result[i] = queue.poll(); + } + + return result; + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + int num = sc.nextInt(); + int k = sc.nextInt(); + int[][] input = new int[num][2]; + for (int i = 0; i < input.length; i++) { + input[i][0] = sc.nextInt(); + input[i][1] = sc.nextInt(); + } + + int[][] output = kClosest(input, k); + System.out.println(Arrays.deepToString(output)); + } +} diff --git a/java/Kadanes.java b/java/Kadanes.java new file mode 100644 index 00000000..e29c5156 --- /dev/null +++ b/java/Kadanes.java @@ -0,0 +1,22 @@ +import java.util.*; + +//kadane's Algorithm is the most optimized +//solution for finding maximum subarray sum and it is also most important algorithm for placements + +public class Kadanes{ + public static int maxSub(int[] nums){ + int maxi = nums[0]; + int curr = nums[0]; + + for(int i = 1; i max) { + max = b; + } + } + + // setting the search space for binary search + long l = 1, r = max; + + // implementing binary search to find the minimum eating speed + while (l <= r) { + long mid = (l + r) / 2; + + long currhr = verify(mid, piles); + + if (currhr > h) { + l = mid + 1; + } else { + // updating the minimum speed found so far so that we have the least possible speed + min = (int) Math.min(min, mid); + r = mid-1; + } + } + + return min; + } + + // helper function to calculate the hours needed at a given speed + private long verify(long num, int[] piles) { + long hr = 0; + + for (int p : piles) { + hr += (p + num - 1) / num; + } + + return hr; + } +} \ No newline at end of file diff --git a/java/KthLargestElement.java b/java/KthLargestElement.java new file mode 100644 index 00000000..baab4b6f --- /dev/null +++ b/java/KthLargestElement.java @@ -0,0 +1,45 @@ +//its the solution for leetcode 215 +//sorting the array using quick select in Time Complexity o(n)(avg) && Space Complexity o(1) + +class Solution { + public int findKthLargest(int[] nums, int k) { + int n = nums.length; + int target = n - k; + int left = 0, right = n - 1; + + Random rand = new Random(); + + while (left <= right) { + int pivotIndex = left + rand.nextInt(right - left + 1); + int pivot = nums[pivotIndex]; + + int lt = left, i = left, gt = right; + while (i <= gt) { + if (nums[i] < pivot) { + swap(nums, lt, i); + lt++; + i++; + } else if (nums[i] > pivot) { + swap(nums, i, gt); + gt--; + } else { + i++; + } + } + if (target >= lt && target <= gt) { + return pivot; + } else if (target < lt) { + right = lt - 1; + } else { + left = gt + 1; + } + } + return -1; + } + + private void swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} diff --git a/java/LRUCache$Node.class b/java/LRUCache$Node.class new file mode 100644 index 00000000..71b9aa3c Binary files /dev/null and b/java/LRUCache$Node.class differ diff --git a/java/LRUCache.class b/java/LRUCache.class new file mode 100644 index 00000000..919844e8 Binary files /dev/null and b/java/LRUCache.class differ diff --git a/java/LRUCache.java b/java/LRUCache.java new file mode 100644 index 00000000..7f6c99c8 --- /dev/null +++ b/java/LRUCache.java @@ -0,0 +1,141 @@ +import java.util.HashMap; +import java.util.Map; + +/** + * An implementation of a Least Recently Used (LRU) Cache. + * + * This data structure uses a combination of a HashMap and a Doubly Linked List + * to achieve O(1) average time complexity for both `get` and `put` operations. + * + * - The HashMap stores the key and a reference to the Node in the linked list + * for O(1) lookup. + * - The Doubly Linked List maintains the order of usage. The most recently used + * item is at the head, and the least recently used item is at the tail. + */ +public class LRUCache { + + // Inner class to represent a node in the doubly linked list. + private static class Node { + int key; + int value; + Node prev; + Node next; + + Node(int key, int value) { + this.key = key; + this.value = value; + } + } + + private final int capacity; + private final Map map; + // Dummy head and tail nodes to simplify list operations (add/remove). + private final Node head; + private final Node tail; + + /** + * Constructs an LRUCache with a given capacity. + * + * @param capacity The maximum number of items the cache can hold. + */ + public LRUCache(int capacity) { + this.capacity = capacity; + this.map = new HashMap<>(); + this.head = new Node(0, 0); // Dummy head + this.tail = new Node(0, 0); // Dummy tail + head.next = tail; + tail.prev = head; + } + + /** + * Retrieves the value for a given key. + * If the key exists, the item is marked as recently used by moving it to the + * head of the list. + * + * @param key The key to look up. + * @return The value associated with the key, or -1 if the key does not exist. + */ + public int get(int key) { + if (!map.containsKey(key)) { + return -1; + } + Node node = map.get(key); + // This item is now the most recently used, so move it to the head. + removeNode(node); + + addToHead(node); + return node.value; + } + + /** + * Inserts or updates a key-value pair. + * If the key already exists, its value is updated, and it's marked as recently + * used. + * If it's a new key and the cache is full, the least recently used item is + * evicted. + * + * @param key The key to insert or update. + * @param value The value to associate with the key. + */ + public void put(int key, int value) { + // If the key already exists, update its value and move it to the head. + if (map.containsKey(key)) { + Node node = map.get(key); + node.value = value; + removeNode(node); + addToHead(node); + return; + } + + // If the cache is full, evict the least recently used item (at the tail). + if (map.size() == capacity) { + Node tailPrev = tail.prev; + removeNode(tailPrev); + map.remove(tailPrev.key); + } + + // Add the new item to the head of the list and to the map. + Node newNode = new Node(key, value); + addToHead(newNode); + map.put(key, newNode); + } + + // Helper method to add a node to the front (head) of the list. + private void addToHead(Node node) { + node.next = head.next; + head.next.prev = node; + head.next = node; + node.prev = head; + } + + // Helper method to remove a node from its current position in the list. + private void removeNode(Node node) { + node.prev.next = node.next; + node.next.prev = node.prev; + } + + // Main method to demonstrate usage. + public static void main(String[] args) { + System.out.println("Initializing LRUCache with capacity 2..."); + LRUCache cache = new LRUCache(2); + + System.out.println("put(1, 1)"); + cache.put(1, 1); + System.out.println("put(2, 2)"); + cache.put(2, 2); + + System.out.println("get(1): " + cache.get(1)); // returns 1, (1,1) is now most recently used + + System.out.println("put(3, 3)"); // evicts key 2, (3,3) is now most recently used + cache.put(3, 3); + + System.out.println("get(2): " + cache.get(2)); // returns -1 (not found) + + System.out.println("put(4, 4)"); // evicts key 1, (4,4) is now most recently used + cache.put(4, 4); + + System.out.println("get(1): " + cache.get(1)); // returns -1 (not found) + System.out.println("get(3): " + cache.get(3)); // returns 3 + System.out.println("get(4): " + cache.get(4)); // returns 4 + } +} \ No newline at end of file diff --git a/java/Largest_Rectangle_in_Histogram.java b/java/Largest_Rectangle_in_Histogram.java new file mode 100644 index 00000000..d4eedc2f --- /dev/null +++ b/java/Largest_Rectangle_in_Histogram.java @@ -0,0 +1,38 @@ +class Solution { + public int largestRectangleArea(int[] heights) { + int n = heights.length; + int[] pse = new int[n]; + int[] nse = new int[n]; + int maxArea = 0; + Stack st = new Stack<>(); + st.push(0); + pse[0] = -1; + for(int i = 1 ; i < n ; i++){ + while(!st.isEmpty() && heights[st.peek()] >= heights[i]){ + st.pop(); + } + if(st.isEmpty()){ + pse[i] = -1; + } + else pse[i] = st.peek(); + st.push(i); + } + while(!st.isEmpty()) st.pop(); + st.push(n-1); + nse[n-1] = n; + for(int i = n-2 ; i >= 0 ; i--){ + while(!st.isEmpty() && heights[st.peek()] >= heights[i]){ + st.pop(); + } + if(st.isEmpty()) nse[i] = n; + else nse[i] = st.peek(); + st.push(i); + } + for(int i = 0 ; i < n ; i++){ + int width = nse[i] - pse[i] - 1; + int area = heights[i]*width; + maxArea = Math.max(maxArea,area); + } + return maxArea; + } +} \ No newline at end of file diff --git a/java/LeadersInArr.class b/java/LeadersInArr.class new file mode 100644 index 00000000..38fdfa37 Binary files /dev/null and b/java/LeadersInArr.class differ diff --git a/java/LeadersInArr.java b/java/LeadersInArr.java new file mode 100644 index 00000000..ffea86c6 --- /dev/null +++ b/java/LeadersInArr.java @@ -0,0 +1,24 @@ +import java.util.*; + +public class LeadersInArr { + + public static void main(String[] args) { + int[] arr = { 16, 17, 4, 3, 5, 2 }; + int n = arr.length; + List leaders = new ArrayList<>(); + + int maxFromRight = arr[n - 1]; + leaders.add(maxFromRight); + + for (int i = n - 2; i >= 0; i--) { + if (arr[i] >= maxFromRight) { + maxFromRight = arr[i]; + leaders.add(maxFromRight); + } + } + + // Reverse to get leaders in correct order + Collections.reverse(leaders); + System.out.println(leaders); + } +} diff --git a/java/Leetcode Solutions/1-two-sum/README.md b/java/Leetcode Solutions/1-two-sum/README.md new file mode 100644 index 00000000..6b3a0556 --- /dev/null +++ b/java/Leetcode Solutions/1-two-sum/README.md @@ -0,0 +1,41 @@ +

    Two Sum

    Difficulty: Easy

    Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.

    + +

    You may assume that each input would have exactly one solution, and you may not use the same element twice.

    + +

    You can return the answer in any order.

    + +

     

    +

    Example 1:

    + +
    +Input: nums = [2,7,11,15], target = 9
    +Output: [0,1]
    +Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
    +
    + +

    Example 2:

    + +
    +Input: nums = [3,2,4], target = 6
    +Output: [1,2]
    +
    + +

    Example 3:

    + +
    +Input: nums = [3,3], target = 6
    +Output: [0,1]
    +
    + +

     

    +

    Constraints:

    + +
      +
    • 2 <= nums.length <= 104
    • +
    • -109 <= nums[i] <= 109
    • +
    • -109 <= target <= 109
    • +
    • Only one valid answer exists.
    • +
    + +

     

    +Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity? \ No newline at end of file diff --git a/java/Leetcode Solutions/1-two-sum/two-sum.java b/java/Leetcode Solutions/1-two-sum/two-sum.java new file mode 100644 index 00000000..335e4f33 --- /dev/null +++ b/java/Leetcode Solutions/1-two-sum/two-sum.java @@ -0,0 +1,14 @@ +class Solution { + public int[] twoSum(int[] arr, int target) { + Map map = new HashMap<>(); + for(int i =0;iN-Queens Difficulty: Hard

    The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two queens attack each other.

    + +

    Given an integer n, return all distinct solutions to the n-queens puzzle. You may return the answer in any order.

    + +

    Each solution contains a distinct board configuration of the n-queens' placement, where 'Q' and '.' both indicate a queen and an empty space, respectively.

    + +

     

    +

    Example 1:

    + +
    +Input: n = 4
    +Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
    +Explanation: There exist two distinct solutions to the 4-queens puzzle as shown above
    +
    + +

    Example 2:

    + +
    +Input: n = 1
    +Output: [["Q"]]
    +
    + +

     

    +

    Constraints:

    + +
      +
    • 1 <= n <= 9
    • +
    diff --git a/java/Leetcode Solutions/51-n-queens/n-queens.java b/java/Leetcode Solutions/51-n-queens/n-queens.java new file mode 100644 index 00000000..fd8e2a57 --- /dev/null +++ b/java/Leetcode Solutions/51-n-queens/n-queens.java @@ -0,0 +1,79 @@ +class Solution { + public List> solveNQueens(int n) { + // Initialize the board with '.' representing empty spaces + char[][] board = new char[n][n]; + // Fill the board with '.' to represent empty positions + for (int i = 0; i < n; i++) { + Arrays.fill(board[i], '.'); + } + + // List to store all valid solutions + List> result = new ArrayList<>(); + + // Arrays to track attacked rows and diagonals + int[] leftRow = new int[n]; // Tracks if a row is occupied + int[] lowerDiagonal = new int[2 * n - 1]; // Tracks if a lower diagonal is attacked + int[] upperDiagonal = new int[2 * n - 1]; // Tracks if an upper diagonal is attacked + + // Start the backtracking process from column 0 + backtrack(0, board, result, leftRow, lowerDiagonal, upperDiagonal); + + // Return the list of all valid solutions + return result; + } + + // Backtracking function to try placing queens column by column + private void backtrack(int col, char[][] board, List> result, + int[] leftRow, int[] lowerDiagonal, int[] upperDiagonal) { + + // If we've placed queens in all columns, we've found a solution + if (col == board.length) { + result.add(construct(board)); // Convert the board to a list of strings and add it to result + return; + } + + // Try placing a queen in each row of the current column + for (int row = 0; row < board.length; row++) { + + // Check if it's safe to place a queen at position (row, col) + // A position is safe if: + // - The row is not already occupied (leftRow[row] == 0) + // - The lower diagonal is not attacked (lowerDiagonal[row + col] == 0) + // - The upper diagonal is not attacked (upperDiagonal[board.length - 1 + col - row] == 0) + if (leftRow[row] == 0 && lowerDiagonal[row + col] == 0 + && upperDiagonal[board.length - 1 + col - row] == 0) { + + // Place the queen on the board at (row, col) + board[row][col] = 'Q'; + + // Mark the row and diagonals as attacked + leftRow[row] = 1; + lowerDiagonal[row + col] = 1; + upperDiagonal[board.length - 1 + col - row] = 1; + + // Recursively place queens in the next column + backtrack(col + 1, board, result, leftRow, lowerDiagonal, upperDiagonal); + + // If placing a queen didn't lead to a solution, backtrack: + // Remove the queen and unmark the attacked positions + board[row][col] = '.'; + leftRow[row] = 0; + lowerDiagonal[row + col] = 0; + upperDiagonal[board.length - 1 + col - row] = 0; + } + } + } + + // Function to convert the board (a 2D char array) to a List of Strings + private List construct(char[][] board) { + List result = new ArrayList<>(); + + // For each row in the board, convert it to a string and add it to the result list + for (char[] row : board) { + result.add(new String(row)); + } + + // Return the list of strings representing the board + return result; + } +} diff --git a/java/Leetcode Solutions/69-sqrtx/README.md b/java/Leetcode Solutions/69-sqrtx/README.md new file mode 100644 index 00000000..57b54248 --- /dev/null +++ b/java/Leetcode Solutions/69-sqrtx/README.md @@ -0,0 +1,31 @@ +

    Sqrt(x)

    Difficulty: Easy

    Given a non-negative integer x, return the square root of x rounded down to the nearest integer. The returned integer should be non-negative as well.

    + +

    You must not use any built-in exponent function or operator.

    + +
      +
    • For example, do not use pow(x, 0.5) in c++ or x ** 0.5 in python.
    • +
    + +

     

    +

    Example 1:

    + +
    +Input: x = 4
    +Output: 2
    +Explanation: The square root of 4 is 2, so we return 2.
    +
    + +

    Example 2:

    + +
    +Input: x = 8
    +Output: 2
    +Explanation: The square root of 8 is 2.82842..., and since we round it down to the nearest integer, 2 is returned.
    +
    + +

     

    +

    Constraints:

    + +
      +
    • 0 <= x <= 231 - 1
    • +
    diff --git a/java/Leetcode Solutions/69-sqrtx/sqrtx.java b/java/Leetcode Solutions/69-sqrtx/sqrtx.java new file mode 100644 index 00000000..f3738086 --- /dev/null +++ b/java/Leetcode Solutions/69-sqrtx/sqrtx.java @@ -0,0 +1,27 @@ +class Solution { + public int mySqrt(int x) { + return binarySearch(x); + } + + private int binarySearch(int n) { + int start = 0; + int end = n; + int mid = start + (end - start) / 2; + int ans = -1; + + while (start <= end) { + long square = (long) mid * mid; + + if (square == n) { + return mid; + } else if (square < n) { + ans = mid; + start = mid + 1; + } else { + end = mid - 1; + } + mid = start + (end - start) / 2; + } + return ans; + } +} \ No newline at end of file diff --git a/java/Leetcode Solutions/7-reverse-integer/README.md b/java/Leetcode Solutions/7-reverse-integer/README.md new file mode 100644 index 00000000..bb7ea1dd --- /dev/null +++ b/java/Leetcode Solutions/7-reverse-integer/README.md @@ -0,0 +1,32 @@ +

    Reverse Integer

    Difficulty: Medium

    Given a signed 32-bit integer x, return x with its digits reversed. If reversing x causes the value to go outside the signed 32-bit integer range [-231, 231 - 1], then return 0.

    + +

    Assume the environment does not allow you to store 64-bit integers (signed or unsigned).

    + +

     

    +

    Example 1:

    + +
    +Input: x = 123
    +Output: 321
    +
    + +

    Example 2:

    + +
    +Input: x = -123
    +Output: -321
    +
    + +

    Example 3:

    + +
    +Input: x = 120
    +Output: 21
    +
    + +

     

    +

    Constraints:

    + +
      +
    • -231 <= x <= 231 - 1
    • +
    diff --git a/java/Leetcode Solutions/7-reverse-integer/reverse-integer.java b/java/Leetcode Solutions/7-reverse-integer/reverse-integer.java new file mode 100644 index 00000000..68b273be --- /dev/null +++ b/java/Leetcode Solutions/7-reverse-integer/reverse-integer.java @@ -0,0 +1,17 @@ +class Solution { + public int reverse(int x) { + int ans = 0; + + while (x != 0) { + int digit = x % 10; + + if ((ans > Integer.MAX_VALUE / 10) || (ans < Integer.MIN_VALUE / 10)) { + return 0; + } + ans = (ans * 10) + digit; + x = x / 10; + + } + return ans; + } +} \ No newline at end of file diff --git a/java/Leetcode Solutions/74-search-a-2d-matrix/README.md b/java/Leetcode Solutions/74-search-a-2d-matrix/README.md new file mode 100644 index 00000000..6632b1b8 --- /dev/null +++ b/java/Leetcode Solutions/74-search-a-2d-matrix/README.md @@ -0,0 +1,35 @@ +

    Search a 2D Matrix

    Difficulty: Medium

    You are given an m x n integer matrix matrix with the following two properties:

    + +
      +
    • Each row is sorted in non-decreasing order.
    • +
    • The first integer of each row is greater than the last integer of the previous row.
    • +
    + +

    Given an integer target, return true if target is in matrix or false otherwise.

    + +

    You must write a solution in O(log(m * n)) time complexity.

    + +

     

    +

    Example 1:

    + +
    +Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
    +Output: true
    +
    + +

    Example 2:

    + +
    +Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
    +Output: false
    +
    + +

     

    +

    Constraints:

    + +
      +
    • m == matrix.length
    • +
    • n == matrix[i].length
    • +
    • 1 <= m, n <= 100
    • +
    • -104 <= matrix[i][j], target <= 104
    • +
    diff --git a/java/Leetcode Solutions/74-search-a-2d-matrix/search-a-2d-matrix.java b/java/Leetcode Solutions/74-search-a-2d-matrix/search-a-2d-matrix.java new file mode 100644 index 00000000..1235a298 --- /dev/null +++ b/java/Leetcode Solutions/74-search-a-2d-matrix/search-a-2d-matrix.java @@ -0,0 +1,26 @@ +class Solution { + public boolean searchMatrix(int[][] matrix, int target) { + int row = matrix.length; + int col = matrix[0].length; + + int start = 0; + int end = row * col - 1; + + int mid = start + (end - start) / 2; + + while (start <= end) { + mid = start + (end - start) / 2; + + int element = matrix[mid / col][mid % col]; + + if (element == target) { + return true; + } else if (element < target) { + start = mid + 1; + } else { + end = mid - 1; + } + } + return false; + } +} \ No newline at end of file diff --git a/java/Leetcode25.class b/java/Leetcode25.class new file mode 100644 index 00000000..15155718 Binary files /dev/null and b/java/Leetcode25.class differ diff --git a/java/Leetcode25.java b/java/Leetcode25.java new file mode 100644 index 00000000..48223f08 --- /dev/null +++ b/java/Leetcode25.java @@ -0,0 +1,77 @@ +// File: Leetcode25.java + +public class Leetcode25 { + + public ListNode reverseKGroup(ListNode head, int k) { + if (head == null) { + return null; + } + + // Check if there are at least k nodes left to reverse + ListNode temp = head; + int count = 0; + while (temp != null && count < k) { + temp = temp.next; + count++; + } + + // If we have fewer than k nodes, return head as is + if (count < k) { + return head; + } + + // Reverse first k nodes + ListNode curr = head, prev = null, next = null; + count = 0; + while (curr != null && count < k) { + next = curr.next; + curr.next = prev; + prev = curr; + curr = next; + count++; + } + + // Recursively reverse the remaining nodes + if (next != null) { + head.next = reverseKGroup(next, k); + } + + return prev; + } + + // --- MAIN METHOD TO TEST --- + public static void main(String[] args) { + // Create a sample linked list: 1 -> 2 -> 3 -> 4 -> 5 + ListNode head = new ListNode(1); + head.next = new ListNode(2); + head.next.next = new ListNode(3); + head.next.next.next = new ListNode(4); + head.next.next.next.next = new ListNode(5); + + int k = 2; // Group size + + Leetcode25 solution = new Leetcode25(); + ListNode result = solution.reverseKGroup(head, k); + + // Print reversed list + System.out.print("Reversed in groups of " + k + ": "); + printList(result); + } + + // Helper function to print the linked list + public static void printList(ListNode head) { + while (head != null) { + System.out.print(head.val); + if (head.next != null) System.out.print(" -> "); + head = head.next; + } + System.out.println(); + } +} + +// Definition for singly-linked list. +class ListNode { + int val; + ListNode next; + ListNode(int val) { this.val = val; } +} diff --git a/java/Levenshtein_distance/ReadMe.md b/java/Levenshtein_distance/ReadMe.md new file mode 100644 index 00000000..1901a99e --- /dev/null +++ b/java/Levenshtein_distance/ReadMe.md @@ -0,0 +1,45 @@ +### Edit Distance AKA ( Levenshtein Distance ) +- Levenshtein distance is a measure of the similarity between two strings, which takes into account the number of insertion, deletion and substitution operations needed to transform one string into the other. + +**Problem statement:** +- Given two words word1 and word2, return the minimum number of operations required to convert word1 to word2. + You have these operations permitted on a word: + - Insert a character + - Delete a character + - Replace a character + +- Example 1: + Input: word1 = "horse", word2 = "ros" + Output: 3 + Explanation: + horse → rorse (replace ‘h’ with ‘r’) + rorse → rose (remove ‘r’) + rose → ros (remove ‘e’) + +- Example 2: + Input: word1 = "intention", word2 = "execution" + Output: 5 + Explanation: + intention -> inention (remove 't') + inention -> enention (replace 'i' with 'e') + enention -> exention (replace 'n' with 'x') + exention -> exection (replace 'n' with 'c') + exection -> execution (insert 'u') + +- Constraints: + 1 <= word1.length, word2.length <= 500 + word1 and word2 consist of lowercase English letters. + +**Approach:** +- Using dynamic programming. +- Defined dp[i][j] = min edits to convert first i chars of word1 to first j chars of word2. +- Recurrence: + - If characters match, dp[i][j] = dp[i-1][j-1] + - Else dp[i][j] = 1 + min(insert, delete, replace) + +**Time Complexity:** O(n * m) +**Space Complexity:** O(n * m) or O(min(n, m)) with optimization. + +**Edge cases:** +- One or both strings empty +- Strings are already equal diff --git a/java/Levenshtein_distance/edit_distance.java b/java/Levenshtein_distance/edit_distance.java new file mode 100644 index 00000000..d33da0f4 --- /dev/null +++ b/java/Levenshtein_distance/edit_distance.java @@ -0,0 +1,101 @@ +class Solution { + /** + * Buri Buri: "Shino-suke, this function will tell us how many changes we need to + * turn one word into another. It's called Levenshtein distance!" + * Shino-suke: "Ehhh? Sounds like some alien name… is it tasty?" + */ + public int minDistance(String s, String t) { + int n = s.length(); + int m = t.length(); + + // Buri Buri: "We’ll use a 2D table, dp, where dp[i][j] means + // ‘minimum edits to convert first i letters of s into first j letters of t.’" + int[][] dp = new int[n+1][m+1]; + + // Buri Buri: "First, if t is empty, we must delete everything from s." + // Shino-suke: "So we just keep pressing backspace, right?" + for (int i = 0; i <= n; i++) { + dp[i][0] = i; + } + + // Buri Buri: "And if s is empty, we need to insert all characters of t." + // Shino-suke: "Like typing the whole thing from scratch… boring~" + for (int j = 0; j <= m; j++) { + dp[0][j] = j; + } + + // Buri Buri: "Now, let’s fill the dp table cell by cell." + // Shino-suke: "Ughhh homework again…" + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + if (s.charAt(i-1) == t.charAt(j-1)) { + // Buri Buri: "If letters match, no need to change, copy diagonal value." + // Shino-suke: "Finally something easy!" + dp[i][j] = dp[i-1][j-1]; + } else { + // Buri Buri: "Else we try 3 things: Insert, Delete, Replace." + // Shino-suke: "So much effort just to make words same… I’d rather nap." + int insertCost = dp[i][j-1] + 1; + int deleteCost = dp[i-1][j] + 1; + int replaceCost = dp[i-1][j-1] + 1; + dp[i][j] = Math.min(insertCost, Math.min(deleteCost, replaceCost)); + } + } + } + // Buri Buri: "And voila! dp[n][m] is the answer!" + // Shino-suke: "Yay! Let’s eat choco chips now~" + return dp[n][m]; + } + + /** + * Buri Buri: "Shino-suke, sometimes memory is precious! + * This version only remembers two rows instead of whole dp table." + * Shino-suke: "So like saving pocket money, huh?" + */ + public int minDistanceOptimized(String s, String t) { + int n = s.length(); + int m = t.length(); + if (n < m) { + return minDistanceOptimized(t, s); + } + int[] prev = new int[m+1]; + int[] curr = new int[m+1]; + + // Initialize base row + for (int j = 0; j <= m; j++) { + prev[j] = j; + } + + for (int i = 1; i <= n; i++) { + curr[0] = i; + for (int j = 1; j <= m; j++) { + if (s.charAt(i-1) == t.charAt(j-1)) { + curr[j] = prev[j-1]; + } else { + int insertCost = curr[j-1] + 1; + int deleteCost = prev[j] + 1; + int replaceCost = prev[j-1] + 1; + curr[j] = Math.min(insertCost, Math.min(deleteCost, replaceCost)); + } + } + // Swap arrays + int[] temp = prev; + prev = curr; + curr = temp; + } + return prev[m]; + } + + /** + public static void main(String[] args) { + EditDistance solver = new EditDistance(); + String word1 = "horse"; + String word2 = "ros"; + + // Buri Buri: "Let’s test our magic with horse → ros." + // Shino-suke: "Heheheh, poor horse, losing letters like hair!" + System.out.println("Edit distance between \"" + word1 + "\" and \"" + word2 + "\": " + + solver.minDistance(word1, word2)); + // Expect 3 + } **/ + } \ No newline at end of file diff --git a/java/Lexicographically Smallest String After Applying Operations (Java) b/java/Lexicographically Smallest String After Applying Operations (Java) new file mode 100644 index 00000000..ed745b68 --- /dev/null +++ b/java/Lexicographically Smallest String After Applying Operations (Java) @@ -0,0 +1,50 @@ +Leetcode problem name - 1625 +Leetcode problem no. - Lexicographically Smallest String After Applying Operations + +Solution in Java: + +class Solution { + void rotate(StringBuilder s, int b) { + int n = s.length(); + b %= n; + reverse(s, 0, n - 1); + reverse(s, 0, b - 1); + reverse(s, b, n - 1); + } + + void reverse(StringBuilder s, int l, int r) { + while (l < r) { + char temp = s.charAt(l); + s.setCharAt(l, s.charAt(r)); + s.setCharAt(r, temp); + l++; + r--; + } + } + + void dfs(StringBuilder curr, int a, int b, Set visited, StringBuilder smallest) { + String str = curr.toString(); + if (visited.contains(str)) return; + visited.add(str); + if (str.compareTo(smallest.toString()) < 0) + smallest.replace(0, smallest.length(), str); + + StringBuilder added = new StringBuilder(str); + for (int i = 1; i < added.length(); i += 2) { + int newDigit = (added.charAt(i) - '0' + a) % 10; + added.setCharAt(i, (char) (newDigit + '0')); + } + dfs(added, a, b, visited, smallest); + + StringBuilder rotated = new StringBuilder(str); + rotate(rotated, b); + dfs(rotated, a, b, visited, smallest); + } + + public String findLexSmallestString(String s, int a, int b) { + Set visited = new HashSet<>(); + StringBuilder smallest = new StringBuilder(s); + dfs(new StringBuilder(s), a, b, visited, smallest); + return smallest.toString(); + } +} diff --git a/java/LinkCutTree.java b/java/LinkCutTree.java new file mode 100644 index 00000000..cc290b62 --- /dev/null +++ b/java/LinkCutTree.java @@ -0,0 +1,213 @@ + +import java.util.*; + +public class LinkCutTre { + + + + static class Node { + + Node left, right, parent; + boolean rev; + long val; + long sum; + int id; + + Node(int id, long val) { + this.id = id; + this.val = val; + this.sum = val; + } + } + + private final Node[] nodes; + + public LinkCutTree(int n) { + nodes = new Node[n + 1]; + for (int i = 1; i <= n; i++) { + nodes[i] = new Node(i, 0); + } + } + + private void pull(Node x) { + x.sum = x.val + (x.left != null ? x.left.sum : 0) + (x.right != null ? x.right.sum : 0); + } + + private void push(Node x) { + if (x == null) { + return; + } + if (x.rev) { + Node t = x.left; + x.left = x.right; + x.right = t; + if (x.left != null) { + x.left.rev ^= true; + } + if (x.right != null) { + x.right.rev ^= true; + } + x.rev = false; + } + } + + private boolean isSplayRoot(Node x) { + Node p = x.parent; + return p == null || (p.left != x && p.right != x); + } + + private void rotate(Node x) { + Node p = x.parent; + Node g = p.parent; + if (!isSplayRoot(p)) { + if (g.left == p) { + g.left = x; + }else { + g.right = x; + } + } + x.parent = g; + if (p.left == x) { + p.left = x.right; + if (x.right != null) { + x.right.parent = p; + } + x.right = p; + p.parent = x; + } else { + p.right = x.left; + if (x.left != null) { + x.left.parent = p; + } + x.left = p; + p.parent = x; + } + pull(p); + pull(x); + } + + private void pushPath(Node x) { + if (!isSplayRoot(x)) { + pushPath(x.parent); + } + push(x); + } + + private void splay(Node x) { + if (x == null) { + return; + } + pushPath(x); + while (!isSplayRoot(x)) { + Node p = x.parent; + Node g = p.parent; + if (!isSplayRoot(p)) { + if ((p.left == x) == (g.left == p)) { + rotate(p); + }else { + rotate(x); + } + } + rotate(x); + } + } + + private Node access(Node x) { + Node last = null; + for (Node y = x; y != null; y = y.parent) { + splay(y); + y.right = last; + pull(y); + last = y; + } + splay(x); + return last; + } + + private void makeRoot(Node x) { + access(x); + x.rev ^= true; + push(x); + } + + private Node findRoot(Node x) { + access(x); + while (true) { + push(x); + if (x.left == null) { + break; + } + x = x.left; + } + splay(x); + return x; + } + + public boolean link(int ui, int vi) { + Node u = nodes[ui], v = nodes[vi]; + makeRoot(u); + if (findRoot(v) == u) { + return false; + } + u.parent = v; + return true; + } + + public boolean cut(int ui, int vi) { + Node u = nodes[ui], v = nodes[vi]; + makeRoot(u); + access(v); + if (v.left == u && u.right == null) { + v.left.parent = null; + v.left = null; + pull(v); + return true; + } + return false; + } + + public boolean connected(int ui, int vi) { + return findRoot(nodes[ui]) == findRoot(nodes[vi]); + } + + public void update(int ui, long newVal) { + Node u = nodes[ui]; + access(u); + u.val = newVal; + pull(u); + } + + public long query(int ui, int vi) { + Node u = nodes[ui], v = nodes[vi]; + makeRoot(u); + access(v); + return v.sum; + } + + public static void main(String[] args) { + LinkCutTree lct = new LinkCutTree(7); + for (int i = 1; i <= 7; i++) { + lct.update(i, i); + } + lct.link(1, 2); + lct.link(2, 3); + lct.link(3, 4); + lct.link(5, 6); + lct.link(6, 7); + + System.out.println(lct.connected(1, 4)); + System.out.println(lct.query(1, 4)); + System.out.println(lct.connected(1, 5)); + + lct.link(4, 5); + System.out.println(lct.connected(1, 7)); + System.out.println(lct.query(2, 7)); + + lct.cut(3, 4); + System.out.println(lct.connected(1, 7)); + System.out.println(lct.query(1, 3)); + + lct.update(2, 20); + System.out.println(lct.query(1, 3)); + } +} diff --git a/java/LinkedListCycleDetection.java b/java/LinkedListCycleDetection.java new file mode 100644 index 00000000..19cd9e38 --- /dev/null +++ b/java/LinkedListCycleDetection.java @@ -0,0 +1,66 @@ +// LinkedListCycleDetection.java +// This class implements Floyd's Cycle Detection Algorithm to detect if a linked list has a cycle. +// Time Complexity: O(n), Space Complexity: O(1) + +class ListNode { + int val; + ListNode next; + ListNode(int x) { + val = x; + next = null; + } +} + +public class LinkedListCycleDetection { + + // Method to detect cycle in linked list using two pointers + public boolean hasCycle(ListNode head) { + if (head == null || head.next == null) { + return false; // No cycle if list is empty or has only one node + } + + ListNode slow = head; // Moves one step at a time + ListNode fast = head; // Moves two steps at a time + + while (fast != null && fast.next != null) { + slow = slow.next; // Move slow pointer by 1 + fast = fast.next.next; // Move fast pointer by 2 + + if (slow == fast) { + return true; // Cycle detected + } + } + + return false; // No cycle found + } + + // Main method for testing + public static void main(String[] args) { + LinkedListCycleDetection detector = new LinkedListCycleDetection(); + + // Create a linked list: 1 -> 2 -> 3 -> 4 -> 2 (cycle back to 2) + ListNode node1 = new ListNode(1); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(3); + ListNode node4 = new ListNode(4); + + node1.next = node2; + node2.next = node3; + node3.next = node4; + node4.next = node2; // Creates cycle + + boolean result = detector.hasCycle(node1); + System.out.println("Cycle detected: " + result); // Should print true + + // Test with no cycle: 1 -> 2 -> 3 -> null + ListNode nodeA = new ListNode(1); + ListNode nodeB = new ListNode(2); + ListNode nodeC = new ListNode(3); + + nodeA.next = nodeB; + nodeB.next = nodeC; + + boolean result2 = detector.hasCycle(nodeA); + System.out.println("Cycle detected: " + result2); // Should print false + } +} \ No newline at end of file diff --git a/java/ListNode.class b/java/ListNode.class new file mode 100644 index 00000000..77d9bcf4 Binary files /dev/null and b/java/ListNode.class differ diff --git a/java/Longest Palindromic Subseuence.java b/java/Longest Palindromic Subseuence.java new file mode 100644 index 00000000..29bcce94 --- /dev/null +++ b/java/Longest Palindromic Subseuence.java @@ -0,0 +1,19 @@ +class Solution { + public int longestPalindromeSubseq(String s) { + int n = s.length(); + String s2 = new StringBuilder(s).reverse().toString(); + int[] prev = new int[n + 1]; + int[] curr = new int[n + 1]; + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= n; j++) { + if (s.charAt(i - 1) == s2.charAt(j - 1)) { + curr[j] = 1 + prev[j - 1]; + } else { + curr[j] = Math.max(prev[j], curr[j - 1]); + } + } + prev = curr.clone(); + } + return prev[n]; + } +} diff --git a/java/Longest Substring Without Repeating Characters.java b/java/Longest Substring Without Repeating Characters.java deleted file mode 100644 index 979e1f62..00000000 --- a/java/Longest Substring Without Repeating Characters.java +++ /dev/null @@ -1,33 +0,0 @@ -import java.util.*; - -public class LongestSubstring { - public static int lengthOfLongestSubstring(String s) { - HashSet set = new HashSet<>(); - int left = 0, maxLength = 0; - - for (int right = 0; right < s.length(); right++) { - while (set.contains(s.charAt(right))) { - set.remove(s.charAt(left)); - left++; - } - set.add(s.charAt(right)); - maxLength = Math.max(maxLength, right - left + 1); - } - - return maxLength; - } - - public static void main(String[] args) { - String s = "abcabcbb"; - System.out.println("Input: " + s); - System.out.println("Longest Substring Length: " + lengthOfLongestSubstring(s)); - - s = "pwwkew"; - System.out.println("Input: " + s); - System.out.println("Longest Substring Length: " + lengthOfLongestSubstring(s)); - - s = "bbbbb"; - System.out.println("Input: " + s); - System.out.println("Longest Substring Length: " + lengthOfLongestSubstring(s)); - } -} \ No newline at end of file diff --git a/java/LongestCommonPrefix.java b/java/LongestCommonPrefix.java new file mode 100644 index 00000000..3aa4d626 --- /dev/null +++ b/java/LongestCommonPrefix.java @@ -0,0 +1,45 @@ +LongestCommonPrefix + +import java.util.Scanner; +import java.util.Arrays; + +public class LongestCommonPrefix { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Taking user input for number of strings + System.out.print("Enter number of strings: "); + int n = sc.nextInt(); + sc.nextLine(); // consume newline + + String[] strs = new String[n]; + System.out.println("Enter the strings one by one:"); + for (int i = 0; i < n; i++) { + strs[i] = sc.nextLine(); + } + + // Call the function + String result = longestCommonPrefix(strs); + System.out.println("Longest Common Prefix: " + result); + + sc.close(); + } + + public static String longestCommonPrefix(String[] strs) { + if (strs == null || strs.length == 0) { + return ""; + } + + Arrays.sort(strs); // Sort the array + + String first = strs[0]; + String last = strs[strs.length - 1]; + + int i = 0; + while (i < first.length() && i < last.length() && first.charAt(i) == last.charAt(i)) { + i++; + } + + return first.substring(0, i); + } +} diff --git a/java/LongestCommonSubsequence.java b/java/LongestCommonSubsequence.java new file mode 100644 index 00000000..faf1e48a --- /dev/null +++ b/java/LongestCommonSubsequence.java @@ -0,0 +1,75 @@ +/* +Longest Common Subsequence (LCS) :- https://leetcode.com/problems/longest-common-subsequence/description/ + +Problem Statement: +Given two strings text1 and text2, return the length of their longest common subsequence. +A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters. +A common subsequence of two strings is a subsequence that is common to both strings. +If there is no common subsequence, return 0. + +Examples: +Input: text1 = "abcde", text2 = "ace" +Output: 3 +Explanation: The longest common subsequence is "ace" and its length is 3. + +Input: text1 = "abc", text2 = "abc" +Output: 3 +Explanation: The longest common subsequence is "abc" and its length is 3. + +Input: text1 = "abc", text2 = "def" +Output: 0 + +Algorithm Description: +This algorithm computes the length of the longest common subsequence between two strings using dynamic programming. +It builds a 2D table where each cell dp[i][j] represents the length of the LCS of the first i characters of text1 and the first j characters of text2. +If the current characters match, the LCS length increases by 1; otherwise, it takes the maximum from skipping a character from either string. + +Use Cases: +- Comparing DNA, RNA, or protein sequences in bioinformatics +- File or version comparison tools (diff utilities) +- Text similarity and plagiarism detection + +Time Complexity: O(n*m) +- Where n and m are the lengths of the two input strings. Each cell in the dp table is filled once. + +Space Complexity: O(n*m) +- The dp table of size (n+1) x (m+1) is used to store intermediate results. +*/ + +public class LongestCommonSubsequence { + public static void main(String[] args) { + String s = "abcde", t = "ace"; + LongestCommonSubsequence lcs = new LongestCommonSubsequence(); + System.out.println(lcs.longestCommonSubsequence(s, t)); // Output: 3 + + // Additional test cases + System.out.println(lcs.longestCommonSubsequence("abc", "abc")); // Output: 3 + System.out.println(lcs.longestCommonSubsequence("abc", "def")); // Output: 0 + System.out.println(lcs.longestCommonSubsequence("", "abc")); // Output: 0 (edge case: empty string) + System.out.println(lcs.longestCommonSubsequence("abc", "")); // Output: 0 (edge case: empty string) + } + + /** + * Calculates the length of the longest common subsequence between two strings. + * @param s First input string + * @param t Second input string + * @return Length of the longest common subsequence + */ + public int longestCommonSubsequence(String s, String t) { + int n = s.length(), m = t.length(); + int[][] dp = new int[n+1][m+1]; + + // Build the dp table bottom-up + for(int i = 1; i <= n; i++) { + for(int j = 1; j <= m; j++) { + if(s.charAt(i-1) == t.charAt(j-1)) { + dp[i][j] = 1 + dp[i-1][j-1]; // Characters match, extend LCS + } + else { + dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); // Skip one character from either string + } + } + } + return dp[n][m]; + } +} diff --git a/java/LongestIncreasingSubsequence.java b/java/LongestIncreasingSubsequence.java new file mode 100644 index 00000000..a7b15d63 --- /dev/null +++ b/java/LongestIncreasingSubsequence.java @@ -0,0 +1,33 @@ +import java.util.*; + +public class LongestIncreasingSubsequence { + + public static int lengthOfLIS(int[] nums) { + if (nums == null || nums.length == 0) return 0; + + + int[] tail = new int[nums.length]; + int size = 0; + + for (int num : nums) { + + int i = Arrays.binarySearch(tail, 0, size, num); + + + if (i < 0) i = -(i + 1); + + tail[i] = num; + + + if (i == size) size++; + } + + return size; + } + + + public static void main(String[] args) { + int[] nums = {10, 9, 2, 5, 3, 7, 101, 18}; + System.out.println("Length of Longest Increasing Subsequence: " + lengthOfLIS(nums)); + } +} diff --git a/java/LongestPalindromicSubsequence.java b/java/LongestPalindromicSubsequence.java new file mode 100644 index 00000000..e2a42ce9 --- /dev/null +++ b/java/LongestPalindromicSubsequence.java @@ -0,0 +1,73 @@ +/* +Longest Palindromic Subsequence + +Problem Statement: +Given a string s, find the length of its longest palindromic subsequence. +A subsequence is a sequence that can be derived from another sequence by deleting some or no elements without changing the order of the remaining elements. +A palindromic subsequence is a subsequence that reads the same forward and backward. + +Examples: +Input: s = "bbbab" +Output: 4 +Explanation: One possible longest palindromic subsequence is "bbbb". + +Input: s = "cbbd" +Output: 2 +Explanation: One possible longest palindromic subsequence is "bb". + +Algorithm Description: +This algorithm computes the length of the longest palindromic subsequence in a string using dynamic programming. +It leverages the fact that the longest palindromic subsequence of a string s is the same as the longest common subsequence (LCS) between s and its reverse. +A 2D DP table is constructed where dp[i][j] represents the length of the LCS between the first i characters of s and the first j characters of its reverse. +If the characters match, the LCS length increases by 1; otherwise, it takes the maximum from skipping a character from either string. + +Use Cases: +- DNA/RNA sequence analysis for palindromic patterns +- Text analysis and pattern recognition +- Data compression and error correction + +Time Complexity: O(n^2) +- Where n is the length of the input string. Each cell in the dp table is filled once. + +Space Complexity: O(n^2) +- The dp table of size (n+1) x (n+1) is used to store intermediate results. +*/ + +public class LongestPalindromicSubsequence { + public static void main(String[] args) { + String s = "bbbab"; + LongestPalindromicSubsequence lps = new LongestPalindromicSubsequence(); + System.out.println(lps.longestPalindromeSubseq(s)); // Output: 4 + + // Additional test cases + System.out.println(lps.longestPalindromeSubseq("cbbd")); // Output: 2 + System.out.println(lps.longestPalindromeSubseq("a")); // Output: 1 (single character) + System.out.println(lps.longestPalindromeSubseq("abcde")); // Output: 1 (no repeating characters) + System.out.println(lps.longestPalindromeSubseq("")); // Output: 0 (empty string) + } + + /** + * Calculates the length of the longest palindromic subsequence in a string. + * Uses the LCS approach between the string and its reverse. + * @param s Input string + * @return Length of the longest palindromic subsequence + */ + public int longestPalindromeSubseq(String s) { + String t = new StringBuilder(s).reverse().toString(); // Reverse of s + int n = s.length(); + int[][] dp = new int[n+1][n+1]; // dp[i][j]: LCS length for s[0..i-1] and t[0..j-1] + + // Build the dp table bottom-up + for(int i = 1; i <= n; i++) { + for(int j = 1; j <= n; j++) { + if(s.charAt(i-1) == t.charAt(j-1)) { + dp[i][j] = 1 + dp[i-1][j-1]; // Characters match, extend LCS + } + else { + dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); // Skip one character from either string + } + } + } + return dp[n][n]; + } +} diff --git a/java/LongestSubstring.class b/java/LongestSubstring.class new file mode 100644 index 00000000..53c9da0e Binary files /dev/null and b/java/LongestSubstring.class differ diff --git a/java/LongestSubstring.java b/java/LongestSubstring.java new file mode 100644 index 00000000..3d15ca70 --- /dev/null +++ b/java/LongestSubstring.java @@ -0,0 +1,21 @@ +public class LongestSubstring { + public static int lengthOfLongestSubstring(String s) { + int[] lastIndex = new int[128]; // ASCII + for (int i = 0; i < 128; i++) lastIndex[i] = -1; + + int maxLen = 0, start = 0; + for (int end = 0; end < s.length(); end++) { + char c = s.charAt(end); + if (lastIndex[c] >= start) { + start = lastIndex[c] + 1; + } + lastIndex[c] = end; + maxLen = Math.max(maxLen, end - start + 1); + } + return maxLen; + } + + public static void main(String[] args) { + System.out.println(lengthOfLongestSubstring("abcabcbb")); // Output: 3 + } +} diff --git a/java/Longest_substring_with_distinct_characters.java b/java/Longest_substring_with_distinct_characters.java new file mode 100644 index 00000000..f1a6df44 --- /dev/null +++ b/java/Longest_substring_with_distinct_characters.java @@ -0,0 +1,36 @@ +// Problem: Longest Substring with Distinct Characters +// Objective: Find the length of the longest substring without repeating characters. +// Approach: Sliding Window + HashSet +// Time Complexity: O(n) +// Space Complexity: O(min(n, charset size)) + +import java.util.HashSet; + +public class Longest_substring_with_distinct_characters { + + public static int longestUniqueSubstr(String s) { + int start = 0, max = 0; + HashSet set = new HashSet<>(); + + for (int end = 0; end < s.length(); end++) { + // If character already exists in the set, shrink the window from the left + while (set.contains(s.charAt(end))) { + set.remove(s.charAt(start)); + start++; + } + + // Add current character to set + set.add(s.charAt(end)); + + // Update max length + max = Math.max(max, end - start + 1); + } + return max; + } + + // Example Test + public static void main(String[] args) { + String s = "abcabcbb"; + System.out.println("Length of longest substring: " + longestUniqueSubstr(s)); + } +} diff --git a/java/Main.java b/java/Main.java index da10602d..3a130bf6 100644 --- a/java/Main.java +++ b/java/Main.java @@ -2,6 +2,27 @@ * A driver class to demonstrate the functionality of BinaryTree and BinarySearchTree. */ public class Main { + int data; + Node left, right; + + public void Node(int data) { + this.data = data; + this.left = this.right = null; + } + public void preOrder(Node node) { + if (node != null) { + System.out.print(node.data + " "); + preOrder(node.left); + preOrder(node.right); + } + } + public void inOrder(Node node) { + if (node != null) { + inOrder(node.left); + System.out.print(node.data + " "); + inOrder(node.right); + } + } public static void main(String[] args) { System.out.println("--- Binary Tree Demonstration ---"); BinaryTree tree = new BinaryTree(); diff --git a/java/MajorityFrequencyCharacters.java b/java/MajorityFrequencyCharacters.java new file mode 100644 index 00000000..50eef00b --- /dev/null +++ b/java/MajorityFrequencyCharacters.java @@ -0,0 +1,29 @@ +//#leetcodeProblem number--3692 +import java.util.*; + +class Solution { + public String majorityFrequencyGroup(String s) { + Map freq = new HashMap<>(); + for(char ch : s.toCharArray()) + freq.put(ch, freq.getOrDefault(ch, 0) + 1); + + Map> group = new HashMap<>(); + for(Map.Entry entry : freq.entrySet()) + group.computeIfAbsent(entry.getValue(), k -> new ArrayList<>()).add(entry.getKey()); + + int maxgroupsize = 0, chosenFreq = 0; + for(Map.Entry> entry : group.entrySet()) { + int freqVal = entry.getKey(), size = entry.getValue().size(); + if(size > maxgroupsize || (size == maxgroupsize && freqVal > chosenFreq)) { + maxgroupsize = size; + chosenFreq = freqVal; + } + } + + List res = group.get(chosenFreq); + StringBuilder sb = new StringBuilder(); + for(char ch : res) + sb.append(ch); + return sb.toString(); + } +} diff --git a/java/MajorityNumber.java b/java/MajorityNumber.java index bfdb7726..574b9e75 100644 --- a/java/MajorityNumber.java +++ b/java/MajorityNumber.java @@ -1,30 +1,31 @@ import java.util.*; + +//This is Morris algorithm with O(n) time complexity and O(1) space complexity public class MajorityNumber { - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - System.out.print("Enter the size of the array: "); - int n = scanner.nextInt(); - int[] arr = new int[n]; - System.out.println("Enter the elements of the array:"); - for (int i = 0; i < n; i++) { - arr[i] = scanner.nextInt(); + + public static int majorityElement(int[] nums) { + int candidate = 0, count = 0; + + //Find candidate + for (int num : nums) { + if (count == 0) { + candidate = num; } - Map countMap = new HashMap<>(); - for (int num : arr) { - countMap.put(num, countMap.getOrDefault(num, 0) + 1); + count += (num == candidate) ? 1 : -1; } - int majorityElement = -1; - for (Map.Entry entry : countMap.entrySet()) { - if (entry.getValue() > n / 2) { - majorityElement = entry.getKey(); - break; - } - } - if (majorityElement != -1) { - System.out.println("The majority element is: " + majorityElement); - } else { - System.out.println("No majority element found."); - } - scanner.close(); + + + count = 0; + for (int num : nums) { + if (num == candidate) count++; + } + return count > nums.length / 2 ? candidate : -1; // -1 means no majority + } + + public static void main(String[] args) { + int[] nums = {2, 2, 1, 1, 1, 2, 2}; + System.out.println("Majority Element = " + majorityElement(nums)); } + + } diff --git a/java/MajorityVoting.java b/java/MajorityVoting.java new file mode 100644 index 00000000..7709c9ae --- /dev/null +++ b/java/MajorityVoting.java @@ -0,0 +1,35 @@ +import java.io.*; + +class MajorityElementFinder { + + public static int findMajority(int[] nums) { + int count = 0, candidate = -1; + + for (int index = 0; index < nums.length; index++) { + if (count == 0) { + candidate = nums[index]; + count = 1; + } else { + if (nums[index] == candidate) + count++; + else + count--; + } + } + + count = 0; + for (int index = 0; index < nums.length; index++) { + if (nums[index] == candidate) + count++; + } + if (count > (nums.length / 2)) + return candidate; + return -1; + } + + public static void main(String[] args) { + int arr[] = { 1, 1, 1, 1, 2, 3, 4 }; + int majority = findMajority(arr); + System.out.println("The majority element is: " + majority); + } +} diff --git a/java/Majority_element.java b/java/Majority_element.java new file mode 100644 index 00000000..2e730258 --- /dev/null +++ b/java/Majority_element.java @@ -0,0 +1,26 @@ +public class Majority_element { + public static void main(String[] args) { + int[] nums = {2, 7, 11, 15}; + int target = 9; + Solution sol = new Solution(); + sol.twoSum(nums, target); + } +} + +class Solution { + public int[] twoSum(int[] nums, int target) { + + int add = 0, n = nums.length; + int i = 0; + + while (i < n - 1) { // Prevent out-of-bounds + add = nums[i] + nums[i + 1]; + if (add == target) { + System.out.print(nums[i]); + System.out.println(nums[i + 1]); + } + i++; + } + return null; + } +} \ No newline at end of file diff --git a/java/MathUtils.java b/java/MathUtils.java new file mode 100644 index 00000000..5cf9f9ec --- /dev/null +++ b/java/MathUtils.java @@ -0,0 +1,27 @@ +/** + * MathUtils - Common mathematical helper functions + * Author: Prince Yadav + * @version 1.0 + * @since October 2025 + */ +public class MathUtils { + + // GCD using Euclidean Algorithm + public static int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } + + // LCM using GCD + public static int lcm(int a, int b) { + return (a / gcd(a, b)) * b; + } + + // Check if number is prime + public static boolean isPrime(int n) { + if (n <= 1) return false; + for (int i = 2; i * i <= n; i++) { + if (n % i == 0) return false; + } + return true; + } +} diff --git a/java/MathUtilsTest.java b/java/MathUtilsTest.java new file mode 100644 index 00000000..02caaaa4 --- /dev/null +++ b/java/MathUtilsTest.java @@ -0,0 +1,21 @@ +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class MathUtilsTest { + + @Test + void testGcd() { + assertEquals(6, MathUtils.gcd(54, 24)); + } + + @Test + void testLcm() { + assertEquals(216, MathUtils.lcm(54, 24)); + } + + @Test + void testIsPrime() { + assertTrue(MathUtils.isPrime(7)); + assertFalse(MathUtils.isPrime(10)); + } +} diff --git a/java/MaximumSubarraySum.java b/java/MaximumSubarraySum.java new file mode 100644 index 00000000..8625a182 --- /dev/null +++ b/java/MaximumSubarraySum.java @@ -0,0 +1,81 @@ +/** + * Maximum Subarray Sum - Kadane's Algorithm + * Finds the contiguous subarray with the largest sum. + */ +public class MaximumSubarraySum { + + // Kadane's Algorithm - O(n) time, O(1) space + public int maxSubarraySum(int[] arr) { + int maxSum = arr[0]; + int currentSum = arr[0]; + + for (int i = 1; i < arr.length; i++) { + currentSum = Math.max(arr[i], currentSum + arr[i]); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; + } + + // Returns both sum and the actual subarray indices + public Result maxSubarrayWithIndices(int[] arr) { + int maxSum = arr[0]; + int currentSum = arr[0]; + int start = 0, end = 0, tempStart = 0; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] > currentSum + arr[i]) { + currentSum = arr[i]; + tempStart = i; + } else { + currentSum += arr[i]; + } + + if (currentSum > maxSum) { + maxSum = currentSum; + start = tempStart; + end = i; + } + } + + return new Result(maxSum, start, end); + } + + // Helper class to return result with indices + public static class Result { + int sum; + int startIndex; + int endIndex; + + public Result(int sum, int startIndex, int endIndex) { + this.sum = sum; + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + @Override + public String toString() { + return "Sum: " + sum + ", Start: " + startIndex + ", End: " + endIndex; + } + } + + public static void main(String[] args) { + MaximumSubarraySum solver = new MaximumSubarraySum(); + + // Test case 1 + int[] arr1 = {2, 3, -8, 7, -1, 2, 3}; + System.out.println("Array: [2, 3, -8, 7, -1, 2, 3]"); + System.out.println("Max sum: " + solver.maxSubarraySum(arr1)); + System.out.println("With indices: " + solver.maxSubarrayWithIndices(arr1)); + + // Test case 2 + int[] arr2 = {-2, -4}; + System.out.println("\nArray: [-2, -4]"); + System.out.println("Max sum: " + solver.maxSubarraySum(arr2)); + + // Test case 3 + int[] arr3 = {5, 4, 1, 7, 8}; + System.out.println("\nArray: [5, 4, 1, 7, 8]"); + System.out.println("Max sum: " + solver.maxSubarraySum(arr3)); + } +} \ No newline at end of file diff --git a/java/MergeIntervals.java b/java/MergeIntervals.java new file mode 100644 index 00000000..b6ca4cc3 --- /dev/null +++ b/java/MergeIntervals.java @@ -0,0 +1,20 @@ +class Solution { + public int[][] merge(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); + List res = new ArrayList<>(); + int i; + + int curr[] = intervals[0]; + for(i=1; i< intervals.length; i++){ + if(curr[1]>=intervals[i][0]){ + curr[1] = Math.max(intervals[i][1],curr[1]); + } + else{ + res.add(curr); + curr = intervals[i]; + } + } + res.add(curr); + return res.toArray(new int[res.size()][]); + } +} \ No newline at end of file diff --git a/java/MergeSort.java b/java/MergeSort.java deleted file mode 100644 index 2956e4d5..00000000 --- a/java/MergeSort.java +++ /dev/null @@ -1,131 +0,0 @@ -import java.util.Arrays; -import java.util.Scanner; - -/** - * A class containing the implementation of the Merge Sort algorithm. - */ -public class MergeSort { - - /** - * The main method that sorts an array using the merge sort algorithm. - * - * @param arr The array to be sorted. - */ - public void sort(int[] arr) { - if (arr == null || arr.length <= 1) { - return; // Already sorted or nothing to sort - } - mergeSort(arr, 0, arr.length - 1); - } - - /** - * A recursive helper method that divides the array and calls the merge method. - * - * @param arr The array containing the subarrays to be sorted. - * @param left The starting index of the subarray. - * @param right The ending index of the subarray. - */ - private void mergeSort(int[] arr, int left, int right) { - if (left < right) { - // Find the middle point to divide the array into two halves - int middle = left + (right - left) / 2; - - // Recursively sort the first and second halves - mergeSort(arr, left, middle); - mergeSort(arr, middle + 1, right); - - // Merge the sorted halves - merge(arr, left, middle, right); - } - } - - /** - * Merges two sorted subarrays into a single sorted subarray. - * The first subarray is arr[left..middle]. - * The second subarray is arr[middle+1..right]. - * - * @param arr The main array. - * @param left The starting index of the first subarray. - * @param middle The ending index of the first subarray. - * @param right The ending index of the second subarray. - */ - private void merge(int[] arr, int left, int middle, int right) { - // Find sizes of two subarrays to be merged - int n1 = middle - left + 1; - int n2 = right - middle; - - // Create temporary arrays - int[] leftArray = new int[n1]; - int[] rightArray = new int[n2]; - - // Copy data to temporary arrays - System.arraycopy(arr, left, leftArray, 0, n1); - System.arraycopy(arr, middle + 1, rightArray, 0, n2); - - // Initial indexes of first and second subarrays - int i = 0, j = 0; - - // Initial index of the merged subarray - int k = left; - - // Merge the temporary arrays back into the original array arr[left..right] - while (i < n1 && j < n2) { - if (leftArray[i] <= rightArray[j]) { - arr[k] = leftArray[i]; - i++; - } else { - arr[k] = rightArray[j]; - j++; - } - k++; - } - - // Copy remaining elements of leftArray[], if any - while (i < n1) { - arr[k] = leftArray[i]; - i++; - k++; - } - - // Copy remaining elements of rightArray[], if any - while (j < n2) { - arr[k] = rightArray[j]; - j++; - k++; - } - } - - /** - * The main method to demonstrate the merge sort functionality interactively. - */ - public static void main(String[] args) { - Scanner scanner = new Scanner(System.in); - MergeSort sorter = new MergeSort(); - - System.out.println("--- Interactive Merge Sort ---"); - System.out.print("Enter the number of elements in the array: "); - int n = scanner.nextInt(); - - if (n <= 0) { - System.out.println("Array size must be positive. Exiting."); - scanner.close(); - return; - } - - int[] arr = new int[n]; - System.out.println("Enter the elements of the array:"); - for (int i = 0; i < n; i++) { - System.out.print("Element " + (i + 1) + ": "); - arr[i] = scanner.nextInt(); - } - - System.out.println("\nOriginal array: " + Arrays.toString(arr)); - - sorter.sort(arr); - - System.out.println("Sorted array: " + Arrays.toString(arr)); - - scanner.close(); - } -} - diff --git a/java/MergerSort.java b/java/MergerSort.java new file mode 100644 index 00000000..36f1d42b --- /dev/null +++ b/java/MergerSort.java @@ -0,0 +1,81 @@ +// Java program for Merge Sort + +class MergeSort { + + // Merges two subarrays of a[] + void merge(int a[], int l, int m, int r) + { + + int n1 = m - l + 1; + int n2 = r - m; + + int L[] = new int[n1]; + int R[] = new int[n2]; + + for (int i = 0; i < n1; ++i) + L[i] = a[l + i]; + + for (int j = 0; j < n2; ++j) + R[j] = a[m + 1 + j]; + + // Merge the temp arrays + // Initial indexes of first and second subarrays + int i = 0, j = 0; + + int k = l; + while (i < n1 && j < n2) { + if (L[i] <= R[j]) { + a[k] = L[i]; + i++; + } + else { + a[k] = R[j]; + j++; + } + k++; + } + + while (i < n1) { + a[k] = L[i]; + i++; + k++; + } + + while (j < n2) { + a[k] = R[j]; + j++; + k++; + } + } + + // Main function that sorts a[l..r] using + // merge() + void sort(int a[], int l, int r) + { + if (l < r) { + + int m = (l + r) / 2; + + // Sort first and second halves + sort(a, l, m); + sort(a, m + 1, r); + + // Merge the sorted halves + merge(a, l, m, r); + } + } + + // Driver method + public static void main(String args[]) + { + int a[] = { 12, 11, 13, 5, 6, 7 }; + + // Calling of Merge Sort + MergeSort ob = new MergeSort(); + ob.sort(a, 0, a.length - 1); + + int n = a.length; + for (int i = 0; i < n; ++i) + System.out.print(a[i] + " "); + } +} diff --git a/java/MinimumWindowSubstring.java b/java/MinimumWindowSubstring.java new file mode 100644 index 00000000..e86072ec --- /dev/null +++ b/java/MinimumWindowSubstring.java @@ -0,0 +1,60 @@ +import java.util.*; + +/** + * Minimum Window Substring - Sliding Window Approach + * Find smallest substring containing all characters of pattern. + */ +public class MinimumWindowSubstring { + + public String minWindow(String s, String p) { + if (s.length() < p.length()) return ""; + + Map pCount = new HashMap<>(); + for (char c : p.toCharArray()) { + pCount.put(c, pCount.getOrDefault(c, 0) + 1); + } + + int left = 0, minLen = Integer.MAX_VALUE, minStart = 0; + int required = pCount.size(), formed = 0; + Map windowCount = new HashMap<>(); + + for (int right = 0; right < s.length(); right++) { + char c = s.charAt(right); + windowCount.put(c, windowCount.getOrDefault(c, 0) + 1); + + if (pCount.containsKey(c) && windowCount.get(c).intValue() == pCount.get(c).intValue()) { + formed++; + } + + while (left <= right && formed == required) { + if (right - left + 1 < minLen) { + minLen = right - left + 1; + minStart = left; + } + + char leftChar = s.charAt(left); + windowCount.put(leftChar, windowCount.get(leftChar) - 1); + if (pCount.containsKey(leftChar) && windowCount.get(leftChar) < pCount.get(leftChar)) { + formed--; + } + left++; + } + } + + return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen); + } + + public static void main(String[] args) { + MinimumWindowSubstring solution = new MinimumWindowSubstring(); + + // Test case 1 + String s1 = "timetopractice", p1 = "toc"; + System.out.println("s = \"" + s1 + "\", p = \"" + p1 + "\""); + System.out.println("Result: \"" + solution.minWindow(s1, p1) + "\""); // "toprac" + + // Test case 2 + String s2 = "zoomlazapzo", p2 = "oza"; + System.out.println("\ns = \"" + s2 + "\", p = \"" + p2 + "\""); + System.out.println("Result: \"" + solution.minWindow(s2, p2) + "\""); // "apzo" + } +} \ No newline at end of file diff --git a/java/MissingNumber.java b/java/MissingNumber.java new file mode 100644 index 00000000..b1c79f58 --- /dev/null +++ b/java/MissingNumber.java @@ -0,0 +1,96 @@ +/** + * Solution for finding missing number in array containing n-1 elements + * from range 1 to N. + * + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * @author Prince Yadav + * @date October 2025 + */ +public class MissingNumber { + + /** + * Finds missing number using mathematical sum formula + * Formula: Sum of first N natural numbers = N * (N + 1) / 2 + * + * @param arr Array containing n-1 numbers from 1 to N + * @param N The upper limit of the range + * @return The missing number + * @throws IllegalArgumentException if array is null or N is invalid + */ + public static int findMissingNumberSumFormula(int[] arr, int N) { + if (arr == null || N < 1) { + throw new IllegalArgumentException("Invalid input"); + } + + int totalSum = N * (N + 1) / 2; + int arrSum = 0; + for (int num : arr) { + arrSum += num; + } + return totalSum - arrSum; + } + + /** + * Alternative approach using XOR for better overflow handling + * XOR properties: a ^ a = 0, a ^ 0 = a + * + * @param arr Array containing n-1 numbers + * @param N Upper limit + * @return Missing number + */ + public static int findMissingNumberXOR(int[] arr, int N) { + if (arr == null || N < 1) { + throw new IllegalArgumentException("Invalid input"); + } + + int xor = 0; + + // XOR all array elements + for (int num : arr) { + xor ^= num; + } + + // XOR with all numbers from 1 to N + for (int i = 1; i <= N; i++) { + xor ^= i; + } + + return xor; + } + + /** + * Test cases demonstrating both approaches + */ + public static void main(String[] args) { + // Test Case 1: Basic case + int[] arr1 = { 2, 3, 1, 5 }; + int N1 = 5; + System.out.println("Test 1 - Sum Formula: " + + findMissingNumberSumFormula(arr1, N1)); // Expected: 4 + System.out.println("Test 1 - XOR Method: " + + findMissingNumberXOR(arr1, N1)); // Expected: 4 + + // Test Case 2: Missing first element + int[] arr2 = { 2, 3, 4, 5 }; + int N2 = 5; + System.out.println("\nTest 2 - Sum Formula: " + + findMissingNumberSumFormula(arr2, N2)); // Expected: 1 + + // Test Case 3: Missing last element + int[] arr3 = { 1, 2, 3, 4 }; + int N3 = 5; + System.out.println("\nTest 3 - Sum Formula: " + + findMissingNumberSumFormula(arr3, N3)); // Expected: 5 + + // Test Case 4: Large numbers + int[] arr4 = new int[99]; + for (int i = 0; i < 99; i++) { + arr4[i] = i + 1; // 1 to 99 + } + int N4 = 100; + System.out.println("\nTest 4 - Large array: " + + findMissingNumberSumFormula(arr4, N4)); // Expected: 100 + } +} \ No newline at end of file diff --git a/java/MoveZeros copy.java b/java/MoveZeros copy.java new file mode 100644 index 00000000..96d0c7bb --- /dev/null +++ b/java/MoveZeros copy.java @@ -0,0 +1,22 @@ +//https://leetcode.com/problems/move-zeroes/ + +class Solution { + public void moveZeroes(int[] nums) { + int cnt = 0; + int index = 0; + for(int i=0 ; i < nums.length ; i++){ + if(nums[i] == 0) cnt++; + else{ + nums[index] = nums[i]; + index++; + } + + } + + for(int i=nums.length-1 ; i>=nums.length - cnt ; i--){ + nums[i] = 0; + } + + for(int i=0 ; i < nums.length ; i++) System.out.print(nums[i]+" "); + } +} diff --git a/java/MultiplicationTable.class b/java/MultiplicationTable.class new file mode 100644 index 00000000..13a38720 Binary files /dev/null and b/java/MultiplicationTable.class differ diff --git a/java/MultiplicationTable.java b/java/MultiplicationTable.java new file mode 100644 index 00000000..3fa8f2dd --- /dev/null +++ b/java/MultiplicationTable.java @@ -0,0 +1,21 @@ +import java.util.Scanner; + +public class MultiplicationTable { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + System.out.print("Enter a number to print its multiplication table: "); + int number = sc.nextInt(); + + System.out.print("Enter how many multiples you want: "); + int limit = sc.nextInt(); + + System.out.println("\nMultiplication Table of " + number + ":"); + + for (int i = 1; i <= limit; i++) { + System.out.println(number + " x " + i + " = " + (number * i)); + } + + sc.close(); + } +} diff --git a/java/NQueens.java b/java/NQueens.java new file mode 100644 index 00000000..3db429b5 --- /dev/null +++ b/java/NQueens.java @@ -0,0 +1,68 @@ +public class NQueens { + static int N = 8; // You can change this for different N + + // Function to print the board + static void printBoard(int board[][]) { + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) + System.out.print((board[i][j] == 1 ? "Q " : ". ")); + System.out.println(); + } + System.out.println(); + } + + // Check if queen can be placed + static boolean isSafe(int board[][], int row, int col) { + int i, j; + + // Check this row on left + for (i = 0; i < col; i++) + if (board[row][i] == 1) + return false; + + // Check upper diagonal + for (i = row, j = col; i >= 0 && j >= 0; i--, j--) + if (board[i][j] == 1) + return false; + + // Check lower diagonal + for (i = row, j = col; i < N && j >= 0; i++, j--) + if (board[i][j] == 1) + return false; + + return true; + } + + // Solve using backtracking + static boolean solveNQUtil(int board[][], int col) { + if (col >= N) { + printBoard(board); + return true; + } + + boolean res = false; + for (int i = 0; i < N; i++) { + if (isSafe(board, i, col)) { + board[i][col] = 1; + + // Recursion + res = solveNQUtil(board, col + 1) || res; + + // Backtrack + board[i][col] = 0; + } + } + return res; + } + + static void solveNQ() { + int board[][] = new int[N][N]; + if (!solveNQUtil(board, 0)) { + System.out.println("Solution does not exist"); + } + } + + public static void main(String args[]) { + solveNQ(); + } +} diff --git a/java/NQueens2.java b/java/NQueens2.java new file mode 100644 index 00000000..d2c4343a --- /dev/null +++ b/java/NQueens2.java @@ -0,0 +1,57 @@ +import java.util.ArrayList; +import java.util.List; + +public class NQueens2{ + static int ans=0; + public static void main(String[] args) { + int n = 4; + System.out.println(totalNQueens(n)); + } + public static int totalNQueens(int n) { + List board = new ArrayList<>(); + StringBuilder s = new StringBuilder(); + for(int i=0;i board,int n){ + if(col==n){ + ans++; + return; + } + for(int row = 0;row board ,int n){ + int temprow = row; + int tempcol = col; + + while(row>=0 && col>=0){ + if(board.get(row--).charAt(col--)=='Q') return false; + } + row=temprow; + col=tempcol; + while(col>=0){ + if(board.get(row).charAt(col--)=='Q') return false; + } + row=temprow; + col=tempcol; + while(row=0){ + if(board.get(row++).charAt(col--)=='Q') return false; + } + return true; + } +} \ No newline at end of file diff --git a/java/Neon_Number.java b/java/Neon_Number.java new file mode 100644 index 00000000..c02aff64 --- /dev/null +++ b/java/Neon_Number.java @@ -0,0 +1,31 @@ +import java.util.Scanner; + +public class NeonNumberChecker { + + public static void main(String[] args) { + Scanner inputScanner = new Scanner(System.in); + + System.out.print("Enter a number to check if it's a Neon number: "); + int number = inputScanner.nextInt(); + + // Calculate the square of the number + int square = number * number; + int sumOfDigitsOfSquare = 0; + + // Calculate the sum of the digits of the square + while (square > 0) { + int digit = square % 10; // Get the last digit + sumOfDigitsOfSquare += digit; // Add the digit to the sum + square /= 10; // Remove the last digit + } + + // Check if the sum of digits of the square equals the original number + if (sumOfDigitsOfSquare == number) { + System.out.println(number + " is a Neon number."); + } else { + System.out.println(number + " is not a Neon number."); + } + + inputScanner.close(); + } +} \ No newline at end of file diff --git a/java/NextGreaterElement.class b/java/NextGreaterElement.class new file mode 100644 index 00000000..9bbd4c5e Binary files /dev/null and b/java/NextGreaterElement.class differ diff --git a/java/NextGreaterElement.java b/java/NextGreaterElement.java new file mode 100644 index 00000000..4b46b5c7 --- /dev/null +++ b/java/NextGreaterElement.java @@ -0,0 +1,37 @@ +import java.util.Stack; + +public class NextGreaterElement { + + static void printNextGreaterElements(int[] arr) { + Stack stack = new Stack(); // using raw Stack for compatibility + int[] result = new int[arr.length]; + + // Traverse from right to left + for (int i = arr.length - 1; i >= 0; i--) { + // Pop smaller elements from stack + while (!stack.isEmpty() && (int) stack.peek() <= arr[i]) { + stack.pop(); + } + + // If stack is empty → no greater element + if (stack.isEmpty()) { + result[i] = -1; + } else { + result[i] = (int) stack.peek(); + } + + // Push current element into stack + stack.push(arr[i]); + } + + System.out.println("Element : Next Greater Element"); + for (int i = 0; i < arr.length; i++) { + System.out.println(arr[i] + " --> " + result[i]); + } + } + + public static void main(String[] args) { + int[] arr = { 4, 5, 2, 25, 7, 8 }; + printNextGreaterElements(arr); + } +} diff --git a/java/NextSmallerElement.java b/java/NextSmallerElement.java new file mode 100644 index 00000000..90fbb486 --- /dev/null +++ b/java/NextSmallerElement.java @@ -0,0 +1,24 @@ +public class NextSmallerElement { + public static void main(String[] args) { + int[] arr = {4, 8, 5, 2, 25}; + int[] result = nextSmallerElement(arr); + for (int val : result) { + System.out.print(val + " "); + } + } + + public static int[] nextSmallerElement(int[] arr) { + int n = arr.length; + int[] result = new int[n]; + java.util.Stack stack = new java.util.Stack<>(); + + for (int i = n - 1; i >= 0; i--) { + while (!stack.isEmpty() && stack.peek() >= arr[i]) { + stack.pop(); + } + result[i] = stack.isEmpty() ? -1 : stack.peek(); + stack.push(arr[i]); + } + return result; + } +} diff --git a/java/NonOverlappingIntervals.java b/java/NonOverlappingIntervals.java new file mode 100644 index 00000000..8e5e784c --- /dev/null +++ b/java/NonOverlappingIntervals.java @@ -0,0 +1,15 @@ +class Solution { + public int eraseOverlapIntervals(int[][] intervals) { + Arrays.sort(intervals, (a,b) -> Integer.compare(a[1],b[1])); + int count=0,i; + int[] curr=intervals[0]; + for(i=1; iintervals[i][0]) + count++; + else{ + curr[1]=intervals[i][1]; + } + } + return count; + } +} \ No newline at end of file diff --git a/java/OnlineExamSystem.java b/java/OnlineExamSystem.java new file mode 100644 index 00000000..36200209 --- /dev/null +++ b/java/OnlineExamSystem.java @@ -0,0 +1,106 @@ +// TASK 4 OIBSIP +import java.util.*; + +public class OnlineExamSystem { + private String username; + private String password; + private boolean isLoggedIn; + private int timeRemaining; + private int questionCount; + private int[] userAnswers; + private int[] correctAnswers; + + public OnlineExamSystem(String username, String password) { + this.username = username; + this.password = password; + System.out.println("Sucessfully You are registered! :)"); + this.isLoggedIn = false; + this.timeRemaining = 10; // in minutes + this.questionCount = 10; + this.userAnswers = new int[questionCount]; + this.correctAnswers = new int[questionCount]; + // initialize correct answers with random values (0 or 1) + for (int i = 0; i < questionCount; i++) { + correctAnswers[i] = (int) Math.round(Math.random()); + } + } + + public void login() { + System.out.println("Log in to give the Exam "); + Scanner scanner = new Scanner(System.in); + System.out.print("Username: "); + String inputUsername = scanner.nextLine(); + System.out.print("Password: "); + String inputPassword = scanner.nextLine(); + if (inputUsername.equals(username) && inputPassword.equals(password)) { + isLoggedIn = true; + System.out.println("Login successful Best of Luck Dear"); + } else { + System.out.println("Login failed. Please try again."); + } + } + + public void logout() { + isLoggedIn = false; + System.out.println("Logout successful."); + } + + public void startExam() { + if (!isLoggedIn) { + System.out.println("Please login first."); + return; + } + Scanner scanner = new Scanner(System.in); + System.out.println("You have " + timeRemaining + " minutes to complete the exam."); + for (int i = 0; i < questionCount; i++) { + System.out.println("Question " + (i + 1) + ":"); + System.out.println("1. Option 1"); + System.out.println("2. Option 2"); + System.out.print("Your answer (1 or 2): "); + int answer = scanner.nextInt(); + userAnswers[i] = answer; + } + + System.out.println("Would you like to submit? \n1:Yes \n2:NO "); + int n = scanner.nextInt(); + if (n == 1) { + submitExam(); + } else { + // auto-submit exam when time is up + try { + Thread.sleep(timeRemaining * 10 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + submitExam(); + } + + } + + } + + public void submitExam() { + if (!isLoggedIn) { + System.out.println("Please login first."); + return; + } + int score = 0; + for (int i = 0; i < questionCount; i++) { + if (userAnswers[i] == correctAnswers[i]) { + score++; + } + } + System.out.println("Your score is " + score + " out of " + questionCount + "."); + System.out.println("Best of luck :)"); + logout(); + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.println("Enter your username and password"); + String uName = sc.nextLine(); + String pWord = sc.nextLine(); + OnlineExamSystem examSystem = new OnlineExamSystem(uName, pWord); + examSystem.login(); + examSystem.startExam(); + } +} diff --git a/java/Palindrome.java b/java/Palindrome.java new file mode 100644 index 00000000..f33219c1 --- /dev/null +++ b/java/Palindrome.java @@ -0,0 +1,26 @@ +// Palindrom => racecar, noon, madam, 1223221, etc + +import java.util.*; + +public class Palindrome { + public static boolean isPalindrome(String str) { + for(int i=0; i 0) { + int digit = num % 10; + reverse = reverse * 10 + digit; + num /= 10; + } + + if (original == reverse) + System.out.println(original + " is a Palindrome"); + else + System.out.println(original + " is not a Palindrome"); + } +} diff --git a/java/PascalTriangle.java b/java/PascalTriangle.java new file mode 100644 index 00000000..68170bdd --- /dev/null +++ b/java/PascalTriangle.java @@ -0,0 +1,15 @@ +class Solution { + public List> generate(int numRows) { + List> ans = new ArrayList<>(); + + for(int i=0; i row = new ArrayList<>(Collections.nCopies(i+1,1)); + for(int j=1; j ans = new ArrayList<>(); + public ArrayList postOrder(Node root) { + // code here + if(root==null) return ans; + postOrder(root.left); + postOrder(root.right); + ans.add(root.data); + + return ans; + } +} + + +// Time Complexity: O(n) +// Auxiliary Space: O(n) diff --git a/java/Prime.java b/java/Prime.java index d6a1bf06..f3f6e3b4 100644 --- a/java/Prime.java +++ b/java/Prime.java @@ -4,22 +4,18 @@ public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter a positive integer: "); int number = scanner.nextInt(); - if (number <= 1) { - System.out.println(number + " is not a prime number."); - } else { - boolean isPrime = true; - for (int i = 2; i <= Math.sqrt(number); i++) { - if (number % i == 0) { - isPrime = false; - break; - } - } - if (isPrime) { - System.out.println(number + " is a prime number."); - } else { - System.out.println(number + " is not a prime number."); + boolean flag =true; + for(int i=2;i<=number/2;i++){ + if(number%i==0){ + flag=false; + }else{ + flag=true; } } - scanner.close(); + if(flag==true){ + System.out.println(number + " is a prime number"); + }else{ + System.out.println(number + " is not a prime number"); + } } } diff --git a/java/PrintingSpiral.java b/java/PrintingSpiral.java new file mode 100644 index 00000000..62460756 --- /dev/null +++ b/java/PrintingSpiral.java @@ -0,0 +1,65 @@ +import java.util.ArrayList; +import java.util.List; + +class Solution { + /** + * Given an m x n matrix, return all elements of the matrix in spiral order. + * * @param matrix The input m x n matrix. + * @return A list of elements in spiral order. + */ + public List spiralOrder(int[][] matrix) { + List result = new ArrayList<>(); + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { + return result; + } + + int numRows = matrix.length; + int numCols = matrix[0].length; + + // Initialize the four boundaries + int top = 0; + int bottom = numRows - 1; + int left = 0; + int right = numCols - 1; + + while (top <= bottom && left <= right) { + + // 1. Traverse Right (from left to right boundary on the current top row) + for (int col = left; col <= right; col++) { + result.add(matrix[top][col]); + } + top++; // Move the top boundary down + + // Check if all rows have been processed + if (top > bottom) break; + + // 2. Traverse Down (from new top to bottom boundary on the current right column) + for (int row = top; row <= bottom; row++) { + result.add(matrix[row][right]); + } + right--; // Move the right boundary in + + // Check if all columns have been processed + if (left > right) break; + + // 3. Traverse Left (from new right to left boundary on the current bottom row) + // This is done in reverse order + for (int col = right; col >= left; col--) { + result.add(matrix[bottom][col]); + } + bottom--; // Move the bottom boundary up + + // Check if all rows have been processed + if (top > bottom) break; + + // 4. Traverse Up (from new bottom to top boundary on the current left column) + // This is done in reverse order + for (int row = bottom; row >= top; row--) { + result.add(matrix[row][left]); + } + left++; // Move the left boundary in + } + + return result; + } +} \ No newline at end of file diff --git a/java/ProductOfArrayExceptSelf.java b/java/ProductOfArrayExceptSelf.java new file mode 100644 index 00000000..011f3543 --- /dev/null +++ b/java/ProductOfArrayExceptSelf.java @@ -0,0 +1,18 @@ +class Solution { + public int[] productExceptSelf(int[] nums) { + int ans[] =new int[nums.length]; + int prefix[] =new int[nums.length]; + int suffix[] =new int[nums.length]; + int i,n=nums.length; + prefix[0]=1; + suffix[n-1]=1; + for(i=1; i=0; i--) + suffix[i]=suffix[i+1]*nums[i+1]; + for(i=0; i queue = new PriorityQueue<>(); + + queue.add("India"); + queue.add("Germany"); + queue.add("USA"); + + System.out.println("Queue:"+queue); + + queue.remove(); + + System.out.println(queue); + + String head = queue.peek(); + System.out.println("Head:"+head); + + head = queue.poll(); + System.out.println("Removed head:"+head); + + System.out.println(queue); + } +} diff --git a/java/Recursion(Lavi)/ConvertStringToInteger.class b/java/Recursion(Lavi)/ConvertStringToInteger.class new file mode 100644 index 00000000..86e24795 Binary files /dev/null and b/java/Recursion(Lavi)/ConvertStringToInteger.class differ diff --git a/java/Recursion(Lavi)/ConvertStringToInteger.java b/java/Recursion(Lavi)/ConvertStringToInteger.java new file mode 100644 index 00000000..0ab20971 --- /dev/null +++ b/java/Recursion(Lavi)/ConvertStringToInteger.java @@ -0,0 +1,76 @@ +public class ConvertStringToInteger { + /** + * Convert a string to an integer without using built-in parsing functions. + * + * Constraints / Rules: + * 1. You may not use built-in functions like Integer.parseInt() or similar. + * 2. You may not use any form of loops (for, while, do-while). + * 3. You may not use any form of conditional statements (if, switch, ternary operator). + * 4. Your function should work for negative numbers. + * 5. If the string is invalid, return 0. + * 6. Only characters that should be allowed in the string are numeric digits from '0' + * through '9', possibly preceded by a single minus sign '-' at the start if the number + * is negative. A string that contains any other characters in it is considered invalid. + * 7. You may assume that the string will not have leading or trailing whitespace. + * 8. You may assume that if the string contains valid characters, then it represents an integer + * that can be successfully stored in an int; that is, its value will not exceed 2^31. + * 9. If the empty string is passed, your function should return 0. + * + * @param s - Input string representing an integer. + * @returns int - The integer value represented by the string. + */ + + /** + * Recursive helper method to convert a numeric string into an integer. + * + * @param s the input string + * @param idx current index being processed + * @param ans the accumulated integer value so far + * @return the integer value if valid, otherwise 0 + */ + public int helper(String s, int idx, int ans) { + if (idx == s.length()) { + return ans; + } + if (!(s.charAt(idx) >= '0' && s.charAt(idx) <= '9')) { + return 0; + } + int temp = s.charAt(idx) - '0'; + ans = ans * 10 + temp; + return helper(s, idx + 1, ans); + } + + /** + * Converts the given string into an integer, handling negatives and invalid inputs. + * + * @param s the input string representing an integer + * @return the integer value represented by the string, or 0 if invalid + */ + public int convertStringToInteger(String s) { + if (s.equals("")) { + return 0; + } + if (s.charAt(0) == '-') { + int ans = helper(s, 1, 0); + return -1 * ans; + } + return helper(s, 0, 0); + } + + + /** + * Main method for testing the ConvertStringToInteger class. + */ + public static void main(String[] args) { + ConvertStringToInteger converter = new ConvertStringToInteger(); + String[] testStrings = {"123", "-456", "0", "789a", "", "-0", "2147483647", "-2147483648"}; + int[] expectedResults = {123, -456, 0, 0, 0, 0, 2147483647, -2147483648}; + + // System.out.println(converter.convertStringToInteger(testStrings[0])); + + for (int i = 0; i < testStrings.length; i++) { + assert converter.convertStringToInteger(testStrings[i]) == expectedResults[i] : "Test case " + (i + 1) + " failed"; + } + System.out.println("All test cases passed"); + } +} \ No newline at end of file diff --git a/java/Recursion(Lavi)/CountPaths.class b/java/Recursion(Lavi)/CountPaths.class new file mode 100644 index 00000000..bbb1452e Binary files /dev/null and b/java/Recursion(Lavi)/CountPaths.class differ diff --git a/java/Recursion(Lavi)/CountPaths.java b/java/Recursion(Lavi)/CountPaths.java new file mode 100644 index 00000000..50d7e855 --- /dev/null +++ b/java/Recursion(Lavi)/CountPaths.java @@ -0,0 +1,48 @@ +import java.util.*; + +public class CountPaths { + /** + * Count the number of unique paths from (x, y) to (0, 0) in an m x n grid. + * + * @param m - Number of rows in the grid. + * @param n - Number of columns in the grid. + * @param x - Starting row position. + * @param y - Starting column position. + * @returns int - Number of unique paths from (x, y) to (0, 0). + */ + private int helper(int n, int m, int i, int j, int[][] dp) { + if (i < 0 || j < 0 || i >= n || j >= m) { + return 0; + } + if (i == 0 && j == 0) { + return 1; + } + if (dp[i][j] != -1) { + return dp[i][j]; + } + return dp[i][j] = helper(n, m, i - 1, j, dp) + helper(n, m, i, j - 1, dp); + } + + public int countPaths(int m, int n, int x, int y) { + if (x == 0 && y == 0) { + return 0; + } + int[][] dp = new int[n][m]; + for (int[] it : dp) { + Arrays.fill(it, -1); + } + return helper(n, m, x, y, dp); + } + + /** + * Main method for testing the CountPaths class. + */ + public static void main(String[] args) { + CountPaths cp = new CountPaths(); + + assert cp.countPaths(3, 3, 2, 2) == 6 : "Test case 1 failed"; + assert cp.countPaths(3, 3, 1, 1) == 2 : "Test case 2 failed"; + assert cp.countPaths(3, 3, 0, 0) == 0 : "Test case 3 failed"; + System.out.println("All test case passed"); + } +} diff --git a/java/Recursion(Lavi)/GenerateParenthesis.class b/java/Recursion(Lavi)/GenerateParenthesis.class new file mode 100644 index 00000000..dcac7ad7 Binary files /dev/null and b/java/Recursion(Lavi)/GenerateParenthesis.class differ diff --git a/java/Recursion(Lavi)/GenerateParenthesis.java b/java/Recursion(Lavi)/GenerateParenthesis.java new file mode 100644 index 00000000..cb091a31 --- /dev/null +++ b/java/Recursion(Lavi)/GenerateParenthesis.java @@ -0,0 +1,58 @@ +import java.util.*; + +public class GenerateParenthesis { + /** + * Given n pairs of parentheses, write a function to generate all combinations of well-formed + * parentheses. + * + * Constraints: + * 1. 1 <= n <= 8 + * 2. The solution set must not contain duplicate combinations. + * + * Example: + * Input: n = 3 + * Output: ["((()))","(()())","(())()","()(())","()()()"] + * + * @param n - Number of pairs of parentheses. + * @returns List - A list of all combinations of well-formed parentheses. + */ + private void helper(int n, List res, StringBuilder sb, int open, int close) { + if (sb.length() == 2 * n) { + res.add(new String(sb)); + } + if (open < n) { + sb.append("("); + helper(n, res, sb, open + 1, close); + sb.deleteCharAt(sb.length() - 1); + } + if (close < open) { + sb.append(")"); + helper(n, res, sb, open, close + 1); + sb.deleteCharAt(sb.length() - 1); + } + } + + public List generateParenthesis(int n) { + if (n == 0) { + return new ArrayList<>(); + } + List res = new ArrayList<>(); + helper(n, res, new StringBuilder(), 0, 0); + return res; + } + + /** + * Main method for testing the GenerateParenthesis class. + */ + public static void main(String[] args) { + GenerateParenthesis gp = new GenerateParenthesis(); + int n = 3; + List result = gp.generateParenthesis(n); + List expected = Arrays.asList("((()))", "(()())", "(())()", "()(())", "()()()"); + + assert result.size() == expected.size() && result.containsAll(expected) + : "Test case failed"; + System.out.println("Passed"); + } +} + diff --git a/java/Recursion(Lavi)/HumanPyramid.class b/java/Recursion(Lavi)/HumanPyramid.class new file mode 100644 index 00000000..7556be3a Binary files /dev/null and b/java/Recursion(Lavi)/HumanPyramid.class differ diff --git a/java/Recursion(Lavi)/HumanPyramid.java b/java/Recursion(Lavi)/HumanPyramid.java new file mode 100644 index 00000000..a1deaa8f --- /dev/null +++ b/java/Recursion(Lavi)/HumanPyramid.java @@ -0,0 +1,84 @@ +import java.util.Arrays; +import java.util.List; +public class HumanPyramid { + /** + * A human pyramid is a formation of people where participants make a horizontal + * row along the ground, and each subsequent row is formed by standing on the shoulders + * of the row below. Each row had one less person than the row below it, and the topmost + * row has a single person. Example of a human pyramid with 4 rows: + * A + * / \ + * B C + * / \ / \ + * D E F + * / \ / \ / \ + * G H I J + * + * Each person in the pyramid has a weight, and each person supports their own weight + * plus half the weight of each person directly above them. For example, in the pyramid + * E supports half the weight supported by B and half the weight supported by C, in + * addition to their own weight. + * + * Given a human pyramid represented as a list of lists of integers, where each integer + * represents the weight of a person, write a function that calculates the total weight + * supported by the person at a given position in the pyramid. + * + * Constraints: + * 1. The pyramid will have at least 1 row and at most 100 rows. + * 2. Each person's weight will be a positive integer less than or equal to 300. + * 3. The position in the pyramid is given as a pair of integers (row, col), where row + * is the row index (0-indexed from the top) and col is the column index (0-indexed from the left). + * 4. You may assume that the given position is valid within the pyramid. + * 5. Your solution should be recursive and not use any loops. + * + * @param pyramid - A list of lists of integers representing the weights of people in the pyramid. + * @param row - The row index of the person whose supported weight is to be calculated. + * @param col - The column index of the person whose supported weight is to be calculated. + * @returns float - The total weight supported by the person at the given position. + */ + private double helper(List> pyramid, int row, int col) { + if (row == 0 && col == 0) { + return pyramid.get(0).get(0); + } + double addOn = 0.0; + if (col == 0) { + addOn = 0.5 * helper(pyramid, row - 1, col); + } else if (row == col) { + addOn = 0.5 * helper(pyramid, row - 1, col - 1); + } else { + addOn = 0.5 * helper(pyramid, row - 1, col) + + 0.5 * helper(pyramid, row - 1, col - 1); + } + return pyramid.get(row).get(col) + addOn; + } + + public float totalWeightSupported(List> pyramid, int row, int col) { + // return helper(pyramid,row,col); + return (float) helper(pyramid, row, col); + } + + /** + * Main method for testing the HumanPyramid class. + */ + public static void main(String[] args) { + HumanPyramid hp = new HumanPyramid(); + List> pyramid = Arrays.asList( + Arrays.asList(51.18), + Arrays.asList(55.90, 131.25), + Arrays.asList(69.05, 133.66, 132.82), + Arrays.asList(53.43, 139.61, 134.06, 121.63) + ); + + assert Math.abs(hp.totalWeightSupported(pyramid, 0, 0) - 51.18) < 1e-2 : "Test case 1 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 1, 0) - 81.49) < 1e-2 : "Test case 2 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 1, 1) - 156.84) < 1e-2 : "Test case 3 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 2, 0) - 109.80) < 1e-2 : "Test case 4 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 2, 1) - 252.82) < 1e-2 : "Test case 5 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 2, 2) - 211.24) < 1e-2 : "Test case 6 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 3, 0) - 108.32) < 1e-2 : "Test case 7 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 3, 1) - 320.92) < 1e-2 : "Test case 8 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 3, 2) - 326.09) < 1e-2 : "Test case 9 failed"; + assert Math.abs(hp.totalWeightSupported(pyramid, 3, 3) - 227.25) < 1e-2 : "Test case 10 failed"; + System.out.println("Passed"); + } +} diff --git a/java/Recursion(Lavi)/NQueens.class b/java/Recursion(Lavi)/NQueens.class new file mode 100644 index 00000000..4c0a8f3e Binary files /dev/null and b/java/Recursion(Lavi)/NQueens.class differ diff --git a/java/Recursion(Lavi)/NQueens.java b/java/Recursion(Lavi)/NQueens.java new file mode 100644 index 00000000..bec5fb65 --- /dev/null +++ b/java/Recursion(Lavi)/NQueens.java @@ -0,0 +1,87 @@ +public class NQueens { + /** + * The n-queens puzzle is the problem of placing n queens on an n x n chessboard such that no two + * queens attack each other. Given an integer n, return the number of distinct solutions to the + * n-queens puzzle. + * + * Example: + * Input n = 4 + * Output: 2 + * Explanation: There are two distinct solutions to the 4-queens puzzle as shown below. + * + * [ + * [".Q..", // Solution 1 + * "...Q", + * "Q...", + * "..Q."], + * ["..Q.", // Solution 2 + * "Q...", + * "...Q", + * ".Q.." + * ] + * ] + * + * Constraints: + * 1. 1 <= n <= 9 + * 2. You may assume that n is a positive integer. + * + * @param n - The size of the chessboard and the number of queens to place. + * @returns int - The number of distinct solutions to the n-queens puzzle. + **/ + public int totalNQueens(int n) { + return placeQueens(new boolean[n][n], n, 0); + } + + private int placeQueens(boolean[][] board, int n, int r) { + if (r == n) { + return 1; // found one valid arrangement + } + + int count = 0; + for (int c = 0; c < n; c++) { + if (isSafe(board, r, c, n)) { + board[r][c] = true; + count += placeQueens(board, n, r + 1); + board[r][c] = false; // backtrack + } + } + return count; + } + + private boolean isSafe(boolean[][] board, int r, int c, int n) { + // check column + for (int i = 0; i < r; i++) { + if (board[i][c]) { + return false; + } + } + + // check left diagonal + for (int i = r - 1, j = c - 1; i >= 0 && j >= 0; i--, j--) { + if (board[i][j]) { + return false; + } + } + + // check right diagonal + for (int i = r - 1, j = c + 1; i >= 0 && j < n; i--, j++) { + if (board[i][j]) { + return false; + } + } + + return true; + } + + /** + * Main method for testing the NQueens class. + */ + public static void main(String[] args) { + NQueens nQueens = new NQueens(); + assert nQueens.totalNQueens(4) == 2 : "Test case 1 failed"; + assert nQueens.totalNQueens(1) == 1 : "Test case 2 failed"; + assert nQueens.totalNQueens(5) == 10 : "Test case 3 failed"; + System.out.println("all test case passed"); + } +} + diff --git a/java/Recursion(Lavi)/SearchMatrix.class b/java/Recursion(Lavi)/SearchMatrix.class new file mode 100644 index 00000000..365b2498 Binary files /dev/null and b/java/Recursion(Lavi)/SearchMatrix.class differ diff --git a/java/Recursion(Lavi)/SearchMatrix.java b/java/Recursion(Lavi)/SearchMatrix.java new file mode 100644 index 00000000..dccd5da1 --- /dev/null +++ b/java/Recursion(Lavi)/SearchMatrix.java @@ -0,0 +1,73 @@ +public class SearchMatrix { + /** + * Search a 2D matrix. + * + * You are given an m x n integer matrix matrix with the following two properties: + * 1. Each row is sorted in non-decreasing order. + * 2. Each column is sorted in non-decreasing order. + * + * Given an integer target, return true if target is in matrix or false otherwise. + * + * Constraints: + * 1. m == matrix.length + * 2. n == matrix[i].length + * 3. 1 <= m, n <= 300 + * 4. -10^9 <= matrix[i][j] <= 10^9 + * + * @param matrix - A 2D list of integers representing the matrix. + * @param target - The integer to search for in the matrix. + * @returns boolean - True if target is found in the matrix, otherwise false. + */ + private boolean helper(int[][] matrix, int target, int row, int col) { + if (row >= matrix.length || col < 0) { + return false; + } + if (matrix[row][col] == target) { + return true; + } else if (matrix[row][col] < target) { + if (helper(matrix, target, row + 1, col)) { + return true; + } + } + return helper(matrix, target, row, col - 1); + } + + /** + * Searches for a target value in a 2D sorted matrix. + * + * @param matrix the input 2D sorted matrix + * @param target the value to search for + * @return true if the target exists in the matrix, otherwise false + */ + public boolean searchMatrix(int[][] matrix, int target) { + int m = matrix[0].length; + return helper(matrix, target, 0, m - 1); + } + + /** + * Main method for testing the SearchMatrix class. + */ + public static void main(String[] args) { + SearchMatrix sm = new SearchMatrix(); + + int[][] matrix1 = { + {1, 4, 7, 11, 15}, + {2, 5, 8, 12, 19}, + {3, 6, 9, 16, 22}, + {10, 13, 14, 17, 24}, + {18, 21, 23, 26, 30} + }; + assert sm.searchMatrix(matrix1, 5) == true : "Test case 1 failed"; + assert sm.searchMatrix(matrix1, 20) == false : "Test case 2 failed"; + + int[][] matrix2 = { + {-1, 3} + }; + assert sm.searchMatrix(matrix2, 3) == true : "Test case 3 failed"; + assert sm.searchMatrix(matrix2, -1) == true : "Test case 4 failed"; + assert sm.searchMatrix(matrix2, 0) == false : "Test case 5 failed"; + + System.out.println("Passed"); + } +} + diff --git a/java/Recursion(Lavi)/SubSequences.class b/java/Recursion(Lavi)/SubSequences.class new file mode 100644 index 00000000..973d37b6 Binary files /dev/null and b/java/Recursion(Lavi)/SubSequences.class differ diff --git a/java/Recursion(Lavi)/SubSequences.java b/java/Recursion(Lavi)/SubSequences.java new file mode 100644 index 00000000..5552fc93 --- /dev/null +++ b/java/Recursion(Lavi)/SubSequences.java @@ -0,0 +1,64 @@ +public class SubSequences { + /** + * If S and T are strings, we say that S is a subsequence of T if all + * letters of S appear in T in the same order (not necessarily consecutively). + * For example, "ace" is a subsequence of "abcde" while "aec" is not. + * Given two strings S and T, checks whether S is a subsequence of T. + * + * Constraints: + * 1. Your solution should be recursive and not use any loops. + * 2. 0 <= len(S), len(T) <= 1000 + * 3. Strings are case-sensitive and contain only English letters. + * + * @param S - The subsequence string. + * @param T - The target string. + * @returns boolean - True if S is a subsequence of T, otherwise false. + **/ + /** + * Recursive helper method to check if string {@code t} is a subsequence of string {@code s}. + * + * @param t the target subsequence string + * @param s the source string + * @param i current index in {@code t} + * @param j current index in {@code s} + * @return true if {@code t} is a subsequence of {@code s}, otherwise false + */ + private boolean helper(String t, String s, int i, int j) { + if (i == t.length()) { + return true; + } + if (j == s.length()) { + return false; + } + if (t.charAt(i) == s.charAt(j)) { + if (helper(t, s, i + 1, j + 1)) { + return true; + } + } + return helper(t, s, i, j + 1); + } + + /** + * Checks whether string {@code t} is a subsequence of string {@code s}. + * + * @param t the target subsequence string + * @param s the source string + * @return true if {@code t} is a subsequence of {@code s}, otherwise false + */ + public boolean isSubsequence(String t, String s) { + return helper(t, s, 0, 0); + } + + /** + * Main method for testing the SubSequences class. + */ + public static void main(String[] args) { + SubSequences subsequences = new SubSequences(); + assert subsequences.isSubsequence("ace", "abcde") == true : "Test case 1 failed"; + assert subsequences.isSubsequence("aec", "abcde") == false : "Test case 2 failed"; + assert subsequences.isSubsequence("", "abcde") == true : "Test case 3 failed"; + assert subsequences.isSubsequence("abc", "") == false : "Test case 4 failed"; + assert subsequences.isSubsequence("abc", "ahbgdc") == true : "Test case 5 failed"; + assert subsequences.isSubsequence("axc", "ahbgdc") == false : "Test case 6 failed"; + } +} diff --git a/java/Recursion(Lavi)/ValidParenthesis.class b/java/Recursion(Lavi)/ValidParenthesis.class new file mode 100644 index 00000000..07495795 Binary files /dev/null and b/java/Recursion(Lavi)/ValidParenthesis.class differ diff --git a/java/Recursion(Lavi)/ValidParenthesis.java b/java/Recursion(Lavi)/ValidParenthesis.java new file mode 100644 index 00000000..2abf51a7 --- /dev/null +++ b/java/Recursion(Lavi)/ValidParenthesis.java @@ -0,0 +1,65 @@ +/** + * A utility class for checking if a string of parentheses is valid. + * + * + */ +public class ValidParenthesis { + + /** + * Determines if the given string is valid using a recursive approach. + * + * @param s input string containing only '(', ')', '{', '}', '[' and ']' + * @return true if the string is valid, false otherwise + */ + public boolean isValidRecursive(String s) { + // Base case: empty string is valid. + if (s.isEmpty()) { + return true; + } + + // If the length is odd, it cannot be valid. + if (s.length() % 2 != 0) { + return false; + } + + // Find the first valid pair. + int index = s.indexOf("()"); + if (index == -1) { + index = s.indexOf("[]"); + } + if (index == -1) { + index = s.indexOf("{}"); + } + + // If no valid pair is found, the string is invalid. + if (index == -1) { + return false; + } + + // Remove the pair and recurse on the reduced string. + String reduced = s.substring(0, index) + s.substring(index + 2); + return isValidRecursive(reduced); + } + + /** + * Runs sample test cases for the recursive validation method. + */ + public static void main(String[] args) { + ValidParenthesis validator = new ValidParenthesis(); + + String test1 = "()"; + String test2 = "()[]{}"; + String test3 = "(]"; + String test4 = "([)]"; + String test5 = "{[]}"; + + assert validator.isValidRecursive(test1) : "Test case 1 failed"; + assert validator.isValidRecursive(test2) : "Test case 2 failed"; + assert !validator.isValidRecursive(test3) : "Test case 3 failed"; + assert !validator.isValidRecursive(test4) : "Test case 4 failed"; + assert validator.isValidRecursive(test5) : "Test case 5 failed"; + + System.out.println("All test cases passed!"); + } +} + diff --git a/java/Recursion(Lavi)/checkstyle-11.0.0-all.jar b/java/Recursion(Lavi)/checkstyle-11.0.0-all.jar new file mode 100644 index 00000000..42af44f3 Binary files /dev/null and b/java/Recursion(Lavi)/checkstyle-11.0.0-all.jar differ diff --git a/java/RestoreFinishingOrder.java b/java/RestoreFinishingOrder.java new file mode 100644 index 00000000..38f289ce --- /dev/null +++ b/java/RestoreFinishingOrder.java @@ -0,0 +1,43 @@ +// LeetCode 3668. Restore Finishing Order +import java.util.ArrayList; + +public class RestoreFinishingOrder { + + public int[] recoverOrder(int[] order, int[] friends) { + ArrayList ans=new ArrayList<>(); + ArrayList Al=new ArrayList<>(); + for(int friend :friends){ + Al.add(friend); + } + + for(int num:order){ + if(Al.contains(num)){ + ans.add(num); + } + } + int[] res=new int[ans.size()]; + + for(int i=0;i= 0; i--) { + reversed += str.charAt(i); + } + return reversed; + } + } diff --git a/java/RotateImage.java b/java/RotateImg.java similarity index 53% rename from java/RotateImage.java rename to java/RotateImg.java index 87a08529..522423b2 100644 --- a/java/RotateImage.java +++ b/java/RotateImg.java @@ -1,17 +1,21 @@ -public class RotateImage { - public static void rotate(int[][] matrix) { +import java.util.*; + +class Rotate_Image { + + // Function to rotate the matrix by 90 degrees clockwise + public void rotate(int[][] matrix) { int n = matrix.length; - // Transpose the matrix + // Step 1: Transpose the matrix for (int i = 0; i < n; i++) { - for (int j = i; j < n; j++) { + for (int j = i + 1; j < n; j++) { int temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } } - // Reverse each row + // Step 2: Reverse each row for (int i = 0; i < n; i++) { for (int j = 0; j < n / 2; j++) { int temp = matrix[i][j]; @@ -21,21 +25,34 @@ public static void rotate(int[][] matrix) { } } + // Function to print the matrix + public void printMatrix(int[][] matrix) { + for (int[] row : matrix) { + for (int val : row) { + System.out.print(val + " "); + } + System.out.println(); + } + } + + // ✅ Main method to test the solution public static void main(String[] args) { + Rotate_Image obj = new Rotate_Image(); + + // Example input int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; - rotate(matrix); + System.out.println("Original Matrix:"); + obj.printMatrix(matrix); - // Print the rotated matrix - for (int[] row : matrix) { - for (int val : row) { - System.out.print(val + " "); - } - System.out.println(); - } + // Rotate the matrix + obj.rotate(matrix); + + System.out.println("\nRotated Matrix (90° Clockwise):"); + obj.printMatrix(matrix); } } diff --git a/java/Rotate_Image.class b/java/Rotate_Image.class new file mode 100644 index 00000000..62494a17 Binary files /dev/null and b/java/Rotate_Image.class differ diff --git a/java/Rotate_array.java b/java/Rotate_array.java new file mode 100644 index 00000000..58272f10 --- /dev/null +++ b/java/Rotate_array.java @@ -0,0 +1,64 @@ +import java.util.*; + + +public class Rotate_array { + + public static void rotate(int[] arr, int d) { + if (arr == null || arr.length == 0 || d % arr.length == 0) { + return; + } + + int n = arr.length; + d = d % n; + + reverse(arr, 0, n - 1); + reverse(arr, 0, n - d - 1); + reverse(arr, n - d, n - 1); + } + + private static void reverse(int[] arr, int start, int end) { + while (start < end) { + int temp = arr[start]; + arr[start] = arr[end]; + arr[end] = temp; + start++; + end--; + } + } + + public static void printArray(int[] arr) { + for (int i = 0; i < arr.length; i++) { + System.out.print(arr[i] + " "); + } + System.out.println(); + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + System.out.println("Enter the number of elements in the array:"); + int n = scanner.nextInt(); + + int[] arr = new int[n]; + + System.out.println("Enter the elements of the array:"); + for (int i = 0; i < n; i++) { + arr[i] = scanner.nextInt(); + } + + System.out.println("Enter the number of positions to rotate (d):"); + int d = scanner.nextInt(); + + System.out.print("Original Array: "); + printArray(arr); + + rotate(arr, d); + + System.out.print("Rotated Array: "); + printArray(arr); + + scanner.close(); + } +} + + diff --git a/java/RowColumnSearchInMatrix.java b/java/RowColumnSearchInMatrix.java new file mode 100644 index 00000000..3f463ccb --- /dev/null +++ b/java/RowColumnSearchInMatrix.java @@ -0,0 +1,47 @@ +/** + * Search in a Row and Column Sorted Matrix + * Time Complexity: O(n + m) + * Space Complexity: O(1) + * + * This program searches for a target element in a matrix + * where each row and column is sorted in ascending order. + * + * Example: + * Input: target = 39 + * Output: [-1, -1] (since 39 is not present) + * + * Author: Ruturaj Pawar + * Contributed for Hacktoberfest 2025 + */ + +import java.util.Arrays; + +public class RowColumnSearchInMatrix { + public static void main(String[] args) { + int[][] arr = { + {10,20,30,40}, + {15,25,35,45}, + {28,29,37,49}, + {33,34,38,50} + }; + System.out.println(Arrays.toString(search(arr, 39))); + } + + static int[] search(int[][] matrix, int target) { + int row = 0; + int col = matrix[0].length - 1; + + while (row < matrix.length && col>= 0) { + if (matrix[row][col] == target) { + return new int[]{row, col}; + } + else if (matrix[row][col] < target) { + row++; + } + else { + col--; + } + } + return new int[]{-1, -1}; + } +} diff --git a/java/SavingsAccount.class b/java/SavingsAccount.class new file mode 100644 index 00000000..9c0dd54e Binary files /dev/null and b/java/SavingsAccount.class differ diff --git a/java/SearchInStrings.java b/java/SearchInStrings.java new file mode 100644 index 00000000..dd10de37 --- /dev/null +++ b/java/SearchInStrings.java @@ -0,0 +1,54 @@ +public class SearchInStrings { + public static void main(String[] args) { + String name = "Ruturaj"; + char target = 'u'; + Search(name, target); + Search2(name, target); + } + + // Method 1: Search using charAt() + static void Search(String str, char target) { + boolean flag = false; // assume not found + + if (str.length() == 0) { // check empty string + System.out.println("String is empty."); + return; + } + + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == target) { // compare each character + flag = true; + break; // stop when found + } + } + + // display result + if (flag) + System.out.println("Target '" + target + "' found in string \"" + str + "\"."); + else + System.out.println("Target '" + target + "' not found in string \"" + str + "\"."); + } + + // Method 2: Search using toCharArray() + static void Search2(String str, char target) { + boolean flag = false; // assume not found + + if (str.length() == 0) { + System.out.println("String is empty."); + return; + } + + for (char ch : str.toCharArray()) { // iterate through char array + if (ch == target) { + flag = true; + break; + } + } + + // display result + if (flag) + System.out.println("Target '" + target + "' found in string \"" + str + "\"."); + else + System.out.println("Target '" + target + "' not found in string \"" + str + "\"."); + } +} \ No newline at end of file diff --git a/java/Secondlargest.java b/java/Secondlargest.java deleted file mode 100644 index d0b0b90f..00000000 --- a/java/Secondlargest.java +++ /dev/null @@ -1,23 +0,0 @@ -public class Secondlargest { - public static void main(String[] args) { - int[] arr = {12, 35, 1, 10, 34, 1}; - int n = arr.length; - System.out.println("The second largest element is: " + findSecondLargest(arr, n)); - } - - static int findSecondLargest(int[] arr, int n) { - int first = Integer.MIN_VALUE; - int second = Integer.MIN_VALUE; - - for (int i = 0; i < n; i++) { - if (arr[i] > first) { - second = first; - first = arr[i]; - } else if (arr[i] > second && arr[i] != first) { - second = arr[i]; - } - } - - return (second == Integer.MIN_VALUE) ? -1 : second; - } -} \ No newline at end of file diff --git a/java/SelectionSort.java b/java/SelectionSort.java new file mode 100644 index 00000000..01df22fb --- /dev/null +++ b/java/SelectionSort.java @@ -0,0 +1,31 @@ +public class SelectionSort { + public static void main(String[] args) { + int[] arr = {64, 25, 12, 22, 11}; + + selectionSort(arr); + + System.out.println("Sorted array:"); + for (int num : arr) { + System.out.print(num + " "); + } + } + + public static void selectionSort(int[] arr) { + int n = arr.length; + + for (int i = 0; i < n - 1; i++) { + int minIndex = i; + + for (int j = i + 1; j < n; j++) { + if (arr[j] < arr[minIndex]) { + minIndex = j; + } + } + + int temp = arr[minIndex]; + arr[minIndex] = arr[i]; + arr[i] = temp; + } + } +} + diff --git a/java/Shotestpath.java b/java/Shotestpath.java new file mode 100644 index 00000000..2930c170 --- /dev/null +++ b/java/Shotestpath.java @@ -0,0 +1,47 @@ +import java.util.*; + +class Solution { + public int shortestPathLength(int[][] graph) { + int n = graph.length; + if (n == 1) return 0; + + // Each state: (node, bitmask) + Queue q = new LinkedList<>(); + boolean[][] visited = new boolean[n][1 << n]; + + // Start BFS from each node + for (int i = 0; i < n; i++) { + q.offer(new int[]{i, 1 << i}); + visited[i][1 << i] = true; + } + + int steps = 0; + + while (!q.isEmpty()) { + int size = q.size(); + + for (int i = 0; i < size; i++) { + int[] curr = q.poll(); + int node = curr[0]; + int mask = curr[1]; + + // If all nodes visited + if (mask == (1 << n) - 1) { + return steps; + } + + // Explore neighbors + for (int next : graph[node]) { + int nextMask = mask | (1 << next); + if (!visited[next][nextMask]) { + visited[next][nextMask] = true; + q.offer(new int[]{next, nextMask}); + } + } + } + steps++; + } + + return -1; // Should never reach + } +} diff --git a/java/SieveofEratosthenes.java b/java/SieveofEratosthenes.java new file mode 100644 index 00000000..3949ddbb --- /dev/null +++ b/java/SieveofEratosthenes.java @@ -0,0 +1,28 @@ +public class SieveofEratosthenes { + public static void sieveOfEratosthenes(int n) { + boolean[] prime = new boolean[n + 1]; + for (int i = 0; i <= n; i++) { + prime[i] = true; + } + + for (int p = 2; p * p <= n; p++) { + if (prime[p]) { + for (int i = p * p; i <= n; i += p) { + prime[i] = false; + } + } + } + + for (int i = 2; i <= n; i++) { + if (prime[i]) { + System.out.print(i + " "); + } + } + } + + public static void main(String[] args) { + int n = 30; + System.out.println("Prime numbers up to " + n + " are:"); + sieveOfEratosthenes(n); + } +} diff --git a/java/Sliding_Window_Maximum.java b/java/Sliding_Window_Maximum.java new file mode 100644 index 00000000..b798a5c1 --- /dev/null +++ b/java/Sliding_Window_Maximum.java @@ -0,0 +1,28 @@ +class Solution { + public int[] maxSlidingWindow(int[] nums, int k) { + int n = nums.length; + int idx = 0; + int[] ans = new int[n-k+1]; + Stack st = new Stack<>(); + int[] nge = new int[n]; + st.push(n-1); + nge[n-1] = n; + for(int i = n-2 ; i >= 0 ; i--){ + while(!st.isEmpty() && nums[st.peek()] < nums[i]) st.pop(); + if(st.isEmpty()) nge[i] = n; + else nge[i] = st.peek(); + st.push(i); + } + int j = 0; + for(int i = 0 ; i < n-k+1 ; i++){ + if(j >= i+k)j = i; + int max = nums[j]; + while(j < i+k){ + max = nums[j]; + j = nge[j]; + } + ans[idx++] = max; + } + return ans; + } +} \ No newline at end of file diff --git a/java/Solution.class b/java/Solution.class new file mode 100644 index 00000000..7c3213b1 Binary files /dev/null and b/java/Solution.class differ diff --git a/java/Sort0S_1S_2S.java b/java/Sort0S_1S_2S.java new file mode 100644 index 00000000..21267cec --- /dev/null +++ b/java/Sort0S_1S_2S.java @@ -0,0 +1,49 @@ +public class Sort0S_1S_2S { + + // Function to sort the array in-place + public static void sortColors(int[] nums) { + int low = 0, mid = 0, high = nums.length - 1; + + while (mid <= high) { + switch (nums[mid]) { + case 0: + // swap nums[low] and nums[mid] + int temp0 = nums[low]; + nums[low] = nums[mid]; + nums[mid] = temp0; + low++; + mid++; + break; + case 1: + mid++; + break; + case 2: + // swap nums[mid] and nums[high] + int temp2 = nums[mid]; + nums[mid] = nums[high]; + nums[high] = temp2; + high--; + break; + } + } + } + + // Helper function to print the array + public static void printArray(int[] nums) { + for (int num : nums) { + System.out.print(num + " "); + } + System.out.println(); + } + + public static void main(String[] args) { + int[] nums = {2, 0, 2, 1, 1, 0}; + System.out.println("Original array:"); + printArray(nums); + + sortColors(nums); + + System.out.println("Sorted array:"); + printArray(nums); + } +} diff --git a/java/SortArrayListint.java b/java/SortArrayListint.java new file mode 100644 index 00000000..6dd0c939 --- /dev/null +++ b/java/SortArrayListint.java @@ -0,0 +1,36 @@ +import java.util.ArrayList; +import java.util.Scanner; + +public class ArrayListDemo { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Read number of elements + int n = sc.nextInt(); + + // Create an ArrayList of Integers + ArrayList numbers = new ArrayList<>(); + + // Read n integers and add them to the ArrayList + for (int i = 0; i < n; i++) { + numbers.add(sc.nextInt()); + } + + // Sort the ArrayList in ascending order using bubble sort + for (int i = 0; i < numbers.size() - 1; i++) { + for (int j = 0; j < numbers.size() - i - 1; j++) { + if (numbers.get(j) > numbers.get(j + 1)) { + // Swap numbers[j] and numbers[j+1] + int temp = numbers.get(j); + numbers.set(j, numbers.get(j + 1)); + numbers.set(j + 1, temp); + } + } + } + + // Print the sorted ArrayList + for (int num : numbers) { + System.out.print(num + " "); + } + } +} diff --git a/java/Sort_Ascending_Order.java b/java/Sort_Ascending_Order.java new file mode 100644 index 00000000..6f738ae4 --- /dev/null +++ b/java/Sort_Ascending_Order.java @@ -0,0 +1,40 @@ +import java.util.ArrayList; +import java.util.Scanner; + +class Sort_Ascending_Order{ + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Step 1: Read number of elements + System.out.println("Enter no of elements:"); + int n = sc.nextInt(); + ArrayList numbers = new ArrayList<>(); + + // Step 2: Read elements into ArrayList + System.out.println("Enter the integers:"); + for (int i = 0; i < n; i++) { + numbers.add(sc.nextInt()); + } + + //Bubble sort + for (int i = 0; i < numbers.size() - 1; i++) { + for (int j = 0; j < numbers.size() - i - 1; j++) { + if (numbers.get(j) > numbers.get(j + 1)) { + // Swap + int temp = numbers.get(j); + numbers.set(j, numbers.get(j + 1)); + numbers.set(j + 1, temp); + } + } + } + //print + for (int i = 0; i < numbers.size(); i++) { + System.out.print(numbers.get(i)); + if (i < numbers.size() - 1) { + System.out.print(" "); + } + } + + sc.close(); + } +} diff --git a/java/Sorting/BinarySearch.java b/java/Sorting/BinarySearch.java new file mode 100644 index 00000000..79f77792 --- /dev/null +++ b/java/Sorting/BinarySearch.java @@ -0,0 +1,32 @@ +import java.util.*; + +public class BinarySearch{ + public static void main(String[] args){ + + int[] arr = {2,3,5,9,14,16,18}; + int target = 15; + int ans = binarySearch(arr, target); + System.out.println(ans); + } + + static int binarySearch(int[] arr, int target){ + int start = 0; + int end = arr.length-1; + + while(start <= end){ + int mid = start + (end - start)/2; + + if(target < arr[mid]){ + end = mid -1; + } + else if(target > arr[mid]){ + start = mid + 1; + } + else{ + return mid; + } + } + return -1; + + } +} \ No newline at end of file diff --git a/java/Sorting/BubbleSort.java b/java/Sorting/BubbleSort.java new file mode 100644 index 00000000..2d847ab3 --- /dev/null +++ b/java/Sorting/BubbleSort.java @@ -0,0 +1,20 @@ +public class BubbleSort { + public static void bubbleSort(int[] arr) { + int n = arr.length; + for (int i = 0; i < n - 1; i++) + for (int j = 0; j < n - i - 1; j++) + if (arr[j] > arr[j + 1]) { + // swap arr[j] and arr[j+1] + int temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + + public static void main(String[] args) { + int[] data = {64, 34, 25, 12, 22, 11, 90}; + bubbleSort(data); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/BuiltInSort.java b/java/Sorting/BuiltInSort.java new file mode 100644 index 00000000..9585e3a7 --- /dev/null +++ b/java/Sorting/BuiltInSort.java @@ -0,0 +1,10 @@ +import java.util.Arrays; + +public class BuiltInSort { + public static void main(String[] args) { + int[] data = {5, 2, 8, 1, 3}; + Arrays.sort(data); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/CyclicSort.class b/java/Sorting/CyclicSort.class new file mode 100644 index 00000000..8ecf6d8a Binary files /dev/null and b/java/Sorting/CyclicSort.class differ diff --git a/java/Sorting/CyclicSort.java b/java/Sorting/CyclicSort.java new file mode 100644 index 00000000..b2b9a544 --- /dev/null +++ b/java/Sorting/CyclicSort.java @@ -0,0 +1,25 @@ +public class CyclicSort { + public static void main(String[] args) { + int[] arr = {1,2,5,3,4,6}; + cyclicsort(arr); + for (int num : arr) { + System.out.print(num + " "); + } + + } + public static void cyclicsort(int[] arr){ + int i =0; + while(i= 0 && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + arr[j + 1] = key; + } + } + + public static void main(String[] args) { + int[] data = {12, 11, 13, 5, 6}; + insertionSort(data); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/MergeSort.java b/java/Sorting/MergeSort.java new file mode 100644 index 00000000..96d377a3 --- /dev/null +++ b/java/Sorting/MergeSort.java @@ -0,0 +1,39 @@ +public class MergeSort { + public static void mergeSort(int[] arr, int left, int right) { + if (left < right) { + int mid = (left + right) / 2; + mergeSort(arr, left, mid); + mergeSort(arr, mid + 1, right); + merge(arr, left, mid, right); + } + } + + public static void merge(int[] arr, int left, int mid, int right) { + int n1 = mid - left + 1; + int n2 = right - mid; + + int[] L = new int[n1]; + int[] R = new int[n2]; + + for (int i = 0; i < n1; i++) + L[i] = arr[left + i]; + for (int j = 0; j < n2; j++) + R[j] = arr[mid + 1 + j]; + + int i = 0, j = 0, k = left; + while (i < n1 && j < n2) + arr[k++] = (L[i] <= R[j]) ? L[i++] : R[j++]; + + while (i < n1) + arr[k++] = L[i++]; + while (j < n2) + arr[k++] = R[j++]; + } + + public static void main(String[] args) { + int[] data = {38, 27, 43, 3, 9, 82, 10}; + mergeSort(data, 0, data.length - 1); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/QuickSort.java b/java/Sorting/QuickSort.java new file mode 100644 index 00000000..14dc0be1 --- /dev/null +++ b/java/Sorting/QuickSort.java @@ -0,0 +1,35 @@ +public class QuickSort { + public static void quickSort(int[] arr, int low, int high) { + if (low < high) { + int pi = partition(arr, low, high); + quickSort(arr, low, pi - 1); + quickSort(arr, pi + 1, high); + } + } + + public static int partition(int[] arr, int low, int high) { + int pivot = arr[high]; + int i = low - 1; + + for (int j = low; j < high; j++) + if (arr[j] < pivot) { + i++; + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + int temp = arr[i + 1]; + arr[i + 1] = arr[high]; + arr[high] = temp; + + return i + 1; + } + + public static void main(String[] args) { + int[] data = {10, 7, 8, 9, 1, 5}; + quickSort(data, 0, data.length - 1); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/SelectionSort.java b/java/Sorting/SelectionSort.java new file mode 100644 index 00000000..3b3674c8 --- /dev/null +++ b/java/Sorting/SelectionSort.java @@ -0,0 +1,22 @@ +public class SelectionSort { + public static void selectionSort(int[] arr) { + int n = arr.length; + for (int i = 0; i < n - 1; i++) { + int minIdx = i; + for (int j = i + 1; j < n; j++) + if (arr[j] < arr[minIdx]) + minIdx = j; + + int temp = arr[minIdx]; + arr[minIdx] = arr[i]; + arr[i] = temp; + } + } + + public static void main(String[] args) { + int[] data = {29, 10, 14, 37, 13}; + selectionSort(data); + for (int num : data) + System.out.print(num + " "); + } +} diff --git a/java/Sorting/heapSort.class b/java/Sorting/heapSort.class new file mode 100644 index 00000000..a64907fe Binary files /dev/null and b/java/Sorting/heapSort.class differ diff --git a/java/Sorting/nextGreatestLetter.java b/java/Sorting/nextGreatestLetter.java new file mode 100644 index 00000000..971411c7 --- /dev/null +++ b/java/Sorting/nextGreatestLetter.java @@ -0,0 +1,33 @@ + +public class nextGreatestLetter { + public static void main(String[] args) { + + int[] arr = {2, 3, 5, 9, 14, 16, 18}; + int target = 15; + int ans = Ceiling(arr, target); + System.out.println(ans); + } + + static int Ceiling(int[] arr, int target) { + + if (target > arr[arr.length - 1]) { + return -1; + } + + int start = 0; + int end = arr.length - 1; + + while (start <= end) { + int mid = start + (end - start) / 2; + + if (target < arr[mid]) { + end = mid - 1; + } else if (target > arr[mid]) { + start = mid + 1; + } else { + return arr[mid]; // found exact match + } + } + return arr[start]; // smallest element >= target + } +} \ No newline at end of file diff --git a/java/Spiral Matrix.java b/java/Spiral Matrix.java new file mode 100644 index 00000000..eb0d7eb9 --- /dev/null +++ b/java/Spiral Matrix.java @@ -0,0 +1,38 @@ +class Solution { + public List spiralOrder(int[][] matrix) { + List res = new ArrayList<>(); + int top = 0, bottom = matrix.length - 1; + int left = 0, right = matrix[0].length - 1; + + while (top <= bottom && left <= right) { + // Top row + for (int i = left; i <= right; i++) { + res.add(matrix[top][i]); + } + top++; + + // Right column + for (int i = top; i <= bottom; i++) { + res.add(matrix[i][right]); + } + right--; + + if (top <= bottom) { + // Bottom row + for (int i = right; i >= left; i--) { + res.add(matrix[bottom][i]); + } + bottom--; + } + + if (left <= right) { + // Left column + for (int i = bottom; i >= top; i--) { + res.add(matrix[i][left]); + } + left++; + } + } + return res; + } +} diff --git a/java/SpiralMatrix.java b/java/SpiralMatrix.java new file mode 100644 index 00000000..69bf1fbd --- /dev/null +++ b/java/SpiralMatrix.java @@ -0,0 +1,47 @@ +// https://leetcode.com/problems/spiral-matrix-ii/ +import java.util.*; + +class Solution { + public int[][] generateMatrix(int n) { + int[][] matrix = new int[n][n]; + + int left = 0, right = n - 1; + int top = 0, bottom = n - 1; + int num = 1; + + while (left <= right && top <= bottom) { + // fill top row + for (int i = left; i <= right; i++) { + matrix[top][i] = num++; + } + top++; + + // fill right column + for (int i = top; i <= bottom; i++) { + matrix[i][right] = num++; + } + right--; + + // fill bottom row + if (top <= bottom) { + for (int i = right; i >= left; i--) { + matrix[bottom][i] = num++; + } + bottom--; + } + + // fill left column + if (left <= right) { + for (int i = bottom; i >= top; i--) { + matrix[i][left] = num++; + } + left++; + } + } + + return matrix; + } +} + +// Time Complexity: O(n^2) +// Space Complexity: O(1) (excluding the output matrix) \ No newline at end of file diff --git a/java/SpiralMatrix2.java b/java/SpiralMatrix2.java new file mode 100644 index 00000000..905a4731 --- /dev/null +++ b/java/SpiralMatrix2.java @@ -0,0 +1,37 @@ +public class SpiralMatrix2 { + public static void printspiral(int matrix[][]){ + int startrow=0,startcolumn =0,endrow=matrix.length-1,endcoloumn=matrix[0].length-1; + + while(startrow<= endrow && startcolumn<=endcoloumn){ + for(int j=startcolumn;j<=endcoloumn;j++) { + System.out.print(matrix[startrow][j]+" "); + } + for(int i=startrow+1;i<=endrow;i++){ + System.out.print(matrix[i][endcoloumn]+" "); + } + for(int j=endcoloumn-1;j>=startcolumn;j--){ + if(startrow==endrow){ + break; + } + System.out.print(matrix[endrow][j]+" "); + } + for(int i=endrow-1;i>=startrow+1;i--){ + if(startcolumn==endcoloumn){ + break; + } + + System.out.print(matrix[i][startcolumn]+" "); + } + startcolumn++; + startrow++; + endcoloumn--; + endrow--; + } + System.out.println(); + } + public static void main(String[] args) { + int matrix[][] ={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; + printspiral(matrix); + + } +} diff --git a/java/Spreadsheet.java b/java/Spreadsheet.java new file mode 100644 index 00000000..172e9e85 --- /dev/null +++ b/java/Spreadsheet.java @@ -0,0 +1,43 @@ + + +class Spreadsheet { + private Map cells = new HashMap<>(); + + public Spreadsheet(int rows) { + } + + public void setCell(String cell, int value) { + cells.put(cell, value); + } + + public void resetCell(String cell) { + cells.remove(cell); + } + + public int getValue(String formula) { + // remove leading '=' if present + if (formula.startsWith("=")) { + formula = formula.substring(1); + } + + // split by '+' + String[] parts = formula.split("\\+"); + int result = 0; + + for (String part : parts) { + part = part.trim(); + + int value; + if (Character.isLetter(part.charAt(0))) { + // It's a cell reference + value = cells.getOrDefault(part, 0); + } else { + // It's a number + value = Integer.parseInt(part); + } + result += value; + } + + return result; + } +} diff --git a/java/Stack.class b/java/Stack.class new file mode 100644 index 00000000..ac119702 Binary files /dev/null and b/java/Stack.class differ diff --git a/java/Stack.java b/java/Stack.java new file mode 100644 index 00000000..0c0aa156 --- /dev/null +++ b/java/Stack.java @@ -0,0 +1,60 @@ +public class Stack { + private int[] stack; + private int top; + private int capacity; + + public Stack(int size) { + capacity = size; + stack = new int[capacity]; + top = -1; + } + + public boolean isEmpty() { + return top == -1; + } + + public boolean isFull() { + return top == capacity - 1; + } + + public void push(int item) { + if (isFull()) { + System.out.println("Stack is full"); + return; + } + stack[++top] = item; + } + + public int pop() { + if (isEmpty()) { + System.out.println("Stack is empty"); + return -1; + } + return stack[top--]; + } + + public int peek() { + if (isEmpty()) { + return -1; + } + return stack[top]; + } + + public void display() { + for (int i = top; i >= 0; i--) { + System.out.print(stack[i] + " "); + } + System.out.println(); + } + + public static void main(String[] args) { + Stack stack = new Stack(5); + stack.push(10); + stack.push(20); + stack.push(30); + System.out.print("Stack: "); + stack.display(); + System.out.println("Popped: " + stack.pop()); + System.out.println("Top element: " + stack.peek()); + } +} diff --git a/java/Stack/NextGreaterElement.class b/java/Stack/NextGreaterElement.class new file mode 100644 index 00000000..8a5717a9 Binary files /dev/null and b/java/Stack/NextGreaterElement.class differ diff --git a/java/Stack/NextGreaterElement.java b/java/Stack/NextGreaterElement.java new file mode 100644 index 00000000..05026256 --- /dev/null +++ b/java/Stack/NextGreaterElement.java @@ -0,0 +1,27 @@ +import java.util.*; + +public class NextGreaterElement { + public static void main(String[] args) { + int[] arr = {4, 5, 2, 25}; + int[] result = nextGreater(arr); + + System.out.println("Next Greater Elements:"); + for (int i = 0; i < arr.length; i++) { + System.out.println(arr[i] + " --> " + result[i]); + } + } + + static int[] nextGreater(int[] arr) { + Stack stack = new Stack<>(); + int[] nge = new int[arr.length]; + + for (int i = arr.length - 1; i >= 0; i--) { + while (!stack.isEmpty() && stack.peek() <= arr[i]) { + stack.pop(); + } + nge[i] = stack.isEmpty() ? -1 : stack.peek(); + stack.push(arr[i]); + } + return nge; + } +} diff --git a/java/Stack/ValidParentheses.class b/java/Stack/ValidParentheses.class new file mode 100644 index 00000000..e5e58c64 Binary files /dev/null and b/java/Stack/ValidParentheses.class differ diff --git a/java/Stack/ValidParentheses.java b/java/Stack/ValidParentheses.java new file mode 100644 index 00000000..e15d49df --- /dev/null +++ b/java/Stack/ValidParentheses.java @@ -0,0 +1,24 @@ +import java.util.*; + +public class ValidParentheses { + public static boolean isValid(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + if (c == '(' || c == '[' || c == '{') stack.push(c); + else { + if (stack.isEmpty()) return false; + char top = stack.pop(); + if ((c == ')' && top != '(') || + (c == ']' && top != '[') || + (c == '}' && top != '{')) + return false; + } + } + return stack.isEmpty(); + } + + public static void main(String[] args) { + String input = "{[()]}"; + System.out.println(isValid(input) ? "Balanced" : "Not Balanced"); + } +} diff --git a/java/Starpattern.java b/java/Starpattern.java new file mode 100644 index 00000000..b8f02605 --- /dev/null +++ b/java/Starpattern.java @@ -0,0 +1,19 @@ +public class Starpattern{ + public static void main(String[] args) { + int row=10; + int col=10; + int i=0; + int j=0; + for (i = 0; i <=col; i++) { + for (j = i; j >=0; j--) { + System.out.print(" *"); + } + System.out.print(" *** "); + for (j =i; j <=col; j++) { + System.out.print(" *"); + } + System.out.println(); + } + + } +} \ No newline at end of file diff --git a/java/StreamDemo.java b/java/StreamDemo.java new file mode 100644 index 00000000..a7af668a --- /dev/null +++ b/java/StreamDemo.java @@ -0,0 +1,68 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class StreamDemo { + public static void main(String[] args) { + ArrayList arrayList = new ArrayList<>(); + + arrayList.add(10); + arrayList.add(20); + arrayList.add(30); + arrayList.add(40); + + //ArrayList squareList = new ArrayList<>(); + + //for(Integer i : arrayList) { + // squareList.add(i*i); + //} + + //single line code for above same task + List squareList = arrayList.stream().map(x -> x*x).collect(Collectors.toList()); + + System.out.println("The list of square numbers: "+squareList); + + // + //List to squared set(Hashset) + + //normal approach + //HashSet squareSet = new HashSet<>(); + //for(Integer i : arrayList) { + // squareSet.add(i*i); + //} + + Set squareSet = arrayList.stream().map(x -> x*x).collect(Collectors.toSet()); + + System.out.println("Square HashSet Is:"+squareSet); + + //Filtering + List languages = new ArrayList<>(); + + + languages.add("Scala"); + languages.add("Java"); + languages.add("Python"); + languages.add("Basic"); + + + //List filterResult = new ArrayList<>(); + //for(String s : languages) { + // if(s.startsWith("P")) { + // filterResult.add(s); + // } + //} + + List filterResult = languages.stream().filter(s -> s.startsWith("P")).collect(Collectors.toList()); + + System.out.println(filterResult); + + // + // + List sortedList = languages.stream().sorted().collect(Collectors.toList()); + System.out.println(sortedList); + + //printing one by one + languages.stream().forEach(y -> System.out.println("Element is " + y)); + } +} diff --git a/java/StringUtils.java b/java/StringUtils.java new file mode 100644 index 00000000..bdcda843 --- /dev/null +++ b/java/StringUtils.java @@ -0,0 +1,60 @@ +/** + * StringUtils - Common String Utility Methods + * + * Provides: + * - Palindrome check + * - Reverse string + * - Count vowels and consonants + * + * Author: Prince Yadav + * Version: 1.0 + * Since: October 2025 + */ +public class StringUtils { + + /** + * Checks if a string is a palindrome (ignores case and spaces) + * @param str input string + * @return true if palindrome, false otherwise + */ + public static boolean isPalindrome(String str) { + if (str == null) return false; + str = str.replaceAll("[^a-zA-Z0-9]", "").toLowerCase(); + int left = 0, right = str.length() - 1; + while (left < right) { + if (str.charAt(left) != str.charAt(right)) return false; + left++; + right--; + } + return true; + } + + /** + * Reverses the given string + * @param str input string + * @return reversed string + */ + public static String reverse(String str) { + if (str == null) return null; + return new StringBuilder(str).reverse().toString(); + } + + /** + * Counts vowels and consonants in a string + * @param str input string + * @return int array [vowelCount, consonantCount] + */ + public static int[] countVowelsConsonants(String str) { + int vowels = 0, consonants = 0; + if (str != null) { + str = str.toLowerCase(); + for (char c : str.toCharArray()) { + if (c >= 'a' && c <= 'z') { + if ("aeiou".indexOf(c) != -1) vowels++; + else consonants++; + } + } + } + return new int[]{vowels, consonants}; + } +} diff --git a/java/StringUtilsTest.java b/java/StringUtilsTest.java new file mode 100644 index 00000000..a6d8695e --- /dev/null +++ b/java/StringUtilsTest.java @@ -0,0 +1,37 @@ +package algorithms.strings; + +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +public class StringUtilsTest { + + @Test + void testIsPalindrome() { + assertTrue(StringUtils.isPalindrome("Madam")); + assertTrue(StringUtils.isPalindrome("A man a plan a canal Panama")); + assertFalse(StringUtils.isPalindrome("Hello")); + assertFalse(StringUtils.isPalindrome(null)); + } + + @Test + void testReverse() { + assertEquals("olleH", StringUtils.reverse("Hello")); + assertEquals("racecar", StringUtils.reverse("racecar")); + assertNull(StringUtils.reverse(null)); + } + + @Test + void testCountVowelsConsonants() { + int[] result = StringUtils.countVowelsConsonants("Hello World"); + assertArrayEquals(new int[]{3, 7}, result); // 3 vowels, 7 consonants + + result = StringUtils.countVowelsConsonants("AEIOU"); + assertArrayEquals(new int[]{5, 0}, result); + + result = StringUtils.countVowelsConsonants(""); + assertArrayEquals(new int[]{0, 0}, result); + + result = StringUtils.countVowelsConsonants(null); + assertArrayEquals(new int[]{0, 0}, result); + } +} diff --git a/java/Substring_without_Repeat.class b/java/Substring_without_Repeat.class new file mode 100644 index 00000000..717eb9df Binary files /dev/null and b/java/Substring_without_Repeat.class differ diff --git a/java/Substring_without_Repeat.java b/java/Substring_without_Repeat.java new file mode 100644 index 00000000..145d8fcc --- /dev/null +++ b/java/Substring_without_Repeat.java @@ -0,0 +1,31 @@ +import java.util.*; + +class Substring_without_Repeat { + + public int lengthOfLongestSubstring(String s) { + Set set = new HashSet<>(); + int left = 0; + int maxLength = 0; + + for (int right = 0; right < s.length(); right++) { + while (set.contains(s.charAt(right))) { + set.remove(s.charAt(left)); + left++; + } + + set.add(s.charAt(right)); + maxLength = Math.max(maxLength, right - left + 1); + } + + return maxLength; + } + + public static void main(String[] args) { + Substring_without_Repeat obj = new Substring_without_Repeat(); + + String s = "abcabcbb"; // You can change this input + int result = obj.lengthOfLongestSubstring(s); + + System.out.println("Length of the longest substring without repeating characters: " + result); + } +} diff --git a/java/SuccessfulPairsOfSpellsAndPotions.java b/java/SuccessfulPairsOfSpellsAndPotions.java new file mode 100644 index 00000000..4faf9995 --- /dev/null +++ b/java/SuccessfulPairsOfSpellsAndPotions.java @@ -0,0 +1,24 @@ +import java.util.Arrays; + +class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int n = spells.length; + int m = potions.length; + Arrays.sort(potions); + int[] ans = new int[n]; + for(int i=0;i= success){ + hi=mid-1; + } + else lo=mid+1; + } + ans[i] = m-lo; + } + return ans; + } +} \ No newline at end of file diff --git a/java/Sunny_Number.java b/java/Sunny_Number.java new file mode 100644 index 00000000..43de6846 --- /dev/null +++ b/java/Sunny_Number.java @@ -0,0 +1,32 @@ +import java.util.Scanner; + +public class SunnyNumberChecker { + + // Method to check if a number is a perfect square + public static boolean isPerfectSquare(double num) { + double sqrt = Math.sqrt(num); + // Check if the square root is an integer (i.e., no fractional part) + return (sqrt == (int) sqrt); + } + + // Method to check if a number is a Sunny Number + public static boolean isSunnyNumber(int num) { + // A number is sunny if (num + 1) is a perfect square + return isPerfectSquare(num + 1); + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + System.out.print("Enter a number to check if it's a Sunny Number: "); + int number = scanner.nextInt(); + + if (isSunnyNumber(number)) { + System.out.println(number + " is a Sunny Number."); + } else { + System.out.println(number + " is not a Sunny Number."); + } + + scanner.close(); + } +} \ No newline at end of file diff --git a/java/SwappingNodesInLinkedList.java b/java/SwappingNodesInLinkedList.java new file mode 100644 index 00000000..08ca7360 --- /dev/null +++ b/java/SwappingNodesInLinkedList.java @@ -0,0 +1,41 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +// contributor > Ayaaz Qureshi +// guthub>> AyaazQureshi +class Solution { + public ListNode swapNodes(ListNode head, int k) { + if (head == null || head.next == null) return head; + + ListNode first = head; + for (int i = 1; i < k; i++) { + first = first.next; + } + + ListNode temp = head; + int len = 0; + while (temp != null) { + temp = temp.next; + len++; + } + + ListNode second = head; + for (int i = 1; i <= len - k; i++) { + second = second.next; + } + + // Swap values + int t = first.val; + first.val = second.val; + second.val = t; + + return head; + } +} \ No newline at end of file diff --git a/java/TappingRainWater.java b/java/TappingRainWater.java new file mode 100644 index 00000000..d473ee6f --- /dev/null +++ b/java/TappingRainWater.java @@ -0,0 +1,34 @@ +class Solution { + public static int trap(int[] height) { + int n = height.length; + int leftmax[] = new int[n]; + leftmax[0]= height[0]; + for(int i = 1 ; i< n ; i++){ + leftmax[i] = Math.max(height[i], leftmax[i-1]); + } + + int rightmax[] = new int[n]; + rightmax[n-1] = height[n-1]; + for(int i=n-2 ; i>=0 ;i--){ + rightmax[i] = Math.max(height[i], rightmax[i+1]); + } + + int tapwater = 0; + + for(int i =0 ; i< n; i++){ + int waterlevel = Math.min(leftmax[i],rightmax[i]); + tapwater += waterlevel - height[i]; + } + + return tapwater; + + } + public static void main(String[] args){ + Scanner scan = new Scanner(System.in); + System.out.println("enter the size of an array"); + int size = scan.nextInt(); + int height[] = new int[size]; + trap(height); + + } +} diff --git a/java/TappingRainWaterII.java b/java/TappingRainWaterII.java new file mode 100644 index 00000000..bf14a632 --- /dev/null +++ b/java/TappingRainWaterII.java @@ -0,0 +1,42 @@ +#include +#include +#include +using namespace std; + +class Solution { +public: + int trapRainWater(vector>& heightMap) { + if (heightMap.empty() || heightMap[0].empty()) return 0; + int m = heightMap.size(), n = heightMap[0].size(); + if (m < 3 || n < 3) return 0; + + using T = tuple; + priority_queue, greater> pq; + vector> visited(m, vector(n, false)); + + for (int i = 0; i < m; ++i) { + pq.emplace(heightMap[i][0], i, 0); visited[i][0] = true; + pq.emplace(heightMap[i][n-1], i, n-1); visited[i][n-1] = true; + } + for (int j = 0; j < n; ++j) { + if (!visited[0][j]) { pq.emplace(heightMap[0][j], 0, j); visited[0][j] = true; } + if (!visited[m-1][j]) { pq.emplace(heightMap[m-1][j], m-1, j); visited[m-1][j] = true; } + } + + int res = 0; + int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; + + while (!pq.empty()) { + auto [h, r, c] = pq.top(); pq.pop(); + for (auto &d : dirs) { + int nr = r + d[0], nc = c + d[1]; + if (nr < 0 || nr >= m || nc < 0 || nc >= n || visited[nr][nc]) continue; + visited[nr][nc] = true; + int nh = heightMap[nr][nc]; + if (nh < h) res += h - nh; + pq.emplace(max(nh, h), nr, nc); + } + } + return res; + } +}; \ No newline at end of file diff --git a/java/TarjanBridgesArticulation.java b/java/TarjanBridgesArticulation.java new file mode 100644 index 00000000..669f2dbf --- /dev/null +++ b/java/TarjanBridgesArticulation.java @@ -0,0 +1,153 @@ +/* + * Tarjan's Algorithm for Bridges and Articulation Points in a Graph + * + * 👉 What are Bridges? + * An edge in a graph is a "bridge" if removing it increases the number of connected components. + * + * 👉 What are Articulation Points (Cut Vertices)? + * A vertex is an articulation point if removing it increases the number of connected components. + * + * 📌 Why Important? + * These concepts are critical in: + * - Network reliability (finding weak links in a network). + * - System design (critical servers or routers). + * - Graph theory problems in competitive programming. + * + * 📌 Algorithm Idea (Tarjan’s DFS): + * - Perform DFS traversal of the graph. + * - Maintain: + * 1. discovery[] = time when a node is discovered + * 2. low[] = lowest discovery time reachable from that node + * - For a node u and its neighbor v: + * - If low[v] > discovery[u], then edge (u, v) is a BRIDGE. + * - If discovery[u] <= low[v], then u is an ARTICULATION POINT. + * + * Time Complexity: O(V + E) + * Space Complexity: O(V) + */ + +import java.util.*; + +public class TarjanBridgesArticulation { + private int V; // number of vertices + private List> adj; // adjacency list + private int time; // global time for DFS traversal + + private int[] discovery; // discovery time of nodes + private int[] low; // lowest discovery time reachable + private boolean[] visited; + private boolean[] isArticulation; // articulation marker + + // Constructor + public TarjanBridgesArticulation(int vertices) { + this.V = vertices; + adj = new ArrayList<>(); + for (int i = 0; i < V; i++) { + adj.add(new ArrayList<>()); + } + discovery = new int[V]; + low = new int[V]; + visited = new boolean[V]; + isArticulation = new boolean[V]; + time = 0; + } + + // Add edge (undirected graph) + public void addEdge(int u, int v) { + adj.get(u).add(v); + adj.get(v).add(u); + } + + // DFS helper + private void dfs(int u, int parent, List bridges) { + visited[u] = true; + discovery[u] = low[u] = ++time; // initialize discovery and low + + int children = 0; // count of children in DFS Tree + + for (int v : adj.get(u)) { + if (v == parent) continue; // ignore the edge to parent + + if (!visited[v]) { + children++; + dfs(v, u, bridges); + + // Update low[u] considering child v + low[u] = Math.min(low[u], low[v]); + + // --- Bridge condition --- + if (low[v] > discovery[u]) { + bridges.add("Bridge found: (" + u + " - " + v + ")"); + } + + // --- Articulation Point condition --- + if (parent != -1 && low[v] >= discovery[u]) { + isArticulation[u] = true; + } + } else { + // Update low[u] for back edge + low[u] = Math.min(low[u], discovery[v]); + } + } + + // Root articulation condition + if (parent == -1 && children > 1) { + isArticulation[u] = true; + } + } + + // Main function to find Bridges and Articulation Points + public void findBridgesAndArticulationPoints() { + List bridges = new ArrayList<>(); + + for (int i = 0; i < V; i++) { + if (!visited[i]) { + dfs(i, -1, bridges); + } + } + + // Print Bridges + System.out.println("🔗 Bridges in the Graph:"); + if (bridges.isEmpty()) { + System.out.println("No bridges found."); + } else { + for (String b : bridges) System.out.println(b); + } + + // Print Articulation Points + System.out.println("\n⚡ Articulation Points in the Graph:"); + boolean foundAP = false; + for (int i = 0; i < V; i++) { + if (isArticulation[i]) { + System.out.println("Articulation Point: " + i); + foundAP = true; + } + } + if (!foundAP) { + System.out.println("No articulation points found."); + } + } + + // --- Driver Code / Example --- + public static void main(String[] args) { + /* + * Example Graph: + * 0 ----- 1 + * | / | + * | / | + * | / | + * 2 3 + * | + * 4 + */ + TarjanBridgesArticulation graph = new TarjanBridgesArticulation(5); + + graph.addEdge(0, 1); + graph.addEdge(0, 2); + graph.addEdge(1, 2); + graph.addEdge(1, 3); + graph.addEdge(3, 4); + + graph.findBridgesAndArticulationPoints(); + } +} diff --git a/java/3Sum.java b/java/ThreeSum.java similarity index 96% rename from java/3Sum.java rename to java/ThreeSum.java index 89aaec5f..2f026077 100644 --- a/java/3Sum.java +++ b/java/ThreeSum.java @@ -1,37 +1,37 @@ -import java.util.*; - -public class ThreeSum { - public List> threeSum(int[] nums) { - Arrays.sort(nums); - List> result = new ArrayList<>(); - - for (int i = 0; i < nums.length - 2; i++) { - if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates - - int left = i + 1, right = nums.length - 1; - while (left < right) { - int sum = nums[i] + nums[left] + nums[right]; - - if (sum == 0) { - result.add(Arrays.asList(nums[i], nums[left], nums[right])); - while (left < right && nums[left] == nums[left + 1]) left++; - while (left < right && nums[right] == nums[right - 1]) right--; - left++; - right--; - } else if (sum < 0) { - left++; - } else { - right--; - } - } - } - - return result; - } - - public static void main(String[] args) { - ThreeSum obj = new ThreeSum(); - System.out.println(obj.threeSum(new int[]{-1,0,1,2,-1,-4})); - // [[-1,-1,2], [-1,0,1]] - } -} +import java.util.*; + +public class ThreeSum { + public List> threeSum(int[] nums) { + Arrays.sort(nums); + List> result = new ArrayList<>(); + + for (int i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates + + int left = i + 1, right = nums.length - 1; + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + + if (sum == 0) { + result.add(Arrays.asList(nums[i], nums[left], nums[right])); + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } else if (sum < 0) { + left++; + } else { + right--; + } + } + } + + return result; + } + + public static void main(String[] args) { + ThreeSum obj = new ThreeSum(); + System.out.println(obj.threeSum(new int[]{-1,0,1,2,-1,-4})); + // [[-1,-1,2], [-1,0,1]] + } +} diff --git a/java/ThreeeeSum.java b/java/ThreeeeSum.java new file mode 100644 index 00000000..99843d27 --- /dev/null +++ b/java/ThreeeeSum.java @@ -0,0 +1,37 @@ +import java.util.*; + +public class ThreeeeSum { + public List> threeSum(int[] nums) { + Arrays.sort(nums); + List> result = new ArrayList<>(); + + for (int i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates + + int left = i + 1, right = nums.length - 1; + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + + if (sum == 0) { + result.add(Arrays.asList(nums[i], nums[left], nums[right])); + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } else if (sum < 0) { + left++; + } else { + right--; + } + } + } + + return result; + } + + public static void main(String[] args) { + ThreeeeSum obj = new ThreeeeSum(); + System.out.println(obj.threeSum(new int[]{-1,0,1,2,-1,-4})); + // [[-1,-1,2], [-1,0,1]] + } +} diff --git a/java/Threesum.java b/java/Threesum.java deleted file mode 100644 index 53f84af8..00000000 --- a/java/Threesum.java +++ /dev/null @@ -1,159 +0,0 @@ - -import java.util.*; - -public class Threesum { - - /** - * Finds all unique triplets in the array that sum to zero - * Time Complexity: O(n^2) - * Space Complexity: O(1) excluding the output array - * - * @param nums input array of integers - * @return list of triplets that sum to zero - */ - public List> threeSum(int[] nums) { - List> result = new ArrayList<>(); - - // Handle edge cases - if (nums == null || nums.length < 3) { - return result; - } - - // Sort the array to enable two-pointer technique - Arrays.sort(nums); - - for (int i = 0; i < nums.length - 2; i++) { - // Skip duplicate values for the first element - if (i > 0 && nums[i] == nums[i - 1]) { - continue; - } - - int left = i + 1; - int right = nums.length - 1; - - while (left < right) { - int sum = nums[i] + nums[left] + nums[right]; - - if (sum == 0) { - // Found a valid triplet - result.add(Arrays.asList(nums[i], nums[left], nums[right])); - - // Skip duplicates for left pointer - while (left < right && nums[left] == nums[left + 1]) { - left++; - } - - // Skip duplicates for right pointer - while (left < right && nums[right] == nums[right - 1]) { - right--; - } - - left++; - right--; - } else if (sum < 0) { - // Sum is too small, move left pointer right - left++; - } else { - // Sum is too large, move right pointer left - right--; - } - } - } - - return result; - } - - - public List> threeSumTarget(int[] nums, int target) { - List> result = new ArrayList<>(); - - if (nums == null || nums.length < 3) { - return result; - } - - Arrays.sort(nums); - - for (int i = 0; i < nums.length - 2; i++) { - if (i > 0 && nums[i] == nums[i - 1]) { - continue; - } - - int left = i + 1; - int right = nums.length - 1; - - while (left < right) { - int sum = nums[i] + nums[left] + nums[right]; - - if (sum == target) { - result.add(Arrays.asList(nums[i], nums[left], nums[right])); - - while (left < right && nums[left] == nums[left + 1]) { - left++; - } - while (left < right && nums[right] == nums[right - 1]) { - right--; - } - - left++; - right--; - } else if (sum < target) { - left++; - } else { - right--; - } - } - } - - return result; - } - - /** - * Helper method to print the results - */ - public void printTriplets(List> triplets) { - if (triplets.isEmpty()) { - System.out.println("No triplets found."); - return; - } - - System.out.println("Found triplets:"); - for (List triplet : triplets) { - System.out.println(triplet); - } - } - - /** - * Main method for testing - */ - public static void main(String[] args) { - Threesum solution = new Threesum(); - - // Test case 1: Basic example - int[] nums1 = {-1, 0, 1, 2, -1, -4}; - System.out.println("Test case 1: " + Arrays.toString(nums1)); - List> result1 = solution.threeSum(nums1); - solution.printTriplets(result1); - System.out.println(); - - // Test case 2: No triplets sum to zero - int[] nums2 = {0, 1, 1}; - System.out.println("Test case 2: " + Arrays.toString(nums2)); - List> result2 = solution.threeSum(nums2); - solution.printTriplets(result2); - System.out.println(); - - // Test case 3: All zeros - int[] nums3 = {0, 0, 0}; - System.out.println("Test case 3: " + Arrays.toString(nums3)); - List> result3 = solution.threeSum(nums3); - solution.printTriplets(result3); - System.out.println(); - - // Test case 4: Custom target - int[] nums4 = {-1, 0, 1, 2, -1, -4}; - int target = 0; - System.out.println("Test case 4 (target=" + target + "): " + Arrays.toString(nums4)); - List> result4 = solution.threeSumTarget(nums4, target); - solution.printTriplets(result4); - } -} diff --git a/java/TopKFrequent.java b/java/TopKFrequent.java new file mode 100644 index 00000000..f78eaed2 --- /dev/null +++ b/java/TopKFrequent.java @@ -0,0 +1,45 @@ +import java.util.*; + +/** + * Top K Frequent Elements - Priority Queue Approach + * Find k most frequent elements with larger number preference for ties. + */ +public class TopKFrequent { + + public int[] topKFrequent(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + PriorityQueue pq = new PriorityQueue<>((a, b) -> { + int freqCompare = freqMap.get(b) - freqMap.get(a); + return freqCompare != 0 ? freqCompare : b - a; + }); + + pq.addAll(freqMap.keySet()); + + int[] result = new int[k]; + for (int i = 0; i < k; i++) { + result[i] = pq.poll(); + } + + return result; + } + + public static void main(String[] args) { + TopKFrequent solution = new TopKFrequent(); + + // Test case 1 + int[] arr1 = {3, 1, 4, 4, 5, 2, 6, 1}; + int[] result1 = solution.topKFrequent(arr1, 2); + System.out.println("Array: [3,1,4,4,5,2,6,1], k=2"); + System.out.println("Result: " + Arrays.toString(result1)); // [4, 1] + + // Test case 2 + int[] arr2 = {7, 10, 11, 5, 2, 5, 5, 7, 11, 8, 9}; + int[] result2 = solution.topKFrequent(arr2, 4); + System.out.println("\nArray: [7,10,11,5,2,5,5,7,11,8,9], k=4"); + System.out.println("Result: " + Arrays.toString(result2)); // [5, 11, 7, 10] + } +} \ No newline at end of file diff --git a/java/TopologicalSort.java b/java/TopologicalSort.java new file mode 100644 index 00000000..3f113b5e --- /dev/null +++ b/java/TopologicalSort.java @@ -0,0 +1,61 @@ +import java.util.*; + +public class TopologicalSort { + + static class Edge { + int src; + int dest; + + public Edge(int s, int d) { + this.src = s; + this.dest = d; + } + } + + static void createGraph(ArrayList graph[]) { + for(int i = 0; i < graph.length; i++) { + graph[i] = new ArrayList<>(); + } + graph[2].add(new Edge(2, 3)); + graph[3].add(new Edge(3, 1)); + graph[4].add(new Edge(4, 0)); + graph[4].add(new Edge(4, 1)); + graph[5].add(new Edge(5, 0)); + graph[5].add(new Edge(5, 2)); + } + + public static void topoSortUtil(ArrayList graph[], int curr, boolean vis[], Stack s) { + vis[curr] = true; + for(int i = 0; i < graph[curr].size(); i++) { + Edge e = graph[curr].get(i); + if(!vis[e.dest]) { + topoSortUtil(graph, e.dest, vis, s); + } + } + s.push(curr); + } + + public static void topoSort(ArrayList graph[]) { + boolean vis[] = new boolean[graph.length]; + Stack s = new Stack<>(); + + for(int i = 0; i < graph.length; i++) { + if(!vis[i]) { + topoSortUtil(graph, i, vis, s); + } + } + + while(!s.isEmpty()) { + System.out.print(s.pop() + " "); + } + System.out.println(); // Added for a clean newline at the end of output + } + + public static void main(String args[]) { + int V = 6; + @SuppressWarnings("unchecked") + ArrayList graph[] = new ArrayList[V]; + createGraph(graph); + topoSort(graph); + } +} \ No newline at end of file diff --git a/java/Tower_Of_Hanoi.java b/java/Tower_Of_Hanoi.java new file mode 100644 index 00000000..a00f99ba --- /dev/null +++ b/java/Tower_Of_Hanoi.java @@ -0,0 +1,44 @@ +import java.util.Scanner; + +class Solution { + public int towerOfHanoi(int n, int from, int to, int aux) { + if (n == 0) { + return 0; + } + + int moves1 = towerOfHanoi(n - 1, from, aux, to); + + System.out.println("Move disk " + n + " from rod " + from + " to rod " + to); + int move2 = 1; + + int moves3 = towerOfHanoi(n - 1, aux, to, from); + + return moves1 + move2 + moves3; + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Solution solver = new Solution(); + + System.out.println("--- Tower of Hanoi Solver (Moves and Count) ---"); + System.out.print("Enter the number of disks (n): "); + + if (scanner.hasNextInt()) { + int n = scanner.nextInt(); + + if (n < 0) { + System.out.println("Please enter a non-negative number of disks."); + } else { + System.out.println("\n--- Sequence of Moves ---"); + // Rods are conventionally 1 (from), 3 (to), 2 (aux) + int moves = solver.towerOfHanoi(n, 1, 3, 2); + System.out.println("-------------------------"); + System.out.println("Total minimum moves required for " + n + " disks: " + moves); + } + } else { + System.out.println("Invalid input. Please enter an integer."); + } + + scanner.close(); + } +} diff --git a/java/TransposeOfMatrix.java b/java/TransposeOfMatrix.java new file mode 100644 index 00000000..7cbf73c1 --- /dev/null +++ b/java/TransposeOfMatrix.java @@ -0,0 +1,48 @@ + +// Time Complexity: O(m * n) +// Space Complexity: O(m * n) + +import java.util.Scanner; + +public class MatrixTranspose { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + // Input number of rows and columns + System.out.print("Enter number of rows (m): "); + int m = sc.nextInt(); + System.out.print("Enter number of columns (n): "); + int n = sc.nextInt(); + + int[][] matrix = new int[m][n]; + + // Input matrix elements + System.out.println("Enter matrix elements:"); + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + matrix[i][j] = sc.nextInt(); + } + } + + // Compute transpose + int[][] transpose = new int[n][m]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + // Swap rows with columns + transpose[j][i] = matrix[i][j]; + } + } + + // Display transposed matrix + System.out.println("\nTransposed Matrix (" + n + " x " + m + "):"); + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + System.out.print(transpose[i][j] + " "); + } + System.out.println(); + } + + sc.close(); + } +} diff --git a/java/TrappingRainWater.java b/java/TrappingRainWater.java new file mode 100644 index 00000000..d5a1758a --- /dev/null +++ b/java/TrappingRainWater.java @@ -0,0 +1,32 @@ +class Solution { + public int trap(int[] h) { + + + int[] l = new int[h.length]; + int[] r = new int[h.length]; + + l[0] = h[0]; + r[h.length - 1] = h[h.length - 1]; + + + for(int i = 1; i <= h.length-1; i++){ + + l[i] = Math.max(h[i], l[i-1]); + } + + + for(int i = h.length - 2; i >= 0; i--){ + + r[i] = Math.max(h[i], r[i+1]); + } + + int sum = 0; + + + for(int i = 0; i < h.length; i++){ + sum += Math.min(l[i], r[i]) - h[i]; + } + return sum; + + } +} diff --git a/java/Trapping_Rain_Water_II.java b/java/Trapping_Rain_Water_II.java new file mode 100644 index 00000000..0c57780d --- /dev/null +++ b/java/Trapping_Rain_Water_II.java @@ -0,0 +1,62 @@ +class Solution { + + public int trapRainWater(int[][] heightMap) { + //left,right,down, up + int dir[][] = {{0,-1},{0,1},{-1,0},{1,0}}; + int rows = heightMap.length; + int cols = heightMap[0].length; + if(rows <3 || cols <3) return 0; + int totalUnvisitedCells = rows*cols; + boolean[][] visited = new boolean[rows][cols]; + // [hight, row, col] -> inc order of height + PriorityQueue pq = new PriorityQueue<>((a,b) -> (a[0]-b[0])); + + for (int i = 0; i < rows; i++) { + pq.offer(new int[]{heightMap[i][0], i, 0}); + pq.offer(new int[]{heightMap[i][cols - 1], i, cols - 1}); + visited[i][0] = true; + visited[i][cols - 1] = true; + totalUnvisitedCells--; + totalUnvisitedCells--; + } + + for (int i = 1; i < cols-1; i++) { + pq.offer(new int[]{heightMap[0][i], 0, i}); + pq.offer(new int []{heightMap[rows - 1][i], rows - 1, i}); + visited[0][i] = true; + visited[rows - 1][i] = true; + totalUnvisitedCells--; + totalUnvisitedCells--; + } + int trappedWater = 0; + int waterLevel=0; + //n*mlog(n*m) + while (!pq.isEmpty() && totalUnvisitedCells>0) { + int currentCell[] = pq.poll(); + int currentHeight = currentCell[0]; + int currentRow = currentCell[1]; + int currentCol = currentCell[2]; + waterLevel = Math.max(waterLevel, currentHeight); + // Explore all 4 neighboring cells + for (int direction = 0; direction < 4; direction++) { + int neighborRow = currentRow + dir[direction][0]; + int neighborCol = currentCol + dir[direction][1]; + // Check if the neighbor is within the grid bounds and not yet visited + if (isValidCell(neighborRow,neighborCol,rows,cols) && !visited[neighborRow][neighborCol]) { + int neighborHeight = heightMap[neighborRow][neighborCol]; + if (neighborHeight < waterLevel) { + trappedWater += waterLevel - neighborHeight; + } + pq.offer(new int[]{neighborHeight,neighborRow,neighborCol}); + visited[neighborRow][neighborCol] = true; + totalUnvisitedCells--; + } + } + } + return trappedWater; + } + + private boolean isValidCell(int row,int col,int rows,int cols) { + return row >= 0 && col >= 0 && row < rows && col < cols; + } +} \ No newline at end of file diff --git a/java/TraverseSpirally.class b/java/TraverseSpirally.class new file mode 100644 index 00000000..d95338bf Binary files /dev/null and b/java/TraverseSpirally.class differ diff --git a/java/TraverseSpirally.java b/java/TraverseSpirally.java new file mode 100644 index 00000000..a0b649eb --- /dev/null +++ b/java/TraverseSpirally.java @@ -0,0 +1,43 @@ +import java.util.ArrayList; + +public class TraverseSpirally { +// Function to return a list of integers denoting spiral traversal of matrix. + + public static ArrayList spirallyTraverse(int matrix[][]) { + ArrayList ans = new ArrayList<>(); + int l = 0, r = matrix[0].length - 1, t = 0, d = matrix.length - 1; + int i = 0, j = 0; + while( l <= r && t <= d){ + for(j = l; j <= r; j++) ans.add( matrix[t][j] ); + t++; + if( t > d) break; + for(i = t;i <= d; i++) ans.add( matrix[i][r] ); + r--; + if( r < l) break; + for(j = r; j >= l; j--) ans.add( matrix[d][j]); + d--; + if( t > d) break; + for(i = d; i >= t; i--) ans.add( matrix[i][l] ); + l++; + if( r < l) break; + } + return ans; + } + public static void main(String[] args) { + int[][] matrix = { + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9} + }; + + ArrayList spiralTraverseList = spirallyTraverse(matrix); + + // Print the rotated matrix + + for (int val : spiralTraverseList) { + System.out.print(val + " "); + } + + } + +} diff --git a/java/TwoPointer.java b/java/TwoPointer.java new file mode 100644 index 00000000..f9dbf04d --- /dev/null +++ b/java/TwoPointer.java @@ -0,0 +1,39 @@ +/** + * TwoPointer.java + * + * This class demonstrates the Two Pointer technique to find a pair + * in a sorted array whose sum equals a given target value. + * + * Time Complexity: O(n) + * Space Complexity: O(1) + */ +public class TwoPointer { + public static void pointer(int[] array, int target) { + int left = 0; // Initialize left pointer at start + int right = array.length - 1; // Initialize right pointer at end + + while (left < right) { + int sum = array[left] + array[right]; + + if (sum == target) { + System.out.println("Pair found: " + array[left] + " " + array[right]); + return; // Stop after finding the first pair + } else if (sum < target) { + left++; // Move left pointer to increase sum + } else { + right--; // Move right pointer to decrease sum + } + } + + // If no pair is found + System.out.println("No pair found"); + } + + // Sample main method to test the code + public static void main(String[] args) { + int[] array = {1, 2, 3, 4, 6}; + int target = 6; + + pointer(array, target); // Expected output: Pair found: 2 4 + } +} diff --git a/java/TwoSum1.java b/java/TwoSum1.java new file mode 100644 index 00000000..38e65137 --- /dev/null +++ b/java/TwoSum1.java @@ -0,0 +1,29 @@ +//LeetCode 1. Two Sum +//Question Link - https://leetcode.com/problems/two-sum/ + +class Solution { + public int[] twoSum(int[] nums, int target) { + int result[] = new int[2]; + + //to store the numbers which have already been encountered + //key = number in array, value = index of the number + Map seen = new HashMap<>(); + + for(int i = 0 ; i < nums.length ; i++){ + //the number nums[i] is alreday in the array + //check if (target - nums[i]) is also in the array or not + int complement = target - nums[i]; + + //we check if we have already encountered complement or not. + if(seen.containsKey(complement)){ + return new int[]{seen.get(complement), i}; + } + + //if complement does not exsist, we must store the current number in seen + //The current number could be the complement of some number to be visited further in the array + seen.put(nums[i], i); + } + + return result; + } +} diff --git a/java/Two_sum.java b/java/Two_sum.java new file mode 100644 index 00000000..fe527078 --- /dev/null +++ b/java/Two_sum.java @@ -0,0 +1,27 @@ +public class Two_sum { + public static void main(String[] args) { + int[] nums = {2, 7, 11, 15}; + int target = 9; + Solution solution = new Solution(); + int[] result = solution.twoSum(nums, target); + if (result != null) { + System.out.println("Indices: " + result[0] + ", " + result[1]); + } else { + System.out.println("No solution found."); + } + } +} + +class Solution { + public int[] twoSum(int[] nums, int target) { + int n = nums.length; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i] + nums[j] == target) { + return new int[]{i, j}; + } + } + } + return null; + } +} \ No newline at end of file diff --git a/java/UniquePaths.java b/java/UniquePaths.java new file mode 100644 index 00000000..c50c7628 --- /dev/null +++ b/java/UniquePaths.java @@ -0,0 +1,19 @@ +class Solution { + public int uniquePaths(int m, int n) { + int[][] dp = new int[m][n]; + for(int i=0; i0){ + Drinked+=numBottles; + Empty+=numBottles; + numBottles=0; + if(Empty>=numExchange){ + numBottles++; + } + Empty-=numExchange; + numExchange++; + } + return Drinked; + } +} + + +// Example 1: + +// Input: numBottles = 13, numExchange = 6 +// Output: 15 +// Explanation: The table above shows the number of full water bottles, empty water bottles, the value of numExchange, and the number of bottles drunk. + +// Example 2: + +// Input: numBottles = 10, numExchange = 3 +// Output: 13 +// Explanation: The table above shows the number of full water bottles, empty water bottles, the value of numExchange, and the number of bottles drunk. + +// Constraints: + +// 1 <= numBottles <= 100 +// 1 <= numExchange <= 100 \ No newline at end of file diff --git a/java/Waterbottles2.java b/java/Waterbottles2.java new file mode 100644 index 00000000..6c8dbe6c --- /dev/null +++ b/java/Waterbottles2.java @@ -0,0 +1,19 @@ +public class Waterbottles2 { + public static void main(String[] args) { + int numBottles = 13; + int numExchange = 6; + System.out.println(maxBottlesDrunk(numBottles, numExchange)); + } + public static int maxBottlesDrunk(int numBottles, int numExchange) { + int sum = numBottles; + int remain = numBottles; + while (remain >= numExchange) { + remain-=numExchange; + remain++; + sum++; + numExchange++; + } + return sum; + + } +} diff --git a/java/WeatherClothingAdvisor.java b/java/WeatherClothingAdvisor.java new file mode 100644 index 00000000..b7c8e820 --- /dev/null +++ b/java/WeatherClothingAdvisor.java @@ -0,0 +1,49 @@ +import java.util.Scanner; + +public class WeatherClothingAdvisor { + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + + System.out.print("Enter the temperature (°C): "); + int temperature = sc.nextInt(); + sc.nextLine(); // consume newline + + System.out.print("Enter weather condition (sunny, rainy, cloudy, windy): "); + String condition = sc.nextLine().toLowerCase(); + + System.out.println("\n👕 Clothing Advice:"); + suggestClothing(temperature, condition); + + sc.close(); + } + + public static void suggestClothing(int temp, String condition) { + if (temp < 10) { + System.out.println("It's quite cold! Wear a heavy jacket or coat."); + } else if (temp >= 10 && temp <= 20) { + System.out.println("Wear a light sweater or hoodie."); + } else if (temp > 20 && temp <= 30) { + System.out.println("It's warm. T-shirt and jeans would be fine."); + } else { + System.out.println("It's hot outside! Wear light cotton clothes."); + } + + switch (condition) { + case "rainy": + System.out.println("Don't forget to carry an umbrella ☔"); + break; + case "sunny": + System.out.println("Wear sunglasses and use sunscreen 😎"); + break; + case "windy": + System.out.println("Consider wearing a windbreaker 🧥"); + break; + case "cloudy": + System.out.println("Might be cool later, take a light jacket."); + break; + default: + System.out.println("Enjoy your day!"); + } + } +} diff --git a/java/WordPattern.java b/java/WordPattern.java new file mode 100644 index 00000000..a0eacf3d --- /dev/null +++ b/java/WordPattern.java @@ -0,0 +1,69 @@ +import java.util.HashMap; + +/** +Given a pattern and a string s, find if s follows the same pattern. + +Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in s. Specifically: + +Each letter in pattern maps to exactly one unique word in s. +Each unique word in s maps to exactly one letter in pattern. +No two letters map to the same word, and no two words map to the same letter. + +Example 1: + +Input: pattern = "abba", s = "dog cat cat dog" + +Output: true + +Explanation: + +The bijection can be established as: + +'a' maps to "dog". +'b' maps to "cat". +Example 2: + +Input: pattern = "abba", s = "dog cat cat fish" + +Output: false + +Example 3: + +Input: pattern = "aaaa", s = "dog cat cat dog" + +Output: false + + +Constraints: + +1 <= pattern.length <= 300 +pattern contains only lower-case English letters. +1 <= s.length <= 3000 +s contains only lowercase English letters and spaces ' '. +s does not contain any leading or trailing spaces. +All the words in s are separated by a single space. + +*/ + +public class WordPattern { + public boolean wordPattern(String pattern, String s) { + HashMap hm = new HashMap<>(); + String arr[] = s.trim().split("\\s+"); + if (pattern.length() != arr.length) return false; + for (int i = 0; i < pattern.length(); i++) { + char ch = pattern.charAt(i); + if (hm.containsKey(ch)) { + if (!hm.get(ch).equals(arr[i])) { + return false; + } + } + else { + if (hm.containsValue(arr[i])) + return false; + + hm.put(ch, arr[i]); + } + } + return true; + } +} \ No newline at end of file diff --git a/java/ash/one.java b/java/ash/one.java new file mode 100644 index 00000000..da233333 --- /dev/null +++ b/java/ash/one.java @@ -0,0 +1,11 @@ +public class AddStrings { + public static void main(String[] args) { + String str1 = "Hello"; + String str2 = "World"; + + // Adding (concatenating) two strings + String result = str1 + " " + str2; + + System.out.println("Result: " + result); + } +} diff --git a/java/ash/three.java b/java/ash/three.java new file mode 100644 index 00000000..cdea6e9c --- /dev/null +++ b/java/ash/three.java @@ -0,0 +1,14 @@ +public class AddStringsBuilder { + public static void main(String[] args) { + String str1 = "Java"; + String str2 = "Programming"; + + StringBuilder sb = new StringBuilder(); + sb.append(str1); + sb.append(" "); + sb.append(str2); + + String result = sb.toString(); + System.out.println("Result: " + result); + } +} diff --git a/java/ash/two.java b/java/ash/two.java new file mode 100644 index 00000000..44589bef --- /dev/null +++ b/java/ash/two.java @@ -0,0 +1,52 @@ +import java.util.*; +// saddle point is a element which is min in its row and max in its columns(one or no saddle point per matrix) +public class SaddlePoint{ + public static void main(String args []){ + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + int m = sc.nextInt(); + + int [][] arr = new int[n][m]; + + //Input for n*m + for(int i=0;imax){ + return false; + } + } + return true; + } + +} diff --git a/java/bellman_ford.java b/java/bellman_ford.java new file mode 100644 index 00000000..c0d60a04 --- /dev/null +++ b/java/bellman_ford.java @@ -0,0 +1,87 @@ + + import java.util.*; +public class bellman_ford { + + + static class Edge { + int src, dest, weight; + + Edge(int src, int dest, int weight) { + this.src = src; + this.dest = dest; + this.weight = weight; + } + } + + int V, E; + Edge[] edges; + + + bellman_ford(int v, int e) { + V = v; + E = e; + edges = new Edge[e]; + } + + + void bellmanFord(int src) { + int[] dist = new int[V]; + + + Arrays.fill(dist, Integer.MAX_VALUE); + dist[src] = 0; + + + for (int i = 1; i < V; ++i) { + for (int j = 0; j < E; ++j) { + int u = edges[j].src; + int v = edges[j].dest; + int weight = edges[j].weight; + + if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) { + dist[v] = dist[u] + weight; + } + } + } + + + for (int j = 0; j < E; ++j) { + int u = edges[j].src; + int v = edges[j].dest; + int weight = edges[j].weight; + if (dist[u] != Integer.MAX_VALUE && dist[u] + weight < dist[v]) { + System.out.println("Graph contains negative weight cycle!"); + return; + } + } + + + printSolution(dist); + } + + void printSolution(int[] dist) { + System.out.println("Vertex Distance from Source:"); + for (int i = 0; i < V; ++i) + System.out.println(i + "\t\t" + dist[i]); + } + + + public static void main(String[] args) { + int V = 5; + int E = 8; + + bellman_ford graph = new bellman_ford(V, E); + + graph.edges[0] = new Edge(0, 1, -1); + graph.edges[1] = new Edge(0, 2, 4); + graph.edges[2] = new Edge(1, 2, 3); + graph.edges[3] = new Edge(1, 3, 2); + graph.edges[4] = new Edge(1, 4, 2); + graph.edges[5] = new Edge(3, 2, 5); + graph.edges[6] = new Edge(3, 1, 1); + graph.edges[7] = new Edge(4, 3, -3); + + graph.bellmanFord(0); + } +} + diff --git a/java/binarySearch.java b/java/binarySearch.java index 2422cca0..7765267d 100644 --- a/java/binarySearch.java +++ b/java/binarySearch.java @@ -1,4 +1,4 @@ -public binarySearch { + public class binarySearch{ public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; @@ -29,5 +29,4 @@ public static void main(String[] args) { System.out.println("Element not found in the array."); } } - -} \ No newline at end of file + } \ No newline at end of file diff --git a/java/characterReplacement.java b/java/characterReplacement.java new file mode 100644 index 00000000..0541c0de --- /dev/null +++ b/java/characterReplacement.java @@ -0,0 +1,28 @@ +public class characterReplacement { + + public int charReplacement(String s, int k) { + int[] count = new int[26]; + int maxCount = 0; + int left = 0; + int result = 0; + + for (int right = 0; right < s.length(); right++) { + count[s.charAt(right) - 'A']++; + maxCount = Math.max(maxCount, count[s.charAt(right) - 'A']); + + while ((right - left + 1) - maxCount > k) { + count[s.charAt(left) - 'A']--; + left++; + } + result = Math.max(result, right - left + 1); + } + return result; + } + public static void main(String[] args) { + characterReplacement cr = new characterReplacement(); + String s = "AABABBA"; + int k = 1; + int result = cr.charReplacement(s, k); + System.out.println("The length of the longest substring after replacement is: " + result); + } +} diff --git a/java/clearBit.java b/java/clearBit.java new file mode 100644 index 00000000..88a474b5 --- /dev/null +++ b/java/clearBit.java @@ -0,0 +1,24 @@ +import java.util.* ; +public class clearBit { + public static void main(String args[]){ + Scanner sc = new Scanner(System.in); + + System.out.print("Enter the number : "); + + int num = sc.nextInt(); + + System.out.print("Enter the bit position to clear (0-indexed): "); + + int pos = sc.nextInt(); + + int bitMask = 1 << pos ; + + int nbitMask = ~bitMask ; + + int result = num & nbitMask; + + System.out.println("Number after clearing bit at position " + pos + " is: " + result); + + sc.close(); + } +} diff --git a/java/countDigitOne.java b/java/countDigitOne.java new file mode 100644 index 00000000..ab961daf --- /dev/null +++ b/java/countDigitOne.java @@ -0,0 +1,30 @@ +public class Solution { + public int countDigitOne(int n) { + int count = 0; + + for(long i = 1; i <= n; i *= 10) { + long left = n / (i * 10); + long current = (n / i) % 10; + long right = n % i; + + if (current == 0) { + count += left * i; + } else if (current == 1) { + count += left * i + right + 1; + } else { + count += (left + 1) * i; + } + } + return count; + } + + public static void main(String[] args) { + Solution solution = new Solution(); + + int n1 = 13; + int n2 = 0; + + System.out.println("Count of digit one up to " + n1 + " is: " + solution.countDigitOne(n1)); // Output: 6 + System.out.println("Count of digit one up to " + n2 + " is: " + solution.countDigitOne(n2)); // Output: 0 + } +} diff --git a/java/dsa-code.iml b/java/dsa-code.iml new file mode 100644 index 00000000..b107a2dd --- /dev/null +++ b/java/dsa-code.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/java/dynamic_programming/CoinChange.java b/java/dynamic_programming/CoinChange.java new file mode 100644 index 00000000..a8b248b8 --- /dev/null +++ b/java/dynamic_programming/CoinChange.java @@ -0,0 +1,344 @@ +/** + * Coin Change Problem - Dynamic Programming Solutions + * + * The coin change problem is a classic dynamic programming problem where + * we need to find the minimum number of coins needed to make a given amount. + * + * Problem Statement: + * Given a set of coin denominations and a target amount, find the minimum + * number of coins needed to make that amount. If it's not possible, return -1. + * + * Time Complexity: O(amount × coins.length) + * Space Complexity: O(amount) for optimized version + * + * Author: Hacktoberfest Contributor + * Date: October 2024 + */ + +import java.util.*; + +public class CoinChange { + + /** + * Approach 1: Bottom-up Dynamic Programming (Tabulation) + * Most efficient and commonly used approach + * + * @param coins Array of coin denominations + * @param amount Target amount to make + * @return Minimum number of coins needed, or -1 if impossible + */ + public static int coinChangeDP(int[] coins, int amount) { + if (amount == 0) return 0; + if (amount < 0) return -1; + + // dp[i] represents minimum coins needed to make amount i + int[] dp = new int[amount + 1]; + Arrays.fill(dp, amount + 1); // Initialize with impossible value + dp[0] = 0; // Base case: 0 coins needed for amount 0 + + // Fill dp table + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i >= coin) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + return dp[amount] > amount ? -1 : dp[amount]; + } + + /** + * Approach 2: Top-down Dynamic Programming (Memoization) + * Recursive approach with caching + * + * @param coins Array of coin denominations + * @param amount Target amount to make + * @return Minimum number of coins needed, or -1 if impossible + */ + public static int coinChangeMemo(int[] coins, int amount) { + Map memo = new HashMap<>(); + int result = coinChangeMemoHelper(coins, amount, memo); + return result == Integer.MAX_VALUE ? -1 : result; + } + + private static int coinChangeMemoHelper(int[] coins, int amount, Map memo) { + if (amount == 0) return 0; + if (amount < 0) return Integer.MAX_VALUE; + + if (memo.containsKey(amount)) { + return memo.get(amount); + } + + int minCoins = Integer.MAX_VALUE; + for (int coin : coins) { + int result = coinChangeMemoHelper(coins, amount - coin, memo); + if (result != Integer.MAX_VALUE) { + minCoins = Math.min(minCoins, result + 1); + } + } + + memo.put(amount, minCoins); + return minCoins; + } + + /** + * Approach 3: Coin Change II - Count number of ways to make amount + * + * @param coins Array of coin denominations + * @param amount Target amount to make + * @return Number of ways to make the amount + */ + public static int coinChangeWays(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + dp[0] = 1; // One way to make amount 0 (use no coins) + + // Process each coin + for (int coin : coins) { + // Update dp array for this coin + for (int i = coin; i <= amount; i++) { + dp[i] += dp[i - coin]; + } + } + + return dp[amount]; + } + + /** + * Approach 4: Reconstruct the actual coin combination + * Returns the actual coins used to make the amount + * + * @param coins Array of coin denominations + * @param amount Target amount to make + * @return List of coins used, empty list if impossible + */ + public static List coinChangeWithPath(int[] coins, int amount) { + if (amount == 0) return new ArrayList<>(); + + int[] dp = new int[amount + 1]; + int[] parent = new int[amount + 1]; // Track which coin was used + + Arrays.fill(dp, amount + 1); + Arrays.fill(parent, -1); + dp[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (int coin : coins) { + if (i >= coin && dp[i - coin] + 1 < dp[i]) { + dp[i] = dp[i - coin] + 1; + parent[i] = coin; + } + } + } + + if (dp[amount] > amount) { + return new ArrayList<>(); // Impossible to make amount + } + + // Reconstruct path + List result = new ArrayList<>(); + int curr = amount; + while (curr > 0) { + int coin = parent[curr]; + result.add(coin); + curr -= coin; + } + + return result; + } + + /** + * Approach 5: Space-optimized version for large amounts + * Uses BFS approach, good when amount is very large + * + * @param coins Array of coin denominations + * @param amount Target amount to make + * @return Minimum number of coins needed, or -1 if impossible + */ + public static int coinChangeBFS(int[] coins, int amount) { + if (amount == 0) return 0; + + Queue queue = new LinkedList<>(); + Set visited = new HashSet<>(); + + queue.offer(0); + visited.add(0); + int level = 0; + + while (!queue.isEmpty()) { + int size = queue.size(); + level++; + + for (int i = 0; i < size; i++) { + int curr = queue.poll(); + + for (int coin : coins) { + int next = curr + coin; + + if (next == amount) { + return level; + } + + if (next < amount && !visited.contains(next)) { + visited.add(next); + queue.offer(next); + } + } + } + } + + return -1; + } + + /** + * Utility method to print detailed analysis + */ + public static void analyzeTestCase(int[] coins, int amount) { + System.out.println("\\n" + "=".repeat(50)); + System.out.println("Test Case: coins = " + Arrays.toString(coins) + ", amount = " + amount); + System.out.println("=".repeat(50)); + + long startTime, endTime; + + // Test DP approach + startTime = System.nanoTime(); + int dpResult = coinChangeDP(coins, amount); + endTime = System.nanoTime(); + System.out.println("DP Result: " + dpResult + " (Time: " + (endTime - startTime) / 1000000.0 + " ms)"); + + // Test Memoization approach + startTime = System.nanoTime(); + int memoResult = coinChangeMemo(coins, amount); + endTime = System.nanoTime(); + System.out.println("Memo Result: " + memoResult + " (Time: " + (endTime - startTime) / 1000000.0 + " ms)"); + + // Test BFS approach + startTime = System.nanoTime(); + int bfsResult = coinChangeBFS(coins, amount); + endTime = System.nanoTime(); + System.out.println("BFS Result: " + bfsResult + " (Time: " + (endTime - startTime) / 1000000.0 + " ms)"); + + // Show number of ways + int ways = coinChangeWays(coins, amount); + System.out.println("Number of ways: " + ways); + + // Show actual coins used + List coinsUsed = coinChangeWithPath(coins, amount); + if (!coinsUsed.isEmpty()) { + System.out.println("Coins used: " + coinsUsed); + + // Verify the solution + int sum = coinsUsed.stream().mapToInt(Integer::intValue).sum(); + System.out.println("Verification: " + coinsUsed + " sum = " + sum + + (sum == amount ? " ✓" : " ✗")); + } else if (dpResult != -1) { + System.out.println("Error in path reconstruction!"); + } else { + System.out.println("No solution possible"); + } + } + + /** + * Comprehensive test suite with various scenarios + */ + public static void runComprehensiveTests() { + System.out.println("🪙 COIN CHANGE PROBLEM - COMPREHENSIVE SOLUTION"); + System.out.println("==============================================="); + + // Test Case 1: Standard case + analyzeTestCase(new int[]{1, 3, 4}, 6); + + // Test Case 2: Classic example + analyzeTestCase(new int[]{1, 5, 10, 25}, 30); + + // Test Case 3: No solution + analyzeTestCase(new int[]{3, 5}, 1); + + // Test Case 4: Large denomination + analyzeTestCase(new int[]{1, 2, 5}, 11); + + // Test Case 5: Single coin + analyzeTestCase(new int[]{1}, 10); + + // Test Case 6: Amount is 0 + analyzeTestCase(new int[]{1, 2, 5}, 0); + + // Test Case 7: Greedy vs DP difference + analyzeTestCase(new int[]{1, 3, 4}, 6); + + System.out.println("\\n" + "=".repeat(60)); + System.out.println("📊 ALGORITHM COMPARISON"); + System.out.println("=".repeat(60)); + System.out.println("1. Bottom-up DP: Most efficient, O(amount × coins) time"); + System.out.println("2. Top-down Memo: Intuitive recursive, same complexity"); + System.out.println("3. BFS: Good for very large amounts, space efficient"); + System.out.println("4. Path Reconstruction: Shows actual coins used"); + System.out.println("5. Counting Ways: Finds number of possible combinations"); + } + + /** + * Interactive demo for user input + */ + public static void interactiveDemo() { + Scanner scanner = new Scanner(System.in); + + System.out.println("\\n🎮 INTERACTIVE COIN CHANGE DEMO"); + System.out.println("================================="); + + System.out.print("Enter coin denominations (space-separated): "); + String[] coinStrings = scanner.nextLine().split("\\\\s+"); + int[] coins = Arrays.stream(coinStrings).mapToInt(Integer::parseInt).toArray(); + + System.out.print("Enter target amount: "); + int amount = scanner.nextInt(); + + analyzeTestCase(coins, amount); + + // Ask for another test + System.out.print("\\nTry another case? (y/n): "); + String choice = scanner.next(); + if (choice.toLowerCase().startsWith("y")) { + scanner.nextLine(); // Consume newline + interactiveDemo(); + } + } + + /** + * Main method - Entry point + */ + public static void main(String[] args) { + // Run comprehensive tests + runComprehensiveTests(); + + // Ask user if they want to try interactive demo + Scanner scanner = new Scanner(System.in); + System.out.print("\\nWould you like to try the interactive demo? (y/n): "); + String choice = scanner.nextLine(); + + if (choice.toLowerCase().startsWith("y")) { + interactiveDemo(); + } + + System.out.println("\\n🎯 Perfect for Hacktoberfest 2024!"); + System.out.println("Happy coding! 🚀"); + } +} + +/* + * Sample Inputs and Expected Outputs: + * + * Input: coins = [1,3,4], amount = 6 + * Output: 2 (use coins [3,3]) + * + * Input: coins = [2], amount = 3 + * Output: -1 (impossible) + * + * Input: coins = [1,5,10,25], amount = 30 + * Output: 2 (use coins [5,25]) + * + * Key Insights: + * 1. Greedy approach doesn't always work (e.g., coins=[1,3,4], amount=6) + * 2. DP builds solution from smaller subproblems + * 3. Multiple approaches help understand the problem better + * 4. Path reconstruction is useful for verification + */ \ No newline at end of file diff --git a/java/dynamic_programming/FrogJump.class b/java/dynamic_programming/FrogJump.class new file mode 100644 index 00000000..381a8f33 Binary files /dev/null and b/java/dynamic_programming/FrogJump.class differ diff --git a/java/dynamic_programming/FrogJump1.class b/java/dynamic_programming/FrogJump1.class new file mode 100644 index 00000000..279d11a8 Binary files /dev/null and b/java/dynamic_programming/FrogJump1.class differ diff --git a/java/dynamic_programming/FrogJump1.java b/java/dynamic_programming/FrogJump1.java new file mode 100644 index 00000000..6e08d0f9 --- /dev/null +++ b/java/dynamic_programming/FrogJump1.java @@ -0,0 +1,62 @@ +// FrogJump + + +// // A frog is crossing a river. The river is divided into some number of units, and at each unit, there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water. +// Given a list of stones positions (in units) in sorted ascending order, determine if the frog can cross the river by landing on the last stone. Initially, the frog is on the first stone and assumes the first jump must be 1 unit. +// If the frog's last jump was k units, its next jump must be either k - 1, k, or k + 1 units. The frog can only jump in the forward direction. + +import java.util.*; + + + +class FrogJump1{ + public boolean canCross(int[] stones) { + int n = stones.length; + if (n == 2) { + return stones[1] == 1; + } + Map> reachable = new HashMap<>(); + for (int i = 0; i < n; i++) { + reachable.put(i, new HashSet<>()); + } + reachable.get(0).add(0); + + Map stonePositions = new HashMap<>(); + for (int i = 0; i < n; i++) { + stonePositions.put(stones[i], i); + } + + for (int i = 0; i < n; i++) { + for (int lastJump : new HashSet<>(reachable.get(i))) { + for (int nextJump : new int[]{lastJump - 1, lastJump, lastJump + 1}) { + if (nextJump > 0) { + int nextPos = stones[i] + nextJump; + if (stonePositions.containsKey(nextPos)) { + int nextIndex = stonePositions.get(nextPos); + reachable.get(nextIndex).add(nextJump); + } + } + } + } + } + + return !reachable.get(n - 1).isEmpty(); + + } + + + public static void main(String[] args) { + FrogJump1 frogJump = new FrogJump1(); + int[] stones1 = {0,1,3,5,6,8,12,17}; + System.out.println(frogJump.canCross(stones1)); + + int[] stones2 = {0,1,2,3,4,8,9,11}; + System.out.println(frogJump.canCross(stones2)); + + + + } + +} + + \ No newline at end of file diff --git a/java/dynamic_programming/PaintHouse/paintHouse1.java b/java/dynamic_programming/PaintHouse/paintHouse1.java new file mode 100644 index 00000000..73ac37a2 --- /dev/null +++ b/java/dynamic_programming/PaintHouse/paintHouse1.java @@ -0,0 +1,99 @@ +// There is a row of n houses, where each house can be painted one of three colors: red, blue, or green. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color. + +// The cost of painting each house with a certain color is represented by an n x 3 cost matrix costs. + +// For example, costs[0][0] is the cost of painting house 0 with the color red; costs[1][2] is the cost of painting house 1 with color green, and so on... +// Return the minimum cost to paint all houses. + + + +// Example 1: + +// Input: costs = [[17,2,17],[16,16,5],[14,3,19]] +// Output: 10 +// Explanation: Paint house 0 into blue, paint house 1 into green, paint house 2 into blue. +// Minimum cost: 2 + 5 + 3 = 10. +// Example 2: + +// Input: costs = [[7,6,2]] +// Output: 2 + +/* +Algorithm Description: +---------------------- +This solution uses recursion with memoization (top-down dynamic programming) to find the minimum cost to paint all houses such that no two adjacent houses have the same color. +- For each house, we try all possible colors (red, blue, green) except the color used for the previous house. +- We recursively compute the minimum cost for each choice and use a memoization table (dp) to avoid recomputation. +- The recursion starts from the first house with no previous color (-1). + +Complexity Analysis: +-------------------- +Let n be the number of houses. +- Time Complexity: O(n * 3), since for each house and each color, we compute the result once and memoize it. +- Space Complexity: O(n * 3) for the memoization table. +*/ + +package dynamic_programming.PaintHouse; + +import java.util.Arrays; + +public class paintHouse1 { + /** + * Recursive helper function to calculate the minimum cost to paint houses from index i onwards, + * given that the previous house was painted with color 'col'. + * @param i Current house index + * @param col Color used for the previous house (-1 if no previous house) + * @param dp Memoization table + * @param a Cost matrix + * @return Minimum cost to paint from house i to the end + */ + private int f(int i, int col, int[][] dp, int[][] a) { + // Base case: If all houses are painted, cost is 0 + if(i >= a.length){ + return 0; + } + // Return cached result if already computed + if(col != -1 && dp[i][col] != -1){ + return dp[i][col]; + } + + if(col == -1){ + // No previous color, try all three colors for the first house + int red = f(i+1,0,dp,a) + a[i][0]; + int blue = f(i+1,1,dp,a) + a[i][1]; + int green = f(i+1,2,dp,a) + a[i][2]; + return Math.min(red, Math.min(blue,green)); + } + + // For each color, try the other two colors for the next house + if(col == 0) { + // Previous was red, so try blue and green + dp[i][col] = Math.min(f(i+1,1,dp,a)+ a[i][1], f(i+1,2,dp,a)+ a[i][2]); + } + if(col == 1) { + // Previous was blue, so try red and green + dp[i][col] = Math.min(f(i+1,0,dp,a)+ a[i][0], f(i+1,2,dp,a) + a[i][2]); + } + if(col == 2) { + // Previous was green, so try blue and red + dp[i][col] = Math.min(f(i+1,1,dp,a)+ a[i][1], f(i+1,0,dp,a)+ a[i][0]); + } + return dp[i][col]; + } + + /** + * Calculates the minimum cost to paint all houses such that no two adjacent houses have the same color. + * @param a Cost matrix + * @return Minimum total cost + */ + public int minCost(int[][] a) { + int n = a.length; + int[][] dp = new int[n+1][4]; + // Initialize dp table with -1 (uncomputed) + for(int[] r:dp){ + Arrays.fill(r,-1); + } + // Start from the first house, with no previous color (-1) + return f(0,-1,dp,a); + } +} diff --git a/java/dynamic_programming/PaintHouse/paintHouse2.java b/java/dynamic_programming/PaintHouse/paintHouse2.java new file mode 100644 index 00000000..5720990e --- /dev/null +++ b/java/dynamic_programming/PaintHouse/paintHouse2.java @@ -0,0 +1,97 @@ +// There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color. + +// The cost of painting each house with a certain color is represented by an n x k cost matrix costs. + +// For example, costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of painting house 1 with color 2, and so on... +// Return the minimum cost to paint all houses. + + + +// Example 1: + +// Input: costs = [[1,5,3],[2,9,4]] +// Output: 5 +// Explanation: +// Paint house 0 into color 0, paint house 1 into color 2. Minimum cost: 1 + 4 = 5; +// Or paint house 0 into color 2, paint house 1 into color 0. Minimum cost: 3 + 2 = 5. +// Example 2: + +// Input: costs = [[1,3],[2,4]] +// Output: 5 + +/* +Algorithm Description: +---------------------- +This solution uses recursion with memoization (top-down dynamic programming) to find the minimum cost to paint all houses such that no two adjacent houses have the same color. +- For each house, we try all possible colors except the color used for the previous house. +- We recursively compute the minimum cost for each choice and use a memoization table (dp) to avoid recomputation. +- The recursion starts from the first house with no previous color (-1). + +Complexity Analysis: +-------------------- +Let n be the number of houses and k be the number of colors. +- Time Complexity: O(n * k^2), since for each house and each color, we try up to k-1 colors for the next house and memoize results. +- Space Complexity: O(n * k) for the memoization table. +*/ + +package dynamic_programming.PaintHouse; + +import java.util.Arrays; + +public class paintHouse2 { + /** + * Recursive helper function to calculate the minimum cost to paint houses from index i onwards, + * given that the previous house was painted with color 'col'. + * @param i Current house index + * @param col Color used for the previous house (-1 if no previous house) + * @param a Cost matrix + * @param dp Memoization table + * @return Minimum cost to paint from house i to the end + */ + private int f(int i, int col, int[][] a, int[][] dp) { + // Base case: If all houses are painted, cost is 0 + if(i >= a.length) { + return 0; + } + // Return cached result if already computed + if(col != -1 && dp[i][col] != -1) { + return dp[i][col]; + } + + int mini = Integer.MAX_VALUE; + + if(col == -1){ + // No previous color, try all colors for the first house + for(int j = 0; j < a[i].length; j++){ + mini = Math.min(mini,a[i][j] + f(i+1,j,a,dp)); + } + return mini; + } + + // Try all colors except the previous color for the current house + for(int j = 0; j < a[i].length; j++){ + // for colour a[i][j], we need to find minimum cost + if(j != col) { + mini = Math.min(mini, a[i][j] + f(i+1,j,a,dp)); + } + } + // Store result in dp table and return + return dp[i][col] = mini; + } + + /** + * Calculates the minimum cost to paint all houses such that no two adjacent houses have the same color. + * @param a Cost matrix + * @return Minimum total cost + */ + public int minCostII(int[][] a) { + int n = a.length, k = a[0].length; + int[][] dp = new int[n+1][k+1]; + // Initialize dp table with -1 (uncomputed) + for(int[] r : dp) { + Arrays.fill(r,-1); + } + // Start from the first house, with no previous color (-1) + return f(0,-1,a,dp); + } +} diff --git a/java/dynamic_programming/UniquePathsii.class b/java/dynamic_programming/UniquePathsii.class new file mode 100644 index 00000000..a6290693 Binary files /dev/null and b/java/dynamic_programming/UniquePathsii.class differ diff --git a/java/dynamic_programming/UniquePathsii.java b/java/dynamic_programming/UniquePathsii.java new file mode 100644 index 00000000..94553a08 --- /dev/null +++ b/java/dynamic_programming/UniquePathsii.java @@ -0,0 +1,105 @@ + + +// Unique Paths II + +// You are given an m x n integer array grid. There is a robot initially located at the top-left corner (i.e., grid[0][0]). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]). The robot can only move either down or right at any point in time. +// An obstacle and space are marked as 1 or 0 respectively in grid. A path that the robot takes cannot include any square that is an obstacle. +// Return the number of possible unique paths that the robot can take to reach the bottom-right corner. +// The testcases are generated so that the answer will be less than or equal to 2 * 109. + + +class UniquePathsii{ + public int uniquePathsWithObstacles(int[][] obstacleGrid) { + int m = obstacleGrid.length; + int n= obstacleGrid[0].length; + + + int dp[][] = new int[m][n]; + + // for(int i = 0 ; i=0 && j>=0 ) && obstacleGRid[i][j] ==1){ + return 0; + } + + if(i==0 && j==0){ + return 1; + } + + if(dp[i][j]!=-1){ + return dp[i][j]; + } + + int up = mazememo(i-1,j,obstacleGRid,dp ); + int left = mazememo(i,j-1, obstacleGRid, dp); + + dp[i][j] = up+left; + + return dp[i][j]; + } + + public int tabulation( int[][] obstacleGrid){ + int m = obstacleGrid.length; + int n= obstacleGrid[0].length; + + int dp[][] = new int[m][n]; + for(int i =0; i0) up = dp[i-1][j]; + if(j>0) left = dp[i][j-1]; + + dp[i][j] = up + left; + + } + + } + } + + return dp[m-1][n-1]; + + } + + + public static void main(String[] args) { + UniquePathsii uniquePathsii = new UniquePathsii(); + int[][] obstacleGrid = { + {0,0,0}, + {0,1,0}, + {0,0,0} + }; + + System.out.println(uniquePathsii.uniquePathsWithObstacles(obstacleGrid)); + } + + + + +} \ No newline at end of file diff --git a/java/dynamic_programming/smallestNumberOfNeighbour.class b/java/dynamic_programming/smallestNumberOfNeighbour.class new file mode 100644 index 00000000..4c37e685 Binary files /dev/null and b/java/dynamic_programming/smallestNumberOfNeighbour.class differ diff --git a/java/dynamic_programming/smallestNumberOfNeighbour.java b/java/dynamic_programming/smallestNumberOfNeighbour.java new file mode 100644 index 00000000..b44fe563 --- /dev/null +++ b/java/dynamic_programming/smallestNumberOfNeighbour.java @@ -0,0 +1,80 @@ +// Find the City With the Smallest Number of Neighbors at a Threshold Distance + + +// There are n cities numbered from 0 to n-1. Given the array edges where edges[i] = [fromi, toi, weighti] represents a bidirectional and weighted edge between cities fromi and toi, and given the integer distanceThreshold. +// Return the city with the smallest number of cities that are reachable through some path and whose distance is at most distanceThreshold, If there are multiple such cities, return the city with the greatest number. +// Notice that the distance of a path connecting cities i and j is equal to the sum of the edges' weights along that path. + + + + +class smallestNumberOfNeighbour { + public int findTheCity(int n, int[][] edges, int distanceThreshold) { + + int INF = 10001; + int [][] dist = new int[n][n]; + + for(int i=0;i " + sol.isPowerOfTwo(num)); + } + } +} diff --git a/java/javac ExecutorServiceDemo.java b/java/javac ExecutorServiceDemo.java new file mode 100644 index 00000000..3872afea --- /dev/null +++ b/java/javac ExecutorServiceDemo.java @@ -0,0 +1,42 @@ +// 9. ExecutorService thread pool executing multiple tasks: print numbers and factorial calculation +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +class PrintNumbersTask implements Runnable { + public void run() { + for (int i = 1; i <= 5; i++) { + System.out.println(Thread.currentThread().getName() + " prints: " + i); + try { Thread.sleep(100); } catch (InterruptedException e) {} + } + } +} + +class FactorialTask implements Runnable { + private int number; + + public FactorialTask(int number) { + this.number = number; + } + + private long factorial(int n) { + if (n <= 1) return 1; + else return n * factorial(n - 1); + } + + public void run() { + long fact = factorial(number); + System.out.println(Thread.currentThread().getName() + " factorial of " + number + " is " + fact); + } +} + +class ExecutorServiceDemo { + public static void main(String[] args) { + ExecutorService executor = Executors.newFixedThreadPool(3); + + executor.execute(new PrintNumbersTask()); + executor.execute(new FactorialTask(5)); + executor.execute(new PrintNumbersTask()); + + executor.shutdown(); + } +} diff --git a/java/leetcode.java b/java/leetcode.java new file mode 100644 index 00000000..f85cad0d --- /dev/null +++ b/java/leetcode.java @@ -0,0 +1,26 @@ +import java.util.*; + +public class leetcode { + public static int[] twoSum(int[] nums, int target) { + Map map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + int complement = target - nums[i]; + if (map.containsKey(complement)) { + return new int[] { map.get(complement), i }; + } + map.put(nums[i], i); + } + + // if no solution found (shouldn’t happen per problem statement) + throw new IllegalArgumentException("No two sum solution"); + } + + public static void main(String[] args) { + int[] nums = {2, 7, 11, 15}; + int target = 9; + + int[] result = twoSum(nums, target); + System.out.println(Arrays.toString(result)); + } +} diff --git a/java/leetcode_contest/weekly_472/q1.java b/java/leetcode_contest/weekly_472/q1.java new file mode 100644 index 00000000..901955b0 --- /dev/null +++ b/java/leetcode_contest/weekly_472/q1.java @@ -0,0 +1,17 @@ +//3718. Smallest Missing Multiple of K +// Weekly Contest 472 Question 1 in Java +import java.util.*; + +class Solution { + public int missingMultiple(int[] nums, int k) { + Set s = new HashSet<>(); + for (int num : nums) { + s.add(num); + } + int current = k; + while (s.contains(current)) { + current += k; + } + return current; + } +} diff --git a/java/lowest_common_ancestor.java b/java/lowest_common_ancestor.java new file mode 100644 index 00000000..80e85488 --- /dev/null +++ b/java/lowest_common_ancestor.java @@ -0,0 +1,64 @@ +import java.util.*; + +class TreeNode { + int val; + TreeNode left; + TreeNode right; + + TreeNode(int x) { + val = x; + left = null; + right = null; + } +} + +public class ZigzagTraversal { + + public static List> zigzagLevelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if (root == null) return result; + + Queue queue = new LinkedList<>(); + queue.offer(root); + boolean leftToRight = true; + + while (!queue.isEmpty()) { + int size = queue.size(); + List level = new ArrayList<>(Collections.nCopies(size, 0)); + + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + int index = leftToRight ? i : size - 1 - i; + level.set(index, node.val); + + if (node.left != null) queue.offer(node.left); + if (node.right != null) queue.offer(node.right); + } + + leftToRight = !leftToRight; + result.add(level); + } + + return result; + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(2); + root.right = new TreeNode(3); + root.left.left = new TreeNode(4); + root.left.right = new TreeNode(5); + root.right.left = new TreeNode(6); + root.right.right = new TreeNode(7); + + List> zigzag = zigzagLevelOrder(root); + + System.out.println("Zigzag Traversal:"); + for (List level : zigzag) { + for (int val : level) { + System.out.print(val + " "); + } + System.out.println(); + } + } +} diff --git a/java/mergeSort.java b/java/mergeSort.java new file mode 100644 index 00000000..e69de29b diff --git a/java/mergeSort1.java b/java/mergeSort1.java new file mode 100644 index 00000000..caac556a --- /dev/null +++ b/java/mergeSort1.java @@ -0,0 +1,135 @@ +/** + * MergeSort.java + * + * Implementation of Merge Sort algorithm in Java. + * + * Merge Sort is a classic Divide and Conquer algorithm that: + * 1. Divides the array into two halves. + * 2. Recursively sorts both halves. + * 3. Merges the two sorted halves into a single sorted array. + * + * Time Complexity: O(n log n) + * Space Complexity: O(n) + * + * Author: Pushpak M. Jaiswal + * Date: October 2025 + */ + +package algorithms.sorting; + +import java.util.Arrays; + +public class MergeSort { + + /** + * Main mergeSort function — recursively divides the array + * and merges the sorted halves. + * + * @param arr the array to be sorted + * @param left starting index + * @param right ending index + */ + public static void mergeSort(int[] arr, int left, int right) { + if (left < right) { + // Find the middle index + int mid = (left + right) / 2; + + // Recursively sort first and second halves + mergeSort(arr, left, mid); + mergeSort(arr, mid + 1, right); + + // Merge the sorted halves + merge(arr, left, mid, right); + } + } + + /** + * Helper function to merge two sorted subarrays. + * Subarray 1: arr[left..mid] + * Subarray 2: arr[mid+1..right] + * + * @param arr the array being sorted + * @param left starting index + * @param mid middle index + * @param right ending index + */ + private static void merge(int[] arr, int left, int mid, int right) { + // Find sizes of two subarrays to be merged + int n1 = mid - left + 1; + int n2 = right - mid; + + // Create temporary arrays + int[] L = new int[n1]; + int[] R = new int[n2]; + + // Copy data to temp arrays + for (int i = 0; i < n1; ++i) + L[i] = arr[left + i]; + for (int j = 0; j < n2; ++j) + R[j] = arr[mid + 1 + j]; + + // Merge the temp arrays back into arr[left..right] + int i = 0, j = 0; + int k = left; + + while (i < n1 && j < n2) { + if (L[i] <= R[j]) { + arr[k] = L[i]; + i++; + } else { + arr[k] = R[j]; + j++; + } + k++; + } + + // Copy remaining elements of L[] if any + while (i < n1) { + arr[k] = L[i]; + i++; + k++; + } + + // Copy remaining elements of R[] if any + while (j < n2) { + arr[k] = R[j]; + j++; + k++; + } + } + + /** + * Utility function to print arrays in readable format. + */ + private static void printArray(String msg, int[] arr) { + System.out.println(msg + Arrays.toString(arr)); + } + + /** + * Main method containing sample test cases. + */ + public static void main(String[] args) { + // 1. Small Array + int[] smallArray = {38, 27, 43, 3, 9, 82, 10}; + mergeSort(smallArray, 0, smallArray.length - 1); + printArray("Sorted Small Array: ", smallArray); + + // 2. Large Array + int[] largeArray = new int[20]; + for (int i = 0; i < 20; i++) { + largeArray[i] = (int) (Math.random() * 100); + } + mergeSort(largeArray, 0, largeArray.length - 1); + printArray("Sorted Large Array: ", largeArray); + + // 3. Already Sorted Array + int[] sortedArray = {1, 2, 3, 4, 5, 6, 7}; + mergeSort(sortedArray, 0, sortedArray.length - 1); + printArray("Already Sorted Array: ", sortedArray); + + // 4. Reverse-Sorted Array + int[] reverseArray = {9, 7, 5, 3, 1}; + mergeSort(reverseArray, 0, reverseArray.length - 1); + printArray("Reverse-Sorted Array: ", reverseArray); + } +} diff --git a/java/mergeTwoLists.java b/java/mergeTwoLists.java new file mode 100644 index 00000000..3314bd92 --- /dev/null +++ b/java/mergeTwoLists.java @@ -0,0 +1,101 @@ +// MergeTwoLists.java +public class mergeTwoLists { + + // Definition for singly-linked list node. + static class ListNode { + int val; + ListNode next; + ListNode() {} + ListNode(int val) { this.val = val; } + ListNode(int val, ListNode next) { this.val = val; this.next = next; } + } + + // Iterative approach: merges two sorted lists and returns the head of the merged list. + public static ListNode mergeTwoListsIterative(ListNode l1, ListNode l2) { + ListNode dummy = new ListNode(-1); // dummy head + ListNode tail = dummy; + + while (l1 != null && l2 != null) { + if (l1.val <= l2.val) { + tail.next = l1; + l1 = l1.next; + } else { + tail.next = l2; + l2 = l2.next; + } + tail = tail.next; + } + + // attach remaining nodes + tail.next = (l1 != null) ? l1 : l2; + + return dummy.next; + } + + // Recursive approach: merges two sorted lists (clean and concise). + public static ListNode mergeTwoListsRecursive(ListNode l1, ListNode l2) { + if (l1 == null) return l2; + if (l2 == null) return l1; + + if (l1.val <= l2.val) { + l1.next = mergeTwoListsRecursive(l1.next, l2); + return l1; + } else { + l2.next = mergeTwoListsRecursive(l1, l2.next); + return l2; + } + } + + // Helper: build linked list from array, returns head. + public static ListNode buildList(int[] arr) { + ListNode dummy = new ListNode(-1); + ListNode tail = dummy; + for (int v : arr) { + tail.next = new ListNode(v); + tail = tail.next; + } + return dummy.next; + } + + // Helper: print linked list. + public static void printList(ListNode head) { + ListNode cur = head; + while (cur != null) { + System.out.print(cur.val); + if (cur.next != null) System.out.print(" -> "); + cur = cur.next; + } + System.out.println(); + } + + // Example usage and simple tests. + public static void main(String[] args) { + // Example 1 + int[] a1 = {1, 2, 4}; + int[] b1 = {1, 3, 4}; + ListNode l1 = buildList(a1); + ListNode l2 = buildList(b1); + + System.out.print("List A: "); + printList(l1); + System.out.print("List B: "); + printList(l2); + + ListNode mergedIter = mergeTwoListsIterative(l1, l2); + System.out.print("Merged (iterative): "); + printList(mergedIter); + + // For recursive test, recreate lists (previous merge re-used nodes). + l1 = buildList(a1); + l2 = buildList(b1); + ListNode mergedRec = mergeTwoListsRecursive(l1, l2); + System.out.print("Merged (recursive): "); + printList(mergedRec); + + // Example 2: one list empty + ListNode empty = null; + ListNode single = buildList(new int[]{0}); + System.out.print("Merged (one empty): "); + printList(mergeTwoListsIterative(empty, single)); + } +} diff --git a/java/moveZeros.java b/java/moveZeros.java new file mode 100644 index 00000000..696f5ba5 --- /dev/null +++ b/java/moveZeros.java @@ -0,0 +1,29 @@ +import java.util.Arrays; + +public class moveZeros { + + public void moveZeroes(int[] nums) { + int j = 0; // pointer for non-zero position + + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + // Swap nums[i] with nums[j] + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + j++; + } + } + } + + public static void main(String[] args) { + moveZeros mz = new moveZeros(); + + int[] nums = {0, 1, 0, 3, 12}; + System.out.println("Before: " + Arrays.toString(nums)); + + mz.moveZeroes(nums); + + System.out.println("After: " + Arrays.toString(nums)); + } +} diff --git a/java/movierenting.java b/java/movierenting.java new file mode 100644 index 00000000..670c8a2d --- /dev/null +++ b/java/movierenting.java @@ -0,0 +1,88 @@ +class MovieRentingSystem { + private static class Node { + final int shop; + final int movie; + final int price; + Node(int shop, int movie, int price) { + this.shop = shop; + this.movie = movie; + this.price = price; + } + } + + // Order: price ↑, shop ↑, movie ↑ (strict: never returns 0 for distinct nodes) + private static final Comparator CMP = + (a, b) -> { + int c = Integer.compare(a.price, b.price); + if (c != 0) return c; + c = Integer.compare(a.shop, b.shop); + if (c != 0) return c; + return Integer.compare(a.movie, b.movie); + }; + + // Available copies grouped by movie + private final Map> availableByMovie = new HashMap<>(); + // All currently rented copies + private final TreeSet rentedSet = new TreeSet<>(CMP); + // Quick lookup from (shop, movie) -> Node + private final Map byPair = new HashMap<>(); + + private static long key(int shop, int movie) { + return (((long) shop) << 32) ^ (movie & 0xffffffffL); + } + + public MovieRentingSystem(int n, int[][] entries) { + for (int[] e : entries) { + int shop = e[0], movie = e[1], price = e[2]; + Node node = new Node(shop, movie, price); + byPair.put(key(shop, movie), node); + availableByMovie + .computeIfAbsent(movie, k -> new TreeSet<>(CMP)) + .add(node); + } + } + + // Return up to 5 shops with this movie, cheapest then shop asc. + public List search(int movie) { + List ans = new ArrayList<>(5); + TreeSet set = availableByMovie.get(movie); + if (set == null || set.isEmpty()) return ans; + Iterator it = set.iterator(); + for (int i = 0; i < 5 && it.hasNext(); i++) { + ans.add(it.next().shop); + } + return ans; + } + + // Move (shop,movie) from available -> rented + public void rent(int shop, int movie) { + long k = key(shop, movie); + Node node = byPair.get(k); + if (node == null) return; // defensive + TreeSet set = availableByMovie.get(movie); + if (set != null) set.remove(node); + rentedSet.add(node); + } + + // Move (shop,movie) from rented -> available + public void drop(int shop, int movie) { + long k = key(shop, movie); + Node node = byPair.get(k); + if (node == null) return; // defensive + rentedSet.remove(node); + availableByMovie + .computeIfAbsent(movie, x -> new TreeSet<>(CMP)) + .add(node); + } + + // Return up to 5 rented copies [shop, movie], cheapest then shop asc, then movie asc. + public List> report() { + List> ans = new ArrayList<>(5); + Iterator it = rentedSet.iterator(); + for (int i = 0; i < 5 && it.hasNext(); i++) { + Node n = it.next(); + ans.add(Arrays.asList(n.shop, n.movie)); + } + return ans; + } +} diff --git a/java/oddReven.java b/java/oddReven.java new file mode 100644 index 00000000..e41db230 --- /dev/null +++ b/java/oddReven.java @@ -0,0 +1,18 @@ + +import java.util.Scanner; + +public class oddReven{ + public static void main(String[] args) { + + Scanner sc=new Scanner(System.in); + System.out.println("enter the number"); + int n=sc.nextInt(); + for(int i=1;i<=n;i++){ + if(n%2==0){ + System.out.println(n + "is even number"); + }else{ + System.out.println(n + "is odd number"); + } + } + } + } \ No newline at end of file diff --git a/java/out/production/dsa-code/.idea/.gitignore b/java/out/production/dsa-code/.idea/.gitignore new file mode 100644 index 00000000..26d33521 --- /dev/null +++ b/java/out/production/dsa-code/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/java/out/production/dsa-code/.idea/misc.xml b/java/out/production/dsa-code/.idea/misc.xml new file mode 100644 index 00000000..6f29fee2 --- /dev/null +++ b/java/out/production/dsa-code/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java/out/production/dsa-code/.idea/modules.xml b/java/out/production/dsa-code/.idea/modules.xml new file mode 100644 index 00000000..07f2a9b1 --- /dev/null +++ b/java/out/production/dsa-code/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/java/out/production/dsa-code/.idea/vcs.xml b/java/out/production/dsa-code/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/java/out/production/dsa-code/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java/out/production/dsa-code/1518-Water-Bottles/README.md b/java/out/production/dsa-code/1518-Water-Bottles/README.md new file mode 100644 index 00000000..b451fa94 --- /dev/null +++ b/java/out/production/dsa-code/1518-Water-Bottles/README.md @@ -0,0 +1,32 @@ +

    Water Bottles

    Difficulty: Easy

    There are numBottles water bottles that are initially full of water. You can exchange numExchange empty water bottles from the market with one full water bottle.

    + +

    The operation of drinking a full water bottle turns it into an empty bottle.

    + +

    Given the two integers numBottles and numExchange, return the maximum number of water bottles you can drink.

    + +

     

    +

    Example 1:

    + +
    +Input: numBottles = 9, numExchange = 3
    +Output: 13
    +Explanation: You can exchange 3 empty bottles to get 1 full water bottle.
    +Number of water bottles you can drink: 9 + 3 + 1 = 13.
    +
    + +

    Example 2:

    + +
    +Input: numBottles = 15, numExchange = 4
    +Output: 19
    +Explanation: You can exchange 4 empty bottles to get 1 full water bottle. 
    +Number of water bottles you can drink: 15 + 3 + 1 = 19.
    +
    + +

     

    +

    Constraints:

    + +
      +
    • 1 <= numBottles <= 100
    • +
    • 2 <= numExchange <= 100
    • +
    diff --git a/java/out/production/dsa-code/407-traping-rain-water-ii/README.md b/java/out/production/dsa-code/407-traping-rain-water-ii/README.md new file mode 100644 index 00000000..78585511 --- /dev/null +++ b/java/out/production/dsa-code/407-traping-rain-water-ii/README.md @@ -0,0 +1,29 @@ +

    Trapping Rain Water II

    Difficulty: Hard

    Given an m x n integer matrix heightMap representing the height of each unit cell in a 2D elevation map, return the volume of water it can trap after raining.

    + +

     

    +

    Example 1:

    + +
    +Input: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
    +Output: 4
    +Explanation: After the rain, water is trapped between the blocks.
    +We have two small ponds 1 and 3 units trapped.
    +The total volume of water trapped is 4.
    +
    + +

    Example 2:

    + +
    +Input: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]]
    +Output: 10
    +
    + +

     

    +

    Constraints:

    + +
      +
    • m == heightMap.length
    • +
    • n == heightMap[i].length
    • +
    • 1 <= m, n <= 200
    • +
    • 0 <= heightMap[i][j] <= 2 * 104
    • +
    diff --git a/java/out/production/dsa-code/42-trapping-rain-water/README.md b/java/out/production/dsa-code/42-trapping-rain-water/README.md new file mode 100644 index 00000000..fb9f3ae5 --- /dev/null +++ b/java/out/production/dsa-code/42-trapping-rain-water/README.md @@ -0,0 +1,26 @@ +

    Trapping Rain Water

    Difficulty: Hard

    Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it can trap after raining.

    + +

     

    +

    Example 1:

    + +
    +Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
    +Output: 6
    +Explanation: The above elevation map (black section) is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped.
    +
    + +

    Example 2:

    + +
    +Input: height = [4,2,0,3,2,5]
    +Output: 9
    +
    + +

     

    +

    Constraints:

    + +
      +
    • n == height.length
    • +
    • 1 <= n <= 2 * 104
    • +
    • 0 <= height[i] <= 105
    • +
    diff --git a/java/out/production/dsa-code/BuyAndSellStock2Onwards/QuestionLinks b/java/out/production/dsa-code/BuyAndSellStock2Onwards/QuestionLinks new file mode 100644 index 00000000..be963a4c --- /dev/null +++ b/java/out/production/dsa-code/BuyAndSellStock2Onwards/QuestionLinks @@ -0,0 +1,11 @@ +714. Best Time to Buy and Sell Stock with Transaction Fee :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/description/ + +309. Best Time to Buy and Sell Stock with Cooldown :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/ + +188. Best Time to Buy and Sell Stock IV :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/ + +123. Best Time to Buy and Sell Stock III :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/ + +122. Best Time to Buy and Sell Stock II :- https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/description/ + + diff --git a/java/out/production/dsa-code/Levenshtein_distance/ReadMe.md b/java/out/production/dsa-code/Levenshtein_distance/ReadMe.md new file mode 100644 index 00000000..1901a99e --- /dev/null +++ b/java/out/production/dsa-code/Levenshtein_distance/ReadMe.md @@ -0,0 +1,45 @@ +### Edit Distance AKA ( Levenshtein Distance ) +- Levenshtein distance is a measure of the similarity between two strings, which takes into account the number of insertion, deletion and substitution operations needed to transform one string into the other. + +**Problem statement:** +- Given two words word1 and word2, return the minimum number of operations required to convert word1 to word2. + You have these operations permitted on a word: + - Insert a character + - Delete a character + - Replace a character + +- Example 1: + Input: word1 = "horse", word2 = "ros" + Output: 3 + Explanation: + horse → rorse (replace ‘h’ with ‘r’) + rorse → rose (remove ‘r’) + rose → ros (remove ‘e’) + +- Example 2: + Input: word1 = "intention", word2 = "execution" + Output: 5 + Explanation: + intention -> inention (remove 't') + inention -> enention (replace 'i' with 'e') + enention -> exention (replace 'n' with 'x') + exention -> exection (replace 'n' with 'c') + exection -> execution (insert 'u') + +- Constraints: + 1 <= word1.length, word2.length <= 500 + word1 and word2 consist of lowercase English letters. + +**Approach:** +- Using dynamic programming. +- Defined dp[i][j] = min edits to convert first i chars of word1 to first j chars of word2. +- Recurrence: + - If characters match, dp[i][j] = dp[i-1][j-1] + - Else dp[i][j] = 1 + min(insert, delete, replace) + +**Time Complexity:** O(n * m) +**Space Complexity:** O(n * m) or O(min(n, m)) with optimization. + +**Edge cases:** +- One or both strings empty +- Strings are already equal diff --git a/java/out/production/dsa-code/dsa-code.iml b/java/out/production/dsa-code/dsa-code.iml new file mode 100644 index 00000000..b107a2dd --- /dev/null +++ b/java/out/production/dsa-code/dsa-code.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/java/primenumber.java b/java/primenumber.java new file mode 100644 index 00000000..7136cd65 --- /dev/null +++ b/java/primenumber.java @@ -0,0 +1,29 @@ +import java.util.Scanner; + +public class primenum { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + System.out.print("Enter a number: "); + int n = sc.nextInt(); + sc.close(); + + if (isPrime(n)) { + System.out.println(n + " is a Prime number."); + } else { + System.out.println(n + " is NOT a Prime number."); + } + } + + static boolean isPrime(int n) { + if (n <= 1) return false; // 0 and 1 are not prime + if (n == 2 || n == 3) return true; // 2 and 3 are prime + if (n % 2 == 0) return false; // eliminate even numbers + + int limit = (int) Math.sqrt(n); // check up to √n + for (int i = 3; i <= limit; i += 2) { + if (n % i == 0) + return false; + } + return true; + } +} diff --git a/java/rapRainWaterII.java b/java/rapRainWaterII.java new file mode 100644 index 00000000..26c0e929 --- /dev/null +++ b/java/rapRainWaterII.java @@ -0,0 +1,78 @@ + +class TrapRainWaterII { + + public static void main(String[] args) { + // Sample height map (3x6 grid) + int[][] heightMap = { + {1, 4, 3, 1, 3, 2}, + {3, 2, 1, 3, 2, 4}, + {2, 3, 3, 2, 3, 1} + }; + + // Call function and print trapped water + int trappedWater = trapRainWater(heightMap); + System.out.println("Total trapped water: " + trappedWater); + } + + public static int trapRainWater(int[][] heightMap) { + // Edge case: empty grid + if (heightMap == null || heightMap.length == 0 || heightMap[0].length == 0) { + return 0; + } + + int m = heightMap.length; // number of rows + int n = heightMap[0].length; // number of columns + int[][] vols = new int[m][n]; // matrix storing final water levels + + // Step 1: Initialize vols with the original height map + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + vols[i][j] = heightMap[i][j]; + } + } + + boolean upt = true; // tracks if updates occur in a pass + boolean init = true; + + // Step 2: Iteratively propagate water levels + while (upt) { + upt = false; + + // Pass 1: Top-left → bottom-right + for (int i = 1; i < m - 1; i++) { + for (int j = 1; j < n - 1; j++) { + int val = Math.max(heightMap[i][j], + Math.min(vols[i - 1][j], vols[i][j - 1])); + if (init || vols[i][j] > val) { + vols[i][j] = val; + upt = true; + } + } + } + + init = false; + + // Pass 2: Bottom-right → top-left + for (int i = m - 2; i >= 1; i--) { + for (int j = n - 2; j >= 1; j--) { + int val = Math.max(heightMap[i][j], + Math.min(vols[i + 1][j], vols[i][j + 1])); + if (vols[i][j] > val) { + vols[i][j] = val; + upt = true; + } + } + } + } + + // Step 3: Calculate total trapped water + int res = 0; + for (int i = 1; i < m - 1; i++) { + for (int j = 1; j < n - 1; j++) { + res += Math.max(vols[i][j] - heightMap[i][j], 0); + } + } + + return res; + } +} diff --git a/java/rotateImage.java b/java/rotateImage.java new file mode 100644 index 00000000..4771506c --- /dev/null +++ b/java/rotateImage.java @@ -0,0 +1,46 @@ +class Solution { + public boolean isValidSudoku(char[][] board) { + int N = 9; + + // Use hash set to record the status + HashSet[] rows = new HashSet[N]; + HashSet[] cols = new HashSet[N]; + HashSet[] boxes = new HashSet[N]; + for (int r = 0; r < N; r++) { + rows[r] = new HashSet(); + cols[r] = new HashSet(); + boxes[r] = new HashSet(); + } + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + char val = board[r][c]; + + // Check if the position is filled with number + if (val == '.') { + continue; + } + + // Check the row + if (rows[r].contains(val)) { + return false; + } + rows[r].add(val); + + // Check the column + if (cols[c].contains(val)) { + return false; + } + cols[c].add(val); + + // Check the box + int idx = (r / 3) * 3 + c / 3; + if (boxes[idx].contains(val)) { + return false; + } + boxes[idx].add(val); + } + } + return true; + } +} diff --git a/java/setBit.java b/java/setBit.java new file mode 100644 index 00000000..f6dc674c --- /dev/null +++ b/java/setBit.java @@ -0,0 +1,26 @@ +import java.util.* ; + +public class setBit { + + public static void main(String args[]){ + + Scanner sc = new Scanner(System.in) ; + + System.out.println("Enter the number :"); + + int num = sc.nextInt(); + + System.out.println("Enter the positon of the bit to set :"); + + int pos = sc.nextInt(); + + int bitMask = 1< charCountMap = new LinkedHashMap<>(); + + // Count frequency of each character + for (char ch : str.toCharArray()) { + charCountMap.put(ch, charCountMap.getOrDefault(ch, 0) + 1); + } + + // Find the first character with count 1 + for (Map.Entry entry : charCountMap.entrySet()) { + if (entry.getValue() == 1) { + return "First non-repeated character: " + entry.getKey(); + } + } + + return "No non-repeated character found"; + } + + public static void main(String[] args) { + // Diverse test cases + String[] testStrings = { + "swiss", // w + "hello", // h + "aabbcc", // none + "programming", // p + "", // empty + "x", // x + null, // null + "aabbcddee", // c + "aabbccddeeffg" // g + }; + + for (String s : testStrings) { + System.out.println("Input: " + s); + System.out.println("Output: " + firstNonRepeated(s)); + System.out.println("-------------------------"); + } + } +} \ No newline at end of file diff --git a/java/strings/KMPAlgorithm.java b/java/strings/KMPAlgorithm.java new file mode 100644 index 00000000..f2dffe85 --- /dev/null +++ b/java/strings/KMPAlgorithm.java @@ -0,0 +1,72 @@ +public class KMPAlgorithm { + + public static int kmpSearch(String text, String pattern) { + if (pattern == null || pattern.isEmpty()) return 0; + if (text == null || text.isEmpty()) return -1; + + int n = text.length(); + int m = pattern.length(); + + + int[] lps = buildLPS(pattern); + + int i = 0; + int j = 0; + + + while (i < n) { + if (text.charAt(i) == pattern.charAt(j)) { + i++; + j++; + } + + if (j == m) { + return i - j; + } else if (i < n && text.charAt(i) != pattern.charAt(j)) { + if (j != 0) { + j = lps[j - 1]; + } else { + i++; + } + } + } + + return -1; + } + + + private static int[] buildLPS(String pattern) { + int m = pattern.length(); + int[] lps = new int[m]; + int len = 0; + int i = 1; + + while (i < m) { + if (pattern.charAt(i) == pattern.charAt(len)) { + len++; + lps[i] = len; + i++; + } else { + if (len != 0) { + len = lps[len - 1]; + } else { + lps[i] = 0; + i++; + } + } + } + + return lps; + } + + public static void main(String[] args) { + String text = "abxabcabcaby"; + String pattern = "abcaby"; + + int index = kmpSearch(text, pattern); + System.out.println("Pattern found at index: " + index); + + System.out.println("Pattern found at index: " + kmpSearch("hello", "ll")); + System.out.println("Pattern found at index: " + kmpSearch("aaaaa", "bba")); + } +} diff --git a/java/strings/LongestUniqueSubstring.java b/java/strings/LongestUniqueSubstring.java new file mode 100644 index 00000000..3cc7ae9f --- /dev/null +++ b/java/strings/LongestUniqueSubstring.java @@ -0,0 +1,200 @@ +/* + Problem: Longest Substring Without Repeating Characters + + Given a string s, find: + 1) The length of the longest substring without repeating characters. + 2) Optionally, return one such longest substring. + + Example + Input: "abcabcbb" + Output: 3 + Explanation: The answer is "abc", with the length of 3. + + Approaches + + 1) Sliding Window + HashMap of Last-Seen Index (Recommended) + - Maintain a window [left..right] with no duplicate characters. + - Use a Map to track the last index where each character appeared. + - When you see a repeated character c at index right: + left = max(left, lastSeen[c] + 1) + This "jumps" the left boundary past the previous occurrence, preserving O(n) time. + - Time: O(n) because each index is visited at most twice (once by right, once by left jump). + - Space: O(k), where k is the character set size appearing in s (≤ n). + - Pros: Simple, robust for general Unicode in the BMP (char-based). + - Cons: For supplementary Unicode code points (outside BMP), char-based methods treat surrogate pairs separately. + + 2) Sliding Window + Fixed Array (ASCII Optimization) + - Use an int[256] array initialized to -1 for last-seen indices (extended ASCII). + - Same logic as above, but constant-time array access is faster and memory-light. + - If a non-ASCII character (> 255) is detected, fall back to the HashMap method. + - Time: O(n) + - Space: O(1) bounded by 256 + - Pros: Very fast and cache-friendly for ASCII inputs. + - Cons: Not safe for non-ASCII; we detect and fall back. + + 3) Brute Force (For completeness; not implemented) + - Check all substrings and test uniqueness with a Set. + - Time: O(n^3) naive, or O(n^2) with some optimizations—still impractical for interviews when O(n) exists. + + Edge Cases + - s is null or empty -> length = 0; substring = "". + - All characters same -> length = 1. + - String with spaces/punctuation -> treated as valid characters. + - Unicode note: This implementation is char-based (UTF-16 code units). For full code point correctness, + you can rework it to iterate over code points and use an Int2IntMap keyed by code point. + + Complexity + - Time: O(n) for sliding window methods. + - Space: O(k), k = distinct characters in the window (HashMap) or O(1) for ASCII array. + + How to Run + # From repo root (adjust path if needed) + javac Java/Strings/LongestUniqueSubstring.java + java -cp Java/Strings LongestUniqueSubstring # runs built-in demos + java -cp Java/Strings LongestUniqueSubstring "pwwkew" # runs on your input + + References + - LeetCode: Longest Substring Without Repeating Characters + https://leetcode.com/problems/longest-substring-without-repeating-characters/ + - GeeksforGeeks: Length of the longest substring without repeating characters + https://www.geeksforgeeks.org/length-of-the-longest-substring-without-repeating-characters/ + + Attribution + - Language: Java + - Tags: Strings, Sliding Window, Hashing, Two Pointers, Interview Prep + - Hacktoberfest: Suitable as a meaningful contribution (place the note about Hacktoberfest in the PR description; not required in code) +*/ + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +public class LongestUniqueSubstring { + + /** + * Returns the length of the longest substring without repeating characters, + * using an optimized sliding window with last-seen indices in a HashMap. + * + * Time Complexity: O(n) + * Space Complexity: O(k), k = number of distinct characters in s + */ + public static int lengthOfLongestSubstring(String s) { + if (s == null || s.isEmpty()) return 0; + + Map last = new HashMap<>(); // char -> last index + int best = 0, left = 0; // window is [left..right] + for (int right = 0; right < s.length(); right++) { + char c = s.charAt(right); + Integer prev = last.get(c); + if (prev != null && prev >= left) { + left = prev + 1; // jump left past the previous occurrence + } + last.put(c, right); + best = Math.max(best, right - left + 1); + } + return best; + } + + /** + * ASCII-optimized variant: uses an int[256] for last-seen indices. + * If a non-ASCII character is detected, falls back to the HashMap method. + * + * Time Complexity: O(n) + * Space Complexity: O(1) bounded by 256 + */ + public static int lengthOfLongestSubstringAscii(String s) { + if (s == null || s.isEmpty()) return 0; + + int[] last = new int[256]; + Arrays.fill(last, -1); + + int best = 0, left = 0; + for (int right = 0; right < s.length(); right++) { + char raw = s.charAt(right); + if (raw > 255) { + // Non-ASCII detected; fall back for correctness + return lengthOfLongestSubstring(s); + } + int prev = last[raw]; + if (prev >= left) { + left = prev + 1; + } + last[raw] = right; + best = Math.max(best, right - left + 1); + } + return best; + } + + /** + * Returns one longest substring without repeating characters (not just its length), + * using the HashMap sliding window approach. + * + * Time Complexity: O(n) + * Space Complexity: O(k) + */ + public static String longestUniqueSubstring(String s) { + if (s == null || s.isEmpty()) return ""; + + Map last = new HashMap<>(); + int bestLen = 0, bestStart = 0; + int left = 0; + + for (int right = 0; right < s.length(); right++) { + char c = s.charAt(right); + Integer prev = last.get(c); + if (prev != null && prev >= left) { + left = prev + 1; + } + last.put(c, right); + + int windowLen = right - left + 1; + if (windowLen > bestLen) { + bestLen = windowLen; + bestStart = left; + } + } + return s.substring(bestStart, bestStart + bestLen); + } + + // Simple CLI and demo + public static void main(String[] args) { + if (args != null && args.length > 0) { + String input = String.join(" ", args); + System.out.println("Input: " + quote(input)); + System.out.println("Length (HashMap): " + lengthOfLongestSubstring(input)); + System.out.println("Length (ASCII optimized): " + lengthOfLongestSubstringAscii(input)); + System.out.println("Substring (HashMap): " + quote(longestUniqueSubstring(input))); + return; + } + + // Demo cases (covering common edge cases) + String[] samples = { + "abcabcbb", // 3 ("abc") + "bbbbb", // 1 ("b") + "pwwkew", // 3 ("wke" or "kew") + "", // 0 ("") + "dvdf", // 3 ("vdf") + "au", // 2 ("au") + "aab", // 2 ("ab") + "abba", // 2 ("ab" or "ba") + "tmmzuxt", // 5 ("mzuxt") + "anviaj", // 5 ("nviaj") + }; + + System.out.println("Demo (HashMap approach):"); + for (String s : samples) { + System.out.printf("Input: %-12s -> len=%d, sub=%s%n", + quote(s), lengthOfLongestSubstring(s), quote(longestUniqueSubstring(s))); + } + + System.out.println("\nDemo (ASCII-optimized approach):"); + for (String s : samples) { + System.out.printf("Input: %-12s -> len=%d%n", + quote(s), lengthOfLongestSubstringAscii(s)); + } + } + + private static String quote(String s) { + return s == null ? "null" : "\"" + s + "\""; + } +} diff --git a/java/strings/Longestpalindrome.java b/java/strings/Longestpalindrome.java new file mode 100644 index 00000000..30e21e28 --- /dev/null +++ b/java/strings/Longestpalindrome.java @@ -0,0 +1,41 @@ +public class Longestpalindrome{ + public static String longestPalindrome(String s) { + if (s == null || s.length() < 1) return ""; + + int start = 0, end = 0; + for (int i = 0; i < s.length(); i++) { + int len1 = expandFromCenter(s, i, i); + int len2 = expandFromCenter(s, i, i + 1); + int len = Math.max(len1, len2); + + if (len > end - start) { + start = i - (len - 1) / 2; + end = i + len / 2; + } + } + + return s.substring(start, end + 1); + } + + private static int expandFromCenter(String s, int left, int right) { + while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) { + left--; + right++; + } + return right - left - 1; + } + + public static void main(String[] args) { + String str = "babad"; + System.out.println("Longest Palindromic Substring: " + longestPalindrome(str)); + + str = "cbbd"; + System.out.println("Longest Palindromic Substring: " + longestPalindrome(str)); + + str = "a"; + System.out.println("Longest Palindromic Substring: " + longestPalindrome(str)); + + str = "forgeeksskeegfor"; + System.out.println("Longest Palindromic Substring: " + longestPalindrome(str)); + } +} diff --git a/java/strings/RabinKarp.java b/java/strings/RabinKarp.java new file mode 100644 index 00000000..2fe2c941 --- /dev/null +++ b/java/strings/RabinKarp.java @@ -0,0 +1,58 @@ +public class RabinKarp { + public static int rabinKarp(String text, String pattern) { + if (text == null || pattern == null) return -1; + int n = text.length(), m = pattern.length(); + if (m > n) return -1; + + int base = 256; + int mod = 101; + + int patternHash = 0; + int textHash = 0; + int h = 1; + + + for (int i = 0; i < m - 1; i++) + h = (h * base) % mod; + + + for (int i = 0; i < m; i++) { + patternHash = (base * patternHash + pattern.charAt(i)) % mod; + textHash = (base * textHash + text.charAt(i)) % mod; + } + + + for (int i = 0; i <= n - m; i++) { + + if (patternHash == textHash) { + + int j; + for (j = 0; j < m; j++) { + if (text.charAt(i + j) != pattern.charAt(j)) + break; + } + if (j == m) return i; + } + + + if (i < n - m) { + textHash = (base * (textHash - text.charAt(i) * h) + text.charAt(i + m)) % mod; + + + if (textHash < 0) + textHash += mod; + } + } + return -1; + } + + public static void main(String[] args) { + String text = "ABCCDDAEFG"; + String pattern = "CDD"; + int index = rabinKarp(text, pattern); + System.out.println("Pattern found at index: " + index); + + System.out.println("Pattern found at index: " + rabinKarp("hello", "ll")); + System.out.println("Pattern found at index: " + rabinKarp("aaaaa", "bba")); + } +} diff --git a/java/strings/Reverse_words.java b/java/strings/Reverse_words.java new file mode 100644 index 00000000..3187ca53 --- /dev/null +++ b/java/strings/Reverse_words.java @@ -0,0 +1,28 @@ +package strings; + +public class Reverse_words { + public static void wordReverse(String str) { + + + String word[] = str.split(" "); + + for (int i = word.length - 1; i >= 0; i--) { + +// int a= word[i].length(); +// System.out.println(a); + System.out.print(word[i] + " "); + } + + } + + + public static void main(String[] args) { + + + String str = "i am somnath dhere"; + + wordReverse(str); + } +} + + diff --git a/java/strings/STRSTR.java b/java/strings/STRSTR.java new file mode 100644 index 00000000..3c2793c8 --- /dev/null +++ b/java/strings/STRSTR.java @@ -0,0 +1,19 @@ +public class STRSTR { + public static int strStr(String haystack, String needle) { + if (needle.isEmpty()) return 0; + int hLen = haystack.length(), nLen = needle.length(); + + for (int i = 0; i <= hLen - nLen; i++) { + if (haystack.substring(i, i + nLen).equals(needle)) { + return i; + } + } + return -1; + } + + public static void main(String[] args) { + System.out.println(strStr("sadbutsad", "sad")); + System.out.println(strStr("leetcode", "leeto")); + System.out.println(strStr("hello", "ll")); + } +} diff --git a/java/strings/StringReverse.java b/java/strings/StringReverse.java new file mode 100644 index 00000000..ea27d10a --- /dev/null +++ b/java/strings/StringReverse.java @@ -0,0 +1,56 @@ +package strings; + +public class StringReverse { + + + //built in method + public static void name(String str) { + + + StringBuilder builder=new StringBuilder(str); + + + String string = builder.reverse().toString(); + System.out.println(string); + } + + + //Using logic + public static void reverse(String str1) { + + String s=""; + + for (int i =str1.length()-1;i>=0; i--) { + + s=s+str1.charAt(i); + } + + System.out.println(s); + + } + + + //Recursion + public static String rucursion(String s ,String r,int i) { + + + + if(i<0) { + return r; + } + + return rucursion(s, r+s.charAt(i),i-1); + + } + public static void main(String[] args) { + + reverse("Somnath"); + String str="somnathdhere"; + String r=""; + int i=str.length()-1; + + System.out.println(rucursion(str, r, i)); + + } + +} diff --git a/java/strings/StringToInteger.java b/java/strings/StringToInteger.java new file mode 100644 index 00000000..321bb9af --- /dev/null +++ b/java/strings/StringToInteger.java @@ -0,0 +1,38 @@ +public class StringToInteger { + public static int myAtoi(String s) { + if (s == null || s.isEmpty()) return 0; + + int i = 0, n = s.length(); + int sign = 1; + long result = 0; + + + while (i < n && s.charAt(i) == ' ') i++; + + if (i < n && (s.charAt(i) == '+' || s.charAt(i) == '-')) { + sign = (s.charAt(i) == '-') ? -1 : 1; + i++; + } + + + while (i < n && Character.isDigit(s.charAt(i))) { + result = result * 10 + (s.charAt(i) - '0'); + + + if (result * sign > Integer.MAX_VALUE) return Integer.MAX_VALUE; + if (result * sign < Integer.MIN_VALUE) return Integer.MIN_VALUE; + + i++; + } + + return (int)(result * sign); + } + + public static void main(String[] args) { + System.out.println(myAtoi("42")); + System.out.println(myAtoi(" -42")); + System.out.println(myAtoi("4193 with words")); + System.out.println(myAtoi("words 987")); + System.out.println(myAtoi("-91283472332")); + } +} diff --git a/java/th3Sum.java b/java/th3Sum.java new file mode 100644 index 00000000..a817e1e9 --- /dev/null +++ b/java/th3Sum.java @@ -0,0 +1,37 @@ +import java.util.*; + +public class th3Sum { + public List> threeSum(int[] nums) { + Arrays.sort(nums); + List> result = new ArrayList<>(); + + for (int i = 0; i < nums.length - 2; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; // Skip duplicates + + int left = i + 1, right = nums.length - 1; + while (left < right) { + int sum = nums[i] + nums[left] + nums[right]; + + if (sum == 0) { + result.add(Arrays.asList(nums[i], nums[left], nums[right])); + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } else if (sum < 0) { + left++; + } else { + right--; + } + } + } + + return result; + } + + public static void main(String[] args) { + ThreeSum obj = new ThreeSum(); + System.out.println(obj.threeSum(new int[]{-1,0,1,2,-1,-4})); + // [[-1,-1,2], [-1,0,1]] + } +} diff --git a/java/topKelements.java b/java/topKelements.java new file mode 100644 index 00000000..b56d7cba --- /dev/null +++ b/java/topKelements.java @@ -0,0 +1,39 @@ +import java.util.*; + +class Solution { + public int[] topKFrequent(int[] nums, int k) { + Map map = new HashMap(); + for(int num: nums){ + map.put(num, map.getOrDefault(num, 0)+1); + } + + List> entryList = new ArrayList<>(map.entrySet()); + + entryList.sort((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue())); + + int res[] = new int[k]; + for(int i=0; i queue = new PriorityQueue<>((a, b) -> a.h - b.h); + boolean[][] visited = new boolean[rows][cols]; + + // directions: left, right, up, down + int[][] directions = { + {0, -1}, {0, 1}, {-1, 0}, {1, 0} + }; + + // Step 1: Add all boundary cells to heap + for (int i = 0; i < rows; i++){ + for(int j = 0; j < cols; j++){ + if (isOnBoundary(i, j, rows, cols)) { + queue.offer(new Entry(heightMap[i][j], i, j)); + visited[i][j] = true; + } + } + } + + int maxValue = 0; // tracks highest boundary seen so far + int trapWater = 0; // result + + // Step 2: Process heap + while (!queue.isEmpty()) { + Entry entry = queue.poll(); + maxValue = Math.max(maxValue, entry.h); + + for (int[] dir : directions) { + int newX = entry.i + dir[0]; + int newY = entry.j + dir[1]; + + if (isValid(newX, newY, rows, cols) && !visited[newX][newY]) { + visited[newX][newY] = true; + int currentHeight = heightMap[newX][newY]; + + // if current cell lower than water level, water can be trapped + if (currentHeight < maxValue) { + trapWater += (maxValue - currentHeight); + } + + // push neighbor with its original height + queue.offer(new Entry(currentHeight, newX, newY)); + } + } + } + return trapWater; + } + + // check if coordinates are inside grid + private boolean isValid(int x, int y, int rows, int cols){ + return x >= 0 && y >= 0 && x < rows && y < cols; + } + + // check if cell is on boundary + private boolean isOnBoundary(int i, int j, int rows, int cols){ + return i == 0 || j == 0 || i == rows - 1 || j == cols - 1; + } + + // Main function for testing + public static void main(String[] args) { + trappingRainwater2 sol = new trappingRainwater2(); + int[][] heightMap = { + {1,4,3,1,3,2}, + {3,2,1,3,2,4}, + {2,3,3,2,3,1} + }; + + System.out.println(sol.trapRainWater(heightMap)); + // Expected output: 4 + } +} diff --git a/java/unionByRank.java b/java/unionByRank.java new file mode 100644 index 00000000..8cd01842 --- /dev/null +++ b/java/unionByRank.java @@ -0,0 +1,63 @@ +import java.util.Arrays; + +public class UnionByRank { + private int parent[]; + private int rank[]; + + UnionByRank(int n){ + parent = new int[n]; + rank = new int[n]; + + for(int i=0; i rank[rootY]){ + parent[rootY] = rootX; + }else if(rank[rootX] < rank[rootY]){ + parent[rootX] = rootY; + }else{ + parent[rootY] = rootX; + rank[rootX]++; + } + } + } + + public boolean isConnected(int x, int y){ + return find(x) == find(y); + } + + public void status(){ + System.out.println("parent"+Arrays.toString(parent)); + System.out.println(" rank"+Arrays.toString(rank)); + } + + public static void main(String []args){ + UnionByRank uf = new UnionByRank(8); + + uf.union(1,2); + uf.union(2,3); + uf.union(4,5); + uf.union(6,7); + uf.union(5,6); + + System.out.println(uf.isConnected(7,4)); + System.out.println(uf.isConnected(3, 6)); + + uf.status(); + } +} \ No newline at end of file diff --git a/java/unionBySize.java b/java/unionBySize.java new file mode 100644 index 00000000..b98e75af --- /dev/null +++ b/java/unionBySize.java @@ -0,0 +1,62 @@ +import java.util.Arrays; + +public class UnionBySize { + private int parent[]; + private int size[]; + + UnionBySize(int n){ + parent = new int[n]; + size = new int[n]; + + for(int i=0; i size[rootY]){ + parent[rootY] = rootX; + size[rootX] += size[rootY]; + }else{ + parent[rootX] = rootY; + size[rootY] = size[rootX]; + } + } + } + + public boolean isConnected(int x, int y){ + return find(x) == find(y); + } + + public void status(){ + System.out.println("parent"+Arrays.toString(parent)); + System.out.println(" size"+Arrays.toString(size)); + } + + public static void main(String []args){ + UnionBySize uf = new UnionBySize(8); + + uf.union(1,2); + uf.union(2,3); + uf.union(4,5); + uf.union(6,7); + uf.union(5,6); + + System.out.println(uf.isConnected(7,4)); + System.out.println(uf.isConnected(3, 6)); + + uf.status(); + } +} diff --git a/java/uniqueNumOccurrences.java b/java/uniqueNumOccurrences.java new file mode 100644 index 00000000..73b437a1 --- /dev/null +++ b/java/uniqueNumOccurrences.java @@ -0,0 +1,29 @@ +public class Solution { + public static boolean uniqueOccurrences(int[] arr) { + int freq[] = new int[2001]; + + for(int num: arr){ + freq[num + 1000]++; + } + + BitSet seen = new BitSet(); + + for(int f: freq){ + if(f == 0) continue; + if(seen.get(f)) return false; + seen.set(f); + } + + return true; + } + + public static void main(String[] args) { + int[] test1 = {1, 2, 2, 1, 1, 3}; + int[] test2 = {1, 2}; + int[] test3 = {-3, 0, 1, -3, 1, 1, 1, -3, 10, 0}; + + System.out.println(uniqueOccurrences(test1)); // true + System.out.println(uniqueOccurrences(test2)); // false + System.out.println(uniqueOccurrences(test3)); // true + } +} diff --git a/java/updateBit.java b/java/updateBit.java new file mode 100644 index 00000000..0e050e9b --- /dev/null +++ b/java/updateBit.java @@ -0,0 +1,33 @@ +import java.util.* ; +public class updateBit { + public static void main (String args[]){ + + Scanner sc = new Scanner(System.in); + + System.out.print("Enter the number :"); + + int num = sc.nextInt(); + + System.out.println("Enter the bit position to update : "); + + int pos = sc.nextInt(); + + System.out.print("Enter the new bit value (0 or 1): "); + + int newBit = sc.nextInt(); + + int bitMask = 1 << pos; + + if(newBit == 0){ + + int newbitMask = ~bitMask ; + int result = num & newbitMask; + System.out.println("Number after clearing bit at position " + pos + " is: " + result); + + } else{ + int result = num | bitMask; + System.out.println("Number after setting bit at position " + pos + " is: " + result); + } + sc.close(); + } +} diff --git a/java/valid_sudoku.java b/java/valid_sudoku.java new file mode 100644 index 00000000..a2aef778 --- /dev/null +++ b/java/valid_sudoku.java @@ -0,0 +1,45 @@ +public class valid_sudoku { + + public static void main(String[] args) { + // Sample Sudoku board + char[][] board = { + {'5','3','.','.','7','.','.','.','.'}, + {'6','.','.','1','9','5','.','.','.'}, + {'.','9','8','.','.','.','.','6','.'}, + {'8','.','.','.','6','.','.','.','3'}, + {'4','.','.','8','.','3','.','.','1'}, + {'7','.','.','.','2','.','.','.','6'}, + {'.','6','.','.','.','.','2','8','.'}, + {'.','.','.','4','1','9','.','.','5'}, + {'.','.','.','.','8','.','.','7','9'} + }; + + Solution solution = new Solution(); + boolean isValid = solution.isValidSudoku(board); + System.out.println("Is the Sudoku board valid? " + isValid); + } +} + +class Solution { + public boolean isValidSudoku(char[][] board) { + boolean[][] rows = new boolean[9][9]; + boolean[][] cols = new boolean[9][9]; + boolean[][] boxes = new boolean[9][9]; + + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 9; j++) { + if (board[i][j] != '.') { + int num = board[i][j] - '1'; + int boxIndex = (i / 3) * 3 + (j / 3); + + if (rows[i][num] || cols[j][num] || boxes[boxIndex][num]) { + return false; + } + + rows[i][num] = cols[j][num] = boxes[boxIndex][num] = true; + } + } + } + return true; + } +} diff --git a/java/wildcard.java b/java/wildcard.java new file mode 100644 index 00000000..931d5d46 --- /dev/null +++ b/java/wildcard.java @@ -0,0 +1,60 @@ +// Given an input string (s) and a pattern (p), implement wildcard pattern matching with support +// for '?' and '*' where: '?' Matches any single character. '*' Matches any sequence of characters +// (including the empty sequence). The matching should cover the entire input string (not partial). + +public class wildcard { + public boolean isMatch(String s, String p) { + int n = s.length(); + int m = p.length(); + + int i = 0; // pointer for s + int j = 0; // pointer for p + int starIdx = -1; // most recent position of '*' in p, -1 if none + int iAfterStar = -1; // position in s corresponding to how many chars '*' has consumed + + while (i < n) { + // Case 1: characters match or pattern has '?' + if (j < m && (p.charAt(j) == '?' || p.charAt(j) == s.charAt(i))) { + i++; + j++; + } + // Case 2: pattern has '*' — record its position and try to match zero + // characters first + else if (j < m && p.charAt(j) == '*') { + starIdx = j; + iAfterStar = i; + j++; // move past '*', try matching zero characters initially + } + // Case 3: mismatch but we previously saw a '*' — backtrack: let '*' consume one + // more character + else if (starIdx != -1) { + // expand the area matched by last '*' by one more char + iAfterStar++; + i = iAfterStar; + j = starIdx + 1; // resume matching just after the '*' + } + // Case 4: mismatch and no previous '*' to adjust -> no match + else { + return false; + } + } + + // consume remaining '*' in pattern (they can match empty sequences) + while (j < m && p.charAt(j) == '*') + j++; + + // if pattern fully consumed, it's a match + return j == m; + } + + // Optional: quick manual test harness + public static void main(String[] args) { + wildcard sol = new wildcard(); + System.out.println(sol.isMatch("aa", "a")); // false + System.out.println(sol.isMatch("aa", "*")); // true + System.out.println(sol.isMatch("cb", "?a")); // false + System.out.println(sol.isMatch("", "*")); // true + System.out.println(sol.isMatch("", "")); // true + System.out.println(sol.isMatch("abcd", "a*d")); // true + } +} diff --git a/javascript/75-Dsa-Problems/remove-zeros-in-decimal-representation.js b/javascript/75-Dsa-Problems/remove-zeros-in-decimal-representation.js new file mode 100644 index 00000000..5fb1ddd8 --- /dev/null +++ b/javascript/75-Dsa-Problems/remove-zeros-in-decimal-representation.js @@ -0,0 +1,7 @@ +/** + * @param {number} n + * @return {number} + */ +var removeZeros = function(n) { + return Number(String(n).replace(/0/g, '')); +}; \ No newline at end of file diff --git a/javascript/A_star.js b/javascript/A_star.js new file mode 100644 index 00000000..51ebbc3c --- /dev/null +++ b/javascript/A_star.js @@ -0,0 +1,111 @@ +class Point { + constructor(x, y) { + this.x = x; + this.y = y; + } + + toString() { + return `${this.x},${this.y}`; + } +} + +// Manhattan distance heuristic +function heuristic(a, b) { + return Math.abs(a.x - b.x) + Math.abs(a.y - b.y); +} + +// Get valid neighbors in 4 directions +function getNeighbors(point, width, height) { + const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const result = []; + + for (const [dx, dy] of dirs) { + const nx = point.x + dx; + const ny = point.y + dy; + if (nx >= 0 && nx < width && ny >= 0 && ny < height) { + result.push(new Point(nx, ny)); + } + } + + return result; +} + +// A* Algorithm +function aStar(start, goal, width, height, obstacles = []) { + const obstacleSet = new Set(obstacles.map(o => o.toString())); + + const openSet = new Set([start.toString()]); + const cameFrom = new Map(); + + const gScore = new Map(); + const fScore = new Map(); + + gScore.set(start.toString(), 0); + fScore.set(start.toString(), heuristic(start, goal)); + + while (openSet.size > 0) { + // Get node with lowest fScore + let currentKey = [...openSet].reduce((a, b) => { + return (fScore.get(a) || Infinity) < (fScore.get(b) || Infinity) ? a : b; + }); + + const [cx, cy] = currentKey.split(',').map(Number); + const current = new Point(cx, cy); + + if (current.toString() === goal.toString()) { + // Reconstruct path + const path = [current]; + let temp = current.toString(); + while (cameFrom.has(temp)) { + temp = cameFrom.get(temp); + const [px, py] = temp.split(',').map(Number); + path.push(new Point(px, py)); + } + return path.reverse(); + } + + openSet.delete(currentKey); + + for (const neighbor of getNeighbors(current, width, height)) { + if (obstacleSet.has(neighbor.toString())) continue; + + const tentativeG = (gScore.get(currentKey) || Infinity) + 1; + + if (tentativeG < (gScore.get(neighbor.toString()) || Infinity)) { + cameFrom.set(neighbor.toString(), currentKey); + gScore.set(neighbor.toString(), tentativeG); + fScore.set(neighbor.toString(), tentativeG + heuristic(neighbor, goal)); + openSet.add(neighbor.toString()); + } + } + } + + return null; // No path found +} + +// Example usage +const width = 10; +const height = 10; +const start = new Point(0, 0); +const goal = new Point(7, 5); + +const obstacles = [ + new Point(3, 1), + new Point(3, 2), + new Point(3, 3), + new Point(3, 4), +]; + +const path = aStar(start, goal, width, height, obstacles); + +if (path) { + console.log("✅ Path found:"); + console.log(path.map(p => `(${p.x},${p.y})`).join(" → ")); +} else { + console.log("❌ No path found."); +} diff --git a/javascript/BestTimetoBuyandSellStock.js b/javascript/BestTimetoBuyandSellStock.js deleted file mode 100644 index d78233f6..00000000 --- a/javascript/BestTimetoBuyandSellStock.js +++ /dev/null @@ -1,10 +0,0 @@ -// Time: O(n), Space: O(1) -var maxProfit = function(prices) { - let minPrice = Infinity; - let maxProfit = 0; - for (let price of prices) { - minPrice = Math.min(minPrice, price); - maxProfit = Math.max(maxProfit, price - minPrice); - } - return maxProfit; -}; diff --git a/javascript/BinarySearch.js b/javascript/BinarySearch.js index 0f2938f7..1ead9354 100644 --- a/javascript/BinarySearch.js +++ b/javascript/BinarySearch.js @@ -1,11 +1,26 @@ -// Time: O(log n), Space: O(1) -var search = function(nums, target) { - let left = 0, right = nums.length - 1; - while (left <= right) { - let mid = Math.floor((left + right) / 2); - if (nums[mid] === target) return mid; - else if (nums[mid] < target) left = mid + 1; - else right = mid - 1; +// Binary Search : Given a sorted array and a target value, return the index if the target is found. If not, return -1. +// Input: nums = [-1,0,3,5,9,12], target = 9 +// Output: 4 +// Explanation: 9 exists in nums and its index is 4 + +function binarySearch(nums, target) { + let left = 0; + let right = nums.length - 1; + while (left <= right) { + // Find the middle element + let mid = Math.floor((left + right) / 2); + // If the middle element is the target, return its index + if (nums[mid] === target) { + return mid; + // If the middle element is less than the target, search the right half + } else if (nums[mid] < target) { + left = mid + 1; + // If the middle element is greater than the target, search the left half + } else { + right = mid - 1; } - return -1; -}; + } + return -1; +} + +console.log(binarySearch([-3, -1, 2, 4, 5, 9, 12], 9)); // Output: 5 diff --git a/javascript/BinarySearchTree.js b/javascript/BinarySearchTree.js new file mode 100644 index 00000000..0ec22788 --- /dev/null +++ b/javascript/BinarySearchTree.js @@ -0,0 +1,349 @@ +/** + * Binary Search Tree Implementation + * A Binary Search Tree (BST) is a node-based binary tree data structure with the following properties: + * - The left subtree of a node contains only nodes with keys less than the node's key + * - The right subtree of a node contains only nodes with keys greater than the node's key + * - Both left and right subtrees must also be binary search trees + * + * Time Complexity: + * - Insert: O(log n) average, O(n) worst case + * - Search: O(log n) average, O(n) worst case + * - Delete: O(log n) average, O(n) worst case + * - Traversals: O(n) + * + * Space Complexity: O(n) + */ + +class Node { + constructor(value) { + this.value = value; + this.left = null; + this.right = null; + } +} + +class BinarySearchTree { + constructor() { + this.root = null; + } + + /** + * Insert a value into the BST + * @param {number} value - The value to insert + * @returns {BinarySearchTree} - Returns this for method chaining + */ + insert(value) { + const newNode = new Node(value); + + if (this.root === null) { + this.root = newNode; + return this; + } + + let current = this.root; + while (true) { + if (value === current.value) return this; // Avoid duplicates + + if (value < current.value) { + if (current.left === null) { + current.left = newNode; + return this; + } + current = current.left; + } else { + if (current.right === null) { + current.right = newNode; + return this; + } + current = current.right; + } + } + } + + /** + * Search for a value in the BST + * @param {number} value - The value to search for + * @returns {boolean} - True if found, false otherwise + */ + search(value) { + if (this.root === null) return false; + + let current = this.root; + while (current !== null) { + if (value === current.value) return true; + if (value < current.value) { + current = current.left; + } else { + current = current.right; + } + } + return false; + } + + /** + * Find a node with a specific value + * @param {number} value - The value to find + * @returns {Node|null} - The node if found, null otherwise + */ + find(value) { + if (this.root === null) return null; + + let current = this.root; + while (current !== null) { + if (value === current.value) return current; + if (value < current.value) { + current = current.left; + } else { + current = current.right; + } + } + return null; + } + + /** + * Delete a value from the BST + * @param {number} value - The value to delete + * @returns {BinarySearchTree} - Returns this for method chaining + */ + delete(value) { + this.root = this._deleteNode(this.root, value); + return this; + } + + /** + * Helper method to delete a node recursively + * @private + */ + _deleteNode(node, value) { + if (node === null) return null; + + if (value < node.value) { + node.left = this._deleteNode(node.left, value); + return node; + } else if (value > node.value) { + node.right = this._deleteNode(node.right, value); + return node; + } else { + // Node to delete found + + // Case 1: Node has no children (leaf node) + if (node.left === null && node.right === null) { + return null; + } + + // Case 2: Node has one child + if (node.left === null) return node.right; + if (node.right === null) return node.left; + + // Case 3: Node has two children + // Find the minimum value in the right subtree (inorder successor) + let minRight = this._findMin(node.right); + node.value = minRight.value; + node.right = this._deleteNode(node.right, minRight.value); + return node; + } + } + + /** + * Find the node with minimum value in a subtree + * @private + */ + _findMin(node) { + while (node.left !== null) { + node = node.left; + } + return node; + } + + /** + * Find the minimum value in the BST + * @returns {number|null} - The minimum value or null if tree is empty + */ + findMin() { + if (this.root === null) return null; + let current = this.root; + while (current.left !== null) { + current = current.left; + } + return current.value; + } + + /** + * Find the maximum value in the BST + * @returns {number|null} - The maximum value or null if tree is empty + */ + findMax() { + if (this.root === null) return null; + let current = this.root; + while (current.right !== null) { + current = current.right; + } + return current.value; + } + + /** + * In-order traversal (Left -> Root -> Right) + * Results in sorted order for BST + * @returns {number[]} - Array of values in sorted order + */ + inOrderTraversal() { + const result = []; + this._inOrder(this.root, result); + return result; + } + + _inOrder(node, result) { + if (node !== null) { + this._inOrder(node.left, result); + result.push(node.value); + this._inOrder(node.right, result); + } + } + + /** + * Pre-order traversal (Root -> Left -> Right) + * @returns {number[]} - Array of values in pre-order + */ + preOrderTraversal() { + const result = []; + this._preOrder(this.root, result); + return result; + } + + _preOrder(node, result) { + if (node !== null) { + result.push(node.value); + this._preOrder(node.left, result); + this._preOrder(node.right, result); + } + } + + /** + * Post-order traversal (Left -> Right -> Root) + * @returns {number[]} - Array of values in post-order + */ + postOrderTraversal() { + const result = []; + this._postOrder(this.root, result); + return result; + } + + _postOrder(node, result) { + if (node !== null) { + this._postOrder(node.left, result); + this._postOrder(node.right, result); + result.push(node.value); + } + } + + /** + * Level-order traversal (Breadth-First Search) + * @returns {number[]} - Array of values in level order + */ + levelOrderTraversal() { + if (this.root === null) return []; + + const result = []; + const queue = [this.root]; + + while (queue.length > 0) { + const node = queue.shift(); + result.push(node.value); + + if (node.left !== null) queue.push(node.left); + if (node.right !== null) queue.push(node.right); + } + + return result; + } + + /** + * Get the height of the tree + * @returns {number} - The height of the tree (-1 for empty tree) + */ + height() { + return this._calculateHeight(this.root); + } + + _calculateHeight(node) { + if (node === null) return -1; + return 1 + Math.max(this._calculateHeight(node.left), this._calculateHeight(node.right)); + } + + /** + * Check if the tree is balanced + * A tree is balanced if the heights of the two subtrees of any node differ by at most 1 + * @returns {boolean} - True if balanced, false otherwise + */ + isBalanced() { + return this._checkBalance(this.root) !== -1; + } + + _checkBalance(node) { + if (node === null) return 0; + + const leftHeight = this._checkBalance(node.left); + if (leftHeight === -1) return -1; + + const rightHeight = this._checkBalance(node.right); + if (rightHeight === -1) return -1; + + if (Math.abs(leftHeight - rightHeight) > 1) return -1; + + return Math.max(leftHeight, rightHeight) + 1; + } + + /** + * Count the total number of nodes in the tree + * @returns {number} - The number of nodes + */ + size() { + return this._countNodes(this.root); + } + + _countNodes(node) { + if (node === null) return 0; + return 1 + this._countNodes(node.left) + this._countNodes(node.right); + } +} + +// Example usage and test cases +const bst = new BinarySearchTree(); + +// Insert values +bst.insert(50); +bst.insert(30); +bst.insert(70); +bst.insert(20); +bst.insert(40); +bst.insert(60); +bst.insert(80); + +console.log("In-order traversal (sorted):", bst.inOrderTraversal()); +// Output: [20, 30, 40, 50, 60, 70, 80] + +console.log("Pre-order traversal:", bst.preOrderTraversal()); +// Output: [50, 30, 20, 40, 70, 60, 80] + +console.log("Post-order traversal:", bst.postOrderTraversal()); +// Output: [20, 40, 30, 60, 80, 70, 50] + +console.log("Level-order traversal:", bst.levelOrderTraversal()); +// Output: [50, 30, 70, 20, 40, 60, 80] + +console.log("Search for 40:", bst.search(40)); // true +console.log("Search for 100:", bst.search(100)); // false + +console.log("Minimum value:", bst.findMin()); // 20 +console.log("Maximum value:", bst.findMax()); // 80 + +console.log("Tree height:", bst.height()); // 2 +console.log("Tree size:", bst.size()); // 7 +console.log("Is balanced:", bst.isBalanced()); // true + +// Delete a node +bst.delete(30); +console.log("After deleting 30:", bst.inOrderTraversal()); +// Output: [20, 40, 50, 60, 70, 80] + +module.exports = { BinarySearchTree, Node }; \ No newline at end of file diff --git a/javascript/BloomFilter.js b/javascript/BloomFilter.js new file mode 100644 index 00000000..8d5422c9 --- /dev/null +++ b/javascript/BloomFilter.js @@ -0,0 +1,209 @@ +/** + * Bloom Filter - Probabilistic Data Structure + * + * A space-efficient probabilistic structure that tests whether an element + * is a member of a set. False positives are possible, but false negatives are not. + * + * Time Complexity: O(k) where k is number of hash functions + * Space Complexity: O(m) where m is bit array size + * + * Real World Use Cases: + * - Google BigTable (database) + * - Bitcoin wallet synchronization + * - Medium.com (recommendation system) + * - Spell checkers + * - Network routers + * - Content recommendation systems + */ + +class BloomFilter { + /** + * @param {number} size - Size of the bit array + * @param {number} numHashes - Number of hash functions to use + */ + constructor(size = 100, numHashes = 3) { + this.size = size; + this.numHashes = numHashes; + this.bitArray = new Array(size).fill(false); + } + + /** + * Simple hash functions using different seeds + * @param {string} item - Item to hash + * @param {number} seed - Seed for hash variation + * @returns {number} Hash value + */ + _hash(item, seed) { + let hash = 0; + for (let i = 0; i < item.length; i++) { + hash = (hash * seed + item.charCodeAt(i)) % this.size; + } + return hash; + } + + /** + * Get all hash values for an item + * @param {string} item - Item to hash + * @returns {number[]} Array of hash positions + */ + _getHashes(item) { + const hashes = []; + // Using different prime numbers as seeds for variety + const seeds = [17, 31, 43, 67, 89].slice(0, this.numHashes); + + for (const seed of seeds) { + const hash = this._hash(item, seed); + hashes.push(Math.abs(hash) % this.size); + } + return hashes; + } + + /** + * Add an item to the Bloom Filter + * @param {string} item - Item to add + */ + add(item) { + const hashes = this._getHashes(item); + for (const position of hashes) { + this.bitArray[position] = true; + } + } + + /** + * Check if an item MIGHT be in the set + * @param {string} item - Item to check + * @returns {boolean} True if probably exists (may have false positives) + */ + mightContain(item) { + const hashes = this._getHashes(item); + for (const position of hashes) { + if (!this.bitArray[position]) { + return false; // Definitely not in set + } + } + return true; // Probably in set (could be false positive) + } + + /** + * Calculate current approximate false positive rate + * @returns {number} Estimated false positive probability + */ + falsePositiveRate() { + // Count how many bits are set to true + const setBits = this.bitArray.filter(bit => bit).length; + const ratio = setBits / this.size; + + // Formula: (1 - e^(-k * n / m)) ^ k + return Math.pow(1 - Math.exp(-this.numHashes * ratio), this.numHashes); + } + + /** + * Get statistics about the Bloom Filter + * @returns {Object} Statistics object + */ + getStats() { + const setBits = this.bitArray.filter(bit => bit).length; + return { + size: this.size, + numHashes: this.numHashes, + bitsSet: setBits, + utilization: (setBits / this.size * 100).toFixed(2) + '%', + falsePositiveRate: (this.falsePositiveRate() * 100).toFixed(2) + '%' + }; + } + + /** + * Clear the Bloom Filter + */ + clear() { + this.bitArray.fill(false); + } +} + +// Advanced Bloom Filter with better hash functions +class AdvancedBloomFilter extends BloomFilter { + /** + * Better hash function using MurmurHash inspiration + */ + _hash(item, seed) { + let hash = 0; + for (let i = 0; i < item.length; i++) { + hash = hash * seed + item.charCodeAt(i); + hash = hash & hash; // Convert to 32-bit integer + } + return Math.abs(hash) % this.size; + } +} + +// Comprehensive test cases and examples +function testBloomFilter() { + console.log("=== Bloom Filter Implementation ===\n"); + + // Create a Bloom Filter + const bloom = new BloomFilter(100, 3); + + // Test data + const websites = [ + "google.com", "github.com", "stackoverflow.com", + "wikipedia.org", "youtube.com", "reddit.com" + ]; + + const notAdded = [ + "twitter.com", "facebook.com", "instagram.com", + "amazon.com", "netflix.com" + ]; + + console.log("📝 Adding websites to Bloom Filter:"); + websites.forEach(site => { + bloom.add(site); + console.log(` Added: ${site}`); + }); + + console.log("\n✅ Checking added websites (should all be true):"); + websites.forEach(site => { + const result = bloom.mightContain(site); + console.log(` ${site}: ${result} ${result ? '✓' : '✗'}`); + }); + + console.log("\n❌ Checking non-added websites (might have false positives):"); + notAdded.forEach(site => { + const result = bloom.mightContain(site); + console.log(` ${site}: ${result} ${!result ? '✓' : '?'}`); + }); + + console.log("\n📊 Bloom Filter Statistics:"); + console.log(bloom.getStats()); + + // Demonstrate false positive concept + console.log("\n🎯 Educational Example - False Positives:"); + const smallBloom = new BloomFilter(10, 2); + smallBloom.add("test"); + console.log(" Small filter with 'test' added:"); + console.log(" Checking 'random':", smallBloom.mightContain("random")); + console.log(" False positive rate:", (smallBloom.falsePositiveRate() * 100).toFixed(2) + '%'); +} + +// Real-world use case example +function spellCheckerExample() { + console.log("\n=== Real World Example: Spell Checker ==="); + + const dictionary = new BloomFilter(500, 4); + const validWords = ["hello", "world", "javascript", "algorithm", "data", "structure"]; + + validWords.forEach(word => dictionary.add(word)); + + const testWords = ["hello", "helo", "world", "wordl", "algorithm", "algorith"]; + + testWords.forEach(word => { + const exists = dictionary.mightContain(word); + console.log(` "${word}" ${exists ? 'might be' : 'is definitely not'} in dictionary`); + }); +} + +// Run tests +if (require.main === module) { + testBloomFilter(); + spellCheckerExample(); +} + +module.exports = { BloomFilter, AdvancedBloomFilter }; \ No newline at end of file diff --git a/javascript/Bubblesort.js b/javascript/Bubblesort.js new file mode 100644 index 00000000..e69de29b diff --git a/javascript/ClimbingStairs.js b/javascript/ClimbingStairs.js index 4d0de593..67e66eee 100644 --- a/javascript/ClimbingStairs.js +++ b/javascript/ClimbingStairs.js @@ -1,11 +1,12 @@ // Time: O(n), Space: O(1) -var climbStairs = function(n) { - if (n <= 2) return n; - let first = 1, second = 2; - for (let i = 3; i <= n; i++) { - let third = first + second; - first = second; - second = third; - } - return second; +var climbStairs = function (n) { + if (n <= 2) return n; + let first = 1, + second = 2; + for (let i = 3; i <= n; i++) { + let third = first + second; + first = second; + second = third; + } + return second; }; diff --git a/javascript/Container_with_most_water.js b/javascript/Container_with_most_water.js new file mode 100644 index 00000000..96d4559a --- /dev/null +++ b/javascript/Container_with_most_water.js @@ -0,0 +1,19 @@ +/* +Problem Statement: You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]). +Find two lines that together with the x-axis form a container, such that the container contains the most water. +Return the maximum amount of water a container can store. +Notice that you may not slant the container. +*/ + +var maxArea = function (height){ + let maxArea = 0; + + for(let a=0; a 0) { + sum += this.tree[i]; + i -= i & -i; + } + return sum; + } + + rangeQuery(l, r) { + if (l > r) return 0; + return this.query(r) - this.query(l - 1); + } + + build(arr) { + for (let i = 0; i < arr.length; i++) { + this.update(i, arr[i]); + } + } +} diff --git a/javascript/LRUcache.js b/javascript/LRUcache.js new file mode 100644 index 00000000..d05716e4 --- /dev/null +++ b/javascript/LRUcache.js @@ -0,0 +1,285 @@ +/** + * LRU (Least Recently Used) Cache Implementation + * + * A fixed-size cache that removes the least recently used items when full. + * Supports O(1) get and put operations using HashMap + Doubly Linked List. + * + * Time Complexity: + * - get: O(1) + * - put: O(1) + * + * Space Complexity: O(capacity) + * + * Real-world Applications: + * - CPU cache management + * - Database query caching + * - Web browser cache + * - Redis/Memcached + */ + +class ListNode { + constructor(key, value) { + this.key = key; + this.value = value; + this.prev = null; + this.next = null; + } +} + +class LRUCache { + /** + * @param {number} capacity - Maximum number of items cache can hold + */ + constructor(capacity) { + this.capacity = capacity; + this.cache = new Map(); // Hash map for O(1) access + this.size = 0; + + // Dummy head and tail for the doubly linked list + this.head = new ListNode(0, 0); // Most recently used + this.tail = new ListNode(0, 0); // Least recently used + + // Initialize empty list + this.head.next = this.tail; + this.tail.prev = this.head; + } + + /** + * Get value by key and mark as most recently used + * @param {number} key + * @return {number} value or -1 if not found + */ + get(key) { + if (!this.cache.has(key)) { + return -1; + } + + const node = this.cache.get(key); + this._moveToHead(node); // Mark as recently used + return node.value; + } + + /** + * Add or update key-value pair + * @param {number} key + * @param {number} value + * @return {void} + */ + put(key, value) { + if (this.cache.has(key)) { + // Update existing key + const node = this.cache.get(key); + node.value = value; + this._moveToHead(node); + } else { + // Add new key + const newNode = new ListNode(key, value); + this.cache.set(key, newNode); + this._addNode(newNode); + this.size++; + + // Evict if over capacity + if (this.size > this.capacity) { + const tail = this._popTail(); + this.cache.delete(tail.key); + this.size--; + } + } + } + + /** + * Remove least recently used item + * @return {ListNode} removed node + */ + _popTail() { + const tail = this.tail.prev; + this._removeNode(tail); + return tail; + } + + /** + * Move node to head (most recently used position) + * @param {ListNode} node + */ + _moveToHead(node) { + this._removeNode(node); + this._addNode(node); + } + + /** + * Remove node from linked list + * @param {ListNode} node + */ + _removeNode(node) { + const prev = node.prev; + const next = node.next; + + prev.next = next; + next.prev = prev; + } + + /** + * Add node to head (most recently used position) + * @param {ListNode} node + */ + _addNode(node) { + node.prev = this.head; + node.next = this.head.next; + + this.head.next.prev = node; + this.head.next = node; + } + + /** + * Get current cache size + * @return {number} + */ + getSize() { + return this.size; + } + + /** + * Get all cache entries in MRU to LRU order + * @return {Array} Array of [key, value] pairs + */ + getEntries() { + const entries = []; + let current = this.head.next; + + while (current !== this.tail) { + entries.push([current.key, current.value]); + current = current.next; + } + + return entries; + } + + /** + * Clear the entire cache + */ + clear() { + this.cache.clear(); + this.size = 0; + this.head.next = this.tail; + this.tail.prev = this.head; + } + + /** + * Get cache statistics + * @return {Object} Cache metrics + */ + getStats() { + return { + size: this.size, + capacity: this.capacity, + usage: `${this.size}/${this.capacity}`, + isFull: this.size === this.capacity + }; + } +} + +// Example Usage and Demonstration +function demonstrateLRUCache() { + console.log("=== LRU Cache Demonstration ===\n"); + + // Create cache with capacity 3 + const cache = new LRUCache(3); + + console.log("1. Initializing cache with capacity 3"); + console.log("Cache stats:", cache.getStats()); + + // Test sequence + console.log("\n2. Adding items:"); + cache.put(1, "A"); + cache.put(2, "B"); + cache.put(3, "C"); + console.log("After adding 3 items:", cache.getEntries()); + console.log("Cache stats:", cache.getStats()); + + console.log("\n3. Access pattern:"); + console.log("Get key 2:", cache.get(2)); // B (moves 2 to MRU) + console.log("Get key 1:", cache.get(1)); // A (moves 1 to MRU) + console.log("Current order:", cache.getEntries()); + + console.log("\n4. Adding 4th item (should evict LRU):"); + cache.put(4, "D"); + console.log("After adding 4th item:", cache.getEntries()); + console.log("Key 3 should be evicted (LRU)"); + + console.log("\n5. Update existing key:"); + cache.put(2, "B-UPDATED"); + console.log("After updating key 2:", cache.getEntries()); + + console.log("\n6. Get non-existent key:"); + console.log("Get key 5:", cache.get(5)); // -1 (not found) + + console.log("\n7. Final cache state:"); + console.log("Entries:", cache.getEntries()); + console.log("Stats:", cache.getStats()); +} + +// Advanced Example: Browser Cache Simulation +class BrowserCache extends LRUCache { + constructor(capacity) { + super(capacity); + this.hits = 0; + this.misses = 0; + } + + get(key) { + const result = super.get(key); + if (result !== -1) { + this.hits++; + } else { + this.misses++; + } + return result; + } + + getHitRate() { + const total = this.hits + this.misses; + return total > 0 ? (this.hits / total * 100).toFixed(2) + '%' : '0%'; + } + + getStats() { + const baseStats = super.getStats(); + return { + ...baseStats, + hits: this.hits, + misses: this.misses, + hitRate: this.getHitRate() + }; + } +} + +function demonstrateBrowserCache() { + console.log("\n\n=== Browser Cache Simulation ==="); + + const browserCache = new BrowserCache(2); + const requests = ['home', 'about', 'home', 'contact', 'about', 'home', 'products']; + + console.log("Cache capacity: 2"); + console.log("Request sequence:", requests); + console.log("\nProcessing requests:"); + + requests.forEach((page, i) => { + const result = browserCache.get(page); + if (result === -1) { + console.log(`Request ${i + 1}: '${page}' - MISS - loading from server`); + browserCache.put(page, `Content for ${page}`); + } else { + console.log(`Request ${i + 1}: '${page}' - HIT - served from cache`); + } + }); + + console.log("\nFinal cache state:", browserCache.getEntries()); + console.log("Performance stats:", browserCache.getStats()); +} + +// Run demonstrations +if (require.main === module) { + demonstrateLRUCache(); + demonstrateBrowserCache(); +} + +module.exports = { LRUCache, BrowserCache }; \ No newline at end of file diff --git a/javascript/LongestSubstringWithoutRepeatingCharacters.js b/javascript/LongestSubstringWithoutRepeatingCharacters.js deleted file mode 100644 index a1a05987..00000000 --- a/javascript/LongestSubstringWithoutRepeatingCharacters.js +++ /dev/null @@ -1,12 +0,0 @@ -// Time: O(n), Space: O(n) -var lengthOfLongestSubstring = function(s) { - let set = new Set(), left = 0, maxLength = 0; - for (let right = 0; right < s.length; right++) { - while (set.has(s[right])) { - set.delete(s[left++]); - } - set.add(s[right]); - maxLength = Math.max(maxLength, right - left + 1); - } - return maxLength; -}; diff --git a/javascript/MaximumSubarray.js b/javascript/MaximumSubarray.js index ddd36255..8adafe08 100644 --- a/javascript/MaximumSubarray.js +++ b/javascript/MaximumSubarray.js @@ -1,10 +1,10 @@ // Time: O(n), Space: O(1) -var maxSubArray = function(nums) { - let maxSoFar = nums[0]; - let current = nums[0]; - for (let i = 1; i < nums.length; i++) { - current = Math.max(nums[i], current + nums[i]); - maxSoFar = Math.max(maxSoFar, current); - } - return maxSoFar; +var maxSubArray = function (nums) { + let maxSoFar = nums[0]; + let current = nums[0]; + for (let i = 1; i < nums.length; i++) { + current = Math.max(nums[i], current + nums[i]); + maxSoFar = Math.max(maxSoFar, current); + } + return maxSoFar; }; diff --git a/javascript/MergeTwoSortedLists.js b/javascript/MergeTwoSortedLists.js deleted file mode 100644 index 19f3ddff..00000000 --- a/javascript/MergeTwoSortedLists.js +++ /dev/null @@ -1,17 +0,0 @@ -// Time: O(m+n), Space: O(1) -var mergeTwoLists = function(list1, list2) { - let dummy = { val: -1, next: null }; - let current = dummy; - while (list1 && list2) { - if (list1.val < list2.val) { - current.next = list1; - list1 = list1.next; - } else { - current.next = list2; - list2 = list2.next; - } - current = current.next; - } - current.next = list1 || list2; - return dummy.next; -}; diff --git a/javascript/ProductofArrayExceptSelf.js b/javascript/ProductofArrayExceptSelf.js deleted file mode 100644 index dd325c32..00000000 --- a/javascript/ProductofArrayExceptSelf.js +++ /dev/null @@ -1,17 +0,0 @@ -// Time: O(n), Space: O(1) (excluding output array) -var productExceptSelf = function(nums) { - let res = Array(nums.length).fill(1); - let left = 1, right = 1; - - for (let i = 0; i < nums.length; i++) { - res[i] *= left; - left *= nums[i]; - } - - for (let i = nums.length - 1; i >= 0; i--) { - res[i] *= right; - right *= nums[i]; - } - - return res; -}; diff --git a/javascript/Stack.js b/javascript/Stack.js new file mode 100644 index 00000000..a66cc6a6 --- /dev/null +++ b/javascript/Stack.js @@ -0,0 +1,448 @@ +/** + * Comprehensive Stack Data Structure Implementation + * + * A stack is a linear data structure that follows the Last In First Out (LIFO) principle. + * The last element inserted is the first one to be removed. + * + * Time Complexity: + * - Push: O(1) + * - Pop: O(1) + * - Peek/Top: O(1) + * - Search: O(n) + * + * Space Complexity: O(n) where n is the number of elements + * + * Author: Hacktoberfest Contributor + * Date: October 2024 + */ + +class Stack { + constructor() { + this.items = []; + this.count = 0; + } + + /** + * Add an element to the top of the stack + * @param {*} element - Element to push + * @return {number} New size of stack + */ + push(element) { + this.items[this.count] = element; + this.count++; + return this.count; + } + + /** + * Remove and return the top element + * @return {*} The removed element, or undefined if empty + */ + pop() { + if (this.isEmpty()) { + return undefined; + } + this.count--; + const result = this.items[this.count]; + delete this.items[this.count]; + return result; + } + + /** + * Return the top element without removing it + * @return {*} Top element, or undefined if empty + */ + peek() { + if (this.isEmpty()) { + return undefined; + } + return this.items[this.count - 1]; + } + + /** + * Check if the stack is empty + * @return {boolean} True if empty, false otherwise + */ + isEmpty() { + return this.count === 0; + } + + /** + * Get the size of the stack + * @return {number} Number of elements + */ + size() { + return this.count; + } + + /** + * Clear all elements from the stack + */ + clear() { + this.items = []; + this.count = 0; + } + + /** + * Convert stack to array (bottom to top) + * @return {Array} Array representation of stack + */ + toArray() { + return this.items.slice(0, this.count); + } + + /** + * Display stack contents + * @return {string} String representation + */ + toString() { + if (this.isEmpty()) { + return 'Stack: []'; + } + return `Stack: [${this.toArray().join(', ')}] <- top`; + } + + /** + * Search for an element (returns position from top, 1-indexed) + * @param {*} element - Element to search for + * @return {number} Position from top (1-indexed), or -1 if not found + */ + search(element) { + for (let i = this.count - 1; i >= 0; i--) { + if (this.items[i] === element) { + return this.count - i; // Position from top + } + } + return -1; + } +} + +/** + * Stack applications and utility functions + */ +class StackApplications { + + /** + * Check if parentheses are balanced + * @param {string} str - String containing parentheses + * @return {boolean} True if balanced, false otherwise + */ + static isBalancedParentheses(str) { + const stack = new Stack(); + const pairs = { + '(': ')', + '[': ']', + '{': '}' + }; + + for (let char of str) { + if (char in pairs) { + // Opening bracket + stack.push(char); + } else if (Object.values(pairs).includes(char)) { + // Closing bracket + if (stack.isEmpty()) return false; + const top = stack.pop(); + if (pairs[top] !== char) return false; + } + } + + return stack.isEmpty(); + } + + /** + * Convert infix expression to postfix (Reverse Polish Notation) + * @param {string} infix - Infix expression + * @return {string} Postfix expression + */ + static infixToPostfix(infix) { + const stack = new Stack(); + let postfix = ''; + + const precedence = { + '+': 1, '-': 1, + '*': 2, '/': 2, + '^': 3 + }; + + const isOperator = (char) => char in precedence; + const isOperand = (char) => /[a-zA-Z0-9]/.test(char); + + for (let char of infix) { + if (isOperand(char)) { + postfix += char; + } else if (char === '(') { + stack.push(char); + } else if (char === ')') { + while (!stack.isEmpty() && stack.peek() !== '(') { + postfix += stack.pop(); + } + stack.pop(); // Remove '(' + } else if (isOperator(char)) { + while (!stack.isEmpty() && + stack.peek() !== '(' && + precedence[stack.peek()] >= precedence[char]) { + postfix += stack.pop(); + } + stack.push(char); + } + } + + while (!stack.isEmpty()) { + postfix += stack.pop(); + } + + return postfix; + } + + /** + * Evaluate postfix expression + * @param {string} postfix - Postfix expression + * @return {number} Result of evaluation + */ + static evaluatePostfix(postfix) { + const stack = new Stack(); + + for (let char of postfix) { + if (/\d/.test(char)) { + stack.push(parseInt(char)); + } else { + const b = stack.pop(); + const a = stack.pop(); + + switch (char) { + case '+': stack.push(a + b); break; + case '-': stack.push(a - b); break; + case '*': stack.push(a * b); break; + case '/': stack.push(Math.floor(a / b)); break; + case '^': stack.push(Math.pow(a, b)); break; + } + } + } + + return stack.pop(); + } + + /** + * Find next greater element for each element in array + * @param {number[]} arr - Input array + * @return {number[]} Array with next greater elements (-1 if none) + */ + static nextGreaterElement(arr) { + const stack = new Stack(); + const result = new Array(arr.length).fill(-1); + + for (let i = arr.length - 1; i >= 0; i--) { + // Pop elements smaller than current + while (!stack.isEmpty() && stack.peek() <= arr[i]) { + stack.pop(); + } + + // If stack not empty, top is the next greater element + if (!stack.isEmpty()) { + result[i] = stack.peek(); + } + + // Push current element + stack.push(arr[i]); + } + + return result; + } + + /** + * Calculate maximum area in histogram + * @param {number[]} heights - Array of histogram heights + * @return {number} Maximum rectangular area + */ + static largestRectangleArea(heights) { + const stack = new Stack(); + let maxArea = 0; + let index = 0; + + while (index < heights.length) { + if (stack.isEmpty() || heights[index] >= heights[stack.peek()]) { + stack.push(index++); + } else { + const top = stack.pop(); + const area = heights[top] * (stack.isEmpty() ? index : index - stack.peek() - 1); + maxArea = Math.max(maxArea, area); + } + } + + while (!stack.isEmpty()) { + const top = stack.pop(); + const area = heights[top] * (stack.isEmpty() ? index : index - stack.peek() - 1); + maxArea = Math.max(maxArea, area); + } + + return maxArea; + } +} + +/** + * Demonstration and testing functions + */ +function demonstrateStack() { + console.log('📚 STACK DATA STRUCTURE DEMONSTRATION'); + console.log('=====================================\n'); + + // Basic operations + console.log('1. Basic Stack Operations:'); + const stack = new Stack(); + + console.log(stack.toString()); // Empty stack + + stack.push(10); + stack.push(20); + stack.push(30); + console.log(stack.toString()); // [10, 20, 30] + + console.log(`Peek: ${stack.peek()}`); // 30 + console.log(`Pop: ${stack.pop()}`); // 30 + console.log(stack.toString()); // [10, 20] + + console.log(`Size: ${stack.size()}`); // 2 + console.log(`Search 20: ${stack.search(20)}`); // 1 (position from top) + console.log(`Search 10: ${stack.search(10)}`); // 2 + console.log(`Search 99: ${stack.search(99)}`); // -1 + + console.log('\n' + '='.repeat(50) + '\n'); + + // Applications + console.log('2. Stack Applications:'); + + // Balanced parentheses + const expressions = [ + '()', + '()[]{}', + '([{}])', + '(((', + '({[}])', + '{[()()]}' + ]; + + console.log('Balanced Parentheses Check:'); + expressions.forEach(expr => { + const balanced = StackApplications.isBalancedParentheses(expr); + console.log(`${expr.padEnd(10)} -> ${balanced ? '✓' : '✗'}`); + }); + + console.log('\nInfix to Postfix Conversion:'); + const infixExpressions = ['A+B*C', '(A+B)*C', 'A+B*C-D']; + infixExpressions.forEach(expr => { + const postfix = StackApplications.infixToPostfix(expr); + console.log(`${expr.padEnd(10)} -> ${postfix}`); + }); + + console.log('\nPostfix Evaluation:'); + const postfixExpressions = ['23+', '23*45*+', '532*+']; + postfixExpressions.forEach(expr => { + const result = StackApplications.evaluatePostfix(expr); + console.log(`${expr.padEnd(10)} -> ${result}`); + }); + + console.log('\nNext Greater Element:'); + const arrays = [[4, 5, 2, 25], [13, 7, 6, 12], [1, 2, 3, 4, 5]]; + arrays.forEach(arr => { + const nge = StackApplications.nextGreaterElement(arr); + console.log(`${JSON.stringify(arr)} -> ${JSON.stringify(nge)}`); + }); + + console.log('\nLargest Rectangle in Histogram:'); + const histograms = [[2, 1, 5, 6, 2, 3], [6, 2, 5, 4, 5, 1, 6]]; + histograms.forEach(heights => { + const area = StackApplications.largestRectangleArea(heights); + console.log(`${JSON.stringify(heights)} -> Max area: ${area}`); + }); +} + +/** + * Performance testing + */ +function performanceTest() { + console.log('\n' + '='.repeat(50)); + console.log('3. Performance Testing:'); + console.log('='.repeat(50)); + + const stack = new Stack(); + const n = 100000; + + // Push performance + console.time('Push 100k elements'); + for (let i = 0; i < n; i++) { + stack.push(i); + } + console.timeEnd('Push 100k elements'); + + // Pop performance + console.time('Pop 100k elements'); + for (let i = 0; i < n; i++) { + stack.pop(); + } + console.timeEnd('Pop 100k elements'); + + console.log(`Final stack size: ${stack.size()}`); +} + +/** + * Interactive demo (for Node.js environment with readline) + */ +function interactiveDemo() { + console.log('\n🎮 INTERACTIVE STACK DEMO'); + console.log('=========================='); + console.log('Commands: push , pop, peek, size, clear, search , quit'); + + const stack = new Stack(); + + // This would work in a Node.js environment with readline + console.log('Note: Interactive demo requires Node.js readline module'); + console.log('Example usage:'); + console.log('> push 10'); + console.log('> push 20'); + console.log('> peek'); + console.log('> pop'); + console.log(stack.toString()); +} + +// Main execution +if (typeof module !== 'undefined' && module.exports) { + // Node.js environment + module.exports = { Stack, StackApplications }; + + if (require.main === module) { + demonstrateStack(); + performanceTest(); + interactiveDemo(); + } +} else { + // Browser environment + window.Stack = Stack; + window.StackApplications = StackApplications; + + // Auto-run demonstration + demonstrateStack(); + performanceTest(); +} + +/* + * Usage Examples: + * + * // Create a new stack + * const myStack = new Stack(); + * + * // Basic operations + * myStack.push(10); + * myStack.push(20); + * console.log(myStack.peek()); // 20 + * console.log(myStack.pop()); // 20 + * console.log(myStack.size()); // 1 + * + * // Check balanced parentheses + * console.log(StackApplications.isBalancedParentheses('([{}])')); // true + * + * // Convert infix to postfix + * console.log(StackApplications.infixToPostfix('A+B*C')); // "ABC*+" + * + * // Next greater element + * console.log(StackApplications.nextGreaterElement([4, 5, 2, 25])); // [5, 25, 25, -1] + */ \ No newline at end of file diff --git a/javascript/TopKFrequentElements.js b/javascript/TopKFrequentElements.js deleted file mode 100644 index c3aa4e72..00000000 --- a/javascript/TopKFrequentElements.js +++ /dev/null @@ -1,8 +0,0 @@ -// Time: O(n log k), Space: O(n) -var topKFrequent = function(nums, k) { - const freqMap = new Map(); - nums.forEach(num => freqMap.set(num, (freqMap.get(num) || 0) + 1)); - - const heap = [...freqMap.entries()].sort((a, b) => b[1] - a[1]); - return heap.slice(0, k).map(entry => entry[0]); -}; diff --git a/javascript/Trie.js b/javascript/Trie.js new file mode 100644 index 00000000..b6a2082b --- /dev/null +++ b/javascript/Trie.js @@ -0,0 +1,311 @@ +/** + * Trie (Prefix Tree) Implementation in JavaScript + * + * A Trie is a tree-like data structure that stores strings in a way that + * allows for efficient prefix-based searching, autocomplete, and spell checking. + * + * Time Complexity: + * - Insert: O(m) where m is the length of the word + * - Search: O(m) where m is the length of the word + * - Prefix Search: O(m) where m is the length of the prefix + * + * Space Complexity: O(n * m) where n is number of words and m is average length + */ + +class TrieNode { + constructor() { + this.children = new Map(); // Stores character -> TrieNode mappings + this.isEndOfWord = false; // Marks if this node completes a word + this.frequency = 0; // Optional: track how many times word was inserted + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + this.totalWords = 0; + } + + /** + * Insert a word into the trie + * @param {string} word - The word to insert + */ + insert(word) { + if (!word || word.length === 0) return false; + + let currentNode = this.root; + + for (let char of word.toLowerCase()) { + if (!currentNode.children.has(char)) { + currentNode.children.set(char, new TrieNode()); + } + currentNode = currentNode.children.get(char); + } + + // Mark the end of word and update frequency + if (!currentNode.isEndOfWord) { + this.totalWords++; + } + currentNode.isEndOfWord = true; + currentNode.frequency++; + + return true; + } + + /** + * Search for a complete word in the trie + * @param {string} word - The word to search for + * @returns {boolean} - True if word exists + */ + search(word) { + if (!word || word.length === 0) return false; + + let currentNode = this.root; + + for (let char of word.toLowerCase()) { + if (!currentNode.children.has(char)) { + return false; + } + currentNode = currentNode.children.get(char); + } + + return currentNode.isEndOfWord; + } + + /** + * Check if any word in trie starts with given prefix + * @param {string} prefix - The prefix to check + * @returns {boolean} - True if prefix exists + */ + startsWith(prefix) { + if (!prefix || prefix.length === 0) return false; + + let currentNode = this.root; + + for (let char of prefix.toLowerCase()) { + if (!currentNode.children.has(char)) { + return false; + } + currentNode = currentNode.children.get(char); + } + + return true; + } + + /** + * Get all words with given prefix (autocomplete) + * @param {string} prefix - The prefix to autocomplete + * @returns {string[]} - Array of matching words + */ + autocomplete(prefix) { + if (!prefix || prefix.length === 0) return []; + + let currentNode = this.root; + const results = []; + + // Navigate to the prefix node + for (let char of prefix.toLowerCase()) { + if (!currentNode.children.has(char)) { + return results; // No words with this prefix + } + currentNode = currentNode.children.get(char); + } + + // Collect all words from this node + this._collectWords(currentNode, prefix, results); + return results; + } + + /** + * Helper method to collect all words from a node + * @param {TrieNode} node - Current node + * @param {string} currentWord - Current word being built + * @param {string[]} results - Array to store results + */ + _collectWords(node, currentWord, results) { + if (node.isEndOfWord) { + results.push({ + word: currentWord, + frequency: node.frequency + }); + } + + for (let [char, childNode] of node.children) { + this._collectWords(childNode, currentWord + char, results); + } + } + + /** + * Delete a word from the trie + * @param {string} word - The word to delete + * @returns {boolean} - True if word was deleted + */ + delete(word) { + if (!word || word.length === 0) return false; + return this._deleteHelper(this.root, word.toLowerCase(), 0); + } + + /** + * Recursive helper for deletion + */ + _deleteHelper(node, word, index) { + if (index === word.length) { + if (!node.isEndOfWord) return false; + + node.isEndOfWord = false; + this.totalWords--; + return node.children.size === 0; // Can be deleted if no children + } + + const char = word[index]; + if (!node.children.has(char)) return false; + + const childNode = node.children.get(char); + const shouldDeleteChild = this._deleteHelper(childNode, word, index + 1); + + if (shouldDeleteChild) { + node.children.delete(char); + return node.children.size === 0 && !node.isEndOfWord; + } + + return false; + } + + /** + * Get the longest common prefix of all words + * @returns {string} - Longest common prefix + */ + longestCommonPrefix() { + let prefix = ""; + let currentNode = this.root; + + while (currentNode.children.size === 1 && !currentNode.isEndOfWord) { + const [char, childNode] = Array.from(currentNode.children)[0]; + prefix += char; + currentNode = childNode; + } + + return prefix; + } + + /** + * Get total number of words in trie + * @returns {number} - Word count + */ + getWordCount() { + return this.totalWords; + } + + /** + * Get all words in trie + * @returns {string[]} - All words + */ + getAllWords() { + const results = []; + this._collectWords(this.root, "", results); + return results.map(item => item.word).sort(); + } + + /** + * Clear the entire trie + */ + clear() { + this.root = new TrieNode(); + this.totalWords = 0; + } +} + +// Example Usage and Test Cases +function demonstrateTrie() { + console.log("=== Trie Data Structure Demonstration ===\n"); + + const trie = new Trie(); + + // Insert words + const words = ["apple", "app", "application", "banana", "bat", "ball", "cat"]; + words.forEach(word => trie.insert(word)); + + console.log("1. Inserted words:", words); + console.log("Total words in trie:", trie.getWordCount()); + + // Search operations + console.log("\n2. Search Operations:"); + console.log("Search 'apple':", trie.search("apple")); // true + console.log("Search 'app':", trie.search("app")); // true + console.log("Search 'appl':", trie.search("appl")); // false + console.log("Search 'dog':", trie.search("dog")); // false + + // Prefix search + console.log("\n3. Prefix Search:"); + console.log("StartsWith 'app':", trie.startsWith("app")); // true + console.log("StartsWith 'ba':", trie.startsWith("ba")); // true + console.log("StartsWith 'dog':", trie.startsWith("dog")); // false + + // Autocomplete + console.log("\n4. Autocomplete Suggestions:"); + console.log("Prefix 'app':", trie.autocomplete("app").map(item => item.word)); + console.log("Prefix 'ba':", trie.autocomplete("ba").map(item => item.word)); + console.log("Prefix 'c':", trie.autocomplete("c").map(item => item.word)); + + // Delete operations + console.log("\n5. Delete Operations:"); + console.log("Delete 'app':", trie.delete("app")); + console.log("Search 'app' after deletion:", trie.search("app")); // false + console.log("StartsWith 'app' after deletion:", trie.startsWith("app")); // true + console.log("Autocomplete 'app' after deletion:", trie.autocomplete("app").map(item => item.word)); + + // Longest common prefix + console.log("\n6. Longest Common Prefix:", trie.longestCommonPrefix()); + + // Get all words + console.log("\n7. All words in trie:", trie.getAllWords()); +} + +// Advanced Example: Spell Checker using Trie +class SpellChecker { + constructor() { + this.trie = new Trie(); + } + + addToDictionary(words) { + words.forEach(word => this.trie.insert(word)); + } + + suggestCorrections(word, maxSuggestions = 5) { + if (this.trie.search(word)) { + return [`"${word}" is spelled correctly!`]; + } + + const suggestions = this.trie.autocomplete(word.slice(0, 3)); + return suggestions + .sort((a, b) => b.frequency - a.frequency) + .slice(0, maxSuggestions) + .map(item => item.word); + } +} + +// Demonstrate spell checker +function demonstrateSpellChecker() { + console.log("\n\n=== Spell Checker Demonstration ==="); + + const spellChecker = new SpellChecker(); + const dictionary = [ + "hello", "world", "javascript", "programming", + "algorithm", "data", "structure", "computer", + "science", "code", "development", "web" + ]; + + spellChecker.addToDictionary(dictionary); + + console.log("Suggestions for 'prog':", spellChecker.suggestCorrections("prog")); + console.log("Suggestions for 'dat':", spellChecker.suggestCorrections("dat")); + console.log("Suggestions for 'xyz':", spellChecker.suggestCorrections("xyz")); +} + +// Run demonstrations +if (require.main === module) { + demonstrateTrie(); + demonstrateSpellChecker(); +} + +module.exports = { Trie, TrieNode, SpellChecker }; \ No newline at end of file diff --git a/javascript/TwoSum.js b/javascript/TwoSum.js index 8fbaee72..236b8d35 100644 --- a/javascript/TwoSum.js +++ b/javascript/TwoSum.js @@ -1,12 +1,12 @@ // Time: O(n), Space: O(n) -var twoSum = function(nums, target) { - const map = new Map(); - for (let i = 0; i < nums.length; i++) { - let complement = target - nums[i]; - if (map.has(complement)) { - return [map.get(complement), i]; - } - map.set(nums[i], i); +var twoSum = function (nums, target) { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + let complement = target - nums[i]; + if (map.has(complement)) { + return [map.get(complement), i]; } - return []; + map.set(nums[i], i); + } + return []; }; diff --git a/javascript/ValidParentheses.js b/javascript/ValidParentheses.js index 5fcfc9e7..801e9a23 100644 --- a/javascript/ValidParentheses.js +++ b/javascript/ValidParentheses.js @@ -1,13 +1,13 @@ // Time: O(n), Space: O(n) -var isValid = function(s) { - const stack = []; - const map = { ')': '(', '}': '{', ']': '[' }; - for (let char of s) { - if (char in map) { - if (stack.length === 0 || stack.pop() !== map[char]) return false; - } else { - stack.push(char); - } +var isValid = function (s) { + const stack = []; + const map = { ")": "(", "}": "{", "]": "[" }; + for (let char of s) { + if (char in map) { + if (stack.length === 0 || stack.pop() !== map[char]) return false; + } else { + stack.push(char); } - return stack.length === 0; + } + return stack.length === 0; }; diff --git a/javascript/addno.js b/javascript/addno.js new file mode 100644 index 00000000..fbdfcc68 --- /dev/null +++ b/javascript/addno.js @@ -0,0 +1,4 @@ +let a = 10; +let b = 20; +let sum = a + b; +console.log("Sum:", sum); diff --git a/javascript/arrayOfObjects.js b/javascript/arrayOfObjects.js new file mode 100644 index 00000000..6ad294dc --- /dev/null +++ b/javascript/arrayOfObjects.js @@ -0,0 +1,49 @@ +const countries = [ + { name: 'United States', population: 331002651, continent: 'North America', capital: 'Washington, D.C.' }, + { name: 'China', population: 1439323776, continent: 'Asia', capital: 'Beijing' }, + { name: 'Brazil', population: 212559417, continent: 'South America', capital: 'Brasília' }, + { name: 'United Kingdom', population: 67886011, continent: 'Europe', capital: 'London' }, + { name: 'South Africa', population: 59308690, continent: 'Africa', capital: 'Pretoria, Cape Town, Bloemfontein' }, +]; + +// 1. Print the names of all countries. +console.log('the names of all countries'); +countries.forEach(item=>console.log(item.name)) + +// 2. Find the country with the largest population. +console.log('the country with the largest population:',countries.reduce((a,b)=>a.population>b.population?a:b)); + +// 3. Find the total population of all countries. +let sum=0 +countries.forEach(item=>sum+=item.population) +console.log('total population of all countries:',sum); + +// 4. Find all countries in a specific continent (e.g., Asia). +console.log('All countries in Asia:'); +countries.forEach(item=>item.continent==='Asia'?console.log(item.name):false) + +// 5. Print the names of capitals with more than one city. +console.log('Names of countrie with more than one capital:',countries.filter(country=>country.capital.includes(','))); + + +// 6. Sort countries based on population (descending order). +console.log('countries based on population (descending order):'); +console.log([...countries].sort((a,b)=>b.population-a.population)); + + +// 7. Find the country with the smallest population. +console.log('country with the smallest population',countries.reduce((a,b)=> + a.population + a.name.length>b.name.length?a:b)); + +// 9. Find the country with the shortest name. +console.log('country with the shortest name',countries.reduce((a,b)=> + a.name.lengthsum+=item.population) +console.log('average population of all countries:',sum/countries.length); \ No newline at end of file diff --git a/javascript/async_await.js b/javascript/async_await.js new file mode 100644 index 00000000..0292cd24 --- /dev/null +++ b/javascript/async_await.js @@ -0,0 +1,26 @@ +function calculateSquare(x){ + return x*x; +} + +function calculate(y){ + var promise=new Promise(function(resolve,reject){ + setTimeout(function(){ + var ss=calculateSquare(y); + resolve(ss); + },5000); + }); +return promise; +} + +async function main(){ + var square1=await calculate(5); + console.log("square of 5:"+square1); + + var square2=await calculate(10); + console.log("sq of 10 is"+square2); + console.log("the end, thank you"); +} + +main(); + +console.log('helll') \ No newline at end of file diff --git a/javascript/bfs.js b/javascript/bfs.js new file mode 100644 index 00000000..162d1b96 --- /dev/null +++ b/javascript/bfs.js @@ -0,0 +1,62 @@ +// Graph class using adjacency list +class Graph { + constructor() { + this.adjList = new Map(); + } + + // Add a vertex to the graph + addVertex(vertex) { + if (!this.adjList.has(vertex)) { + this.adjList.set(vertex, []); + } + } + + // Add an edge between two vertices (undirected graph) + addEdge(v, w) { + if (this.adjList.has(v)) this.adjList.get(v).push(w); + if (this.adjList.has(w)) this.adjList.get(w).push(v); + } + + // Breadth-First Search + bfs(startingVertex) { + const visited = new Set(); // Track visited vertices + const queue = []; // Queue for BFS + const result = []; // Store the order of traversal + + visited.add(startingVertex); + queue.push(startingVertex); + + while (queue.length > 0) { + const vertex = queue.shift(); // Dequeue vertex + result.push(vertex); + + const neighbors = this.adjList.get(vertex); + for (const neighbor of neighbors) { + if (!visited.has(neighbor)) { + visited.add(neighbor); + queue.push(neighbor); + } + } + } + + return result; + } +} + +// Example usage +const g = new Graph(); + +// Add vertices +['A', 'B', 'C', 'D', 'E', 'F'].forEach(v => g.addVertex(v)); + +// Add edges +g.addEdge('A', 'B'); +g.addEdge('A', 'C'); +g.addEdge('B', 'D'); +g.addEdge('B', 'E'); +g.addEdge('C', 'F'); + +// Perform BFS starting from vertex 'A' +const bfsResult = g.bfs('A'); +console.log("BFS Traversal Order:", bfsResult.join(' -> ')); +// Output: BFS Traversal Order: A -> B -> C -> D -> E -> F \ No newline at end of file diff --git a/javascript/calculator.js b/javascript/calculator.js index e6b7b08f..ff70f253 100644 --- a/javascript/calculator.js +++ b/javascript/calculator.js @@ -1,138 +1,145 @@ // Simple Calculator in JavaScript class Calculator { - constructor() { - this.result = 0; - } + constructor() { + this.result = 0; + } - // Addition - add(a, b) { - return a + b; - } + // Addition + add(a, b) { + return a + b; + } - // Subtraction - subtract(a, b) { - return a - b; - } + // Subtraction + subtract(a, b) { + return a - b; + } - // Multiplication - multiply(a, b) { - return a * b; - } + // Multiplication + multiply(a, b) { + return a * b; + } - // Division - divide(a, b) { - if (b === 0) { - throw new Error("Division by zero is not allowed"); - } - return a / b; + // Division + divide(a, b) { + if (b === 0) { + throw new Error("Division by zero is not allowed"); } + return a / b; + } - // Power - power(a, b) { - return Math.pow(a, b); - } + // Power + power(a, b) { + return Math.pow(a, b); + } - // Square root - sqrt(a) { - if (a < 0) { - throw new Error("Square root of negative number is not allowed"); - } - return Math.sqrt(a); + // Square root + sqrt(a) { + if (a < 0) { + throw new Error("Square root of negative number is not allowed"); } + return Math.sqrt(a); + } - // Percentage - percentage(a, b) { - return (a * b) / 100; - } + // Percentage + percentage(a, b) { + return (a * b) / 100; + } + + // Calculate expression (simple parser for basic operations) + calculate(expression) { + try { + // Remove whitespace and validate expression + expression = expression.replace(/\s/g, ""); + + // Basic validation to prevent code injection + if (!/^[0-9+\-*/.()]+$/.test(expression)) { + throw new Error("Invalid characters in expression"); + } - // Calculate expression (simple parser for basic operations) - calculate(expression) { - try { - // Remove whitespace and validate expression - expression = expression.replace(/\s/g, ''); - - // Basic validation to prevent code injection - if (!/^[0-9+\-*/.()]+$/.test(expression)) { - throw new Error("Invalid characters in expression"); - } - - // Use eval for simple expressions (Note: In production, use a proper parser) - return eval(expression); - } catch (error) { - throw new Error("Invalid expression: " + error.message); - } + // Use eval for simple expressions (Note: In production, use a proper parser) + return eval(expression); + } catch (error) { + throw new Error("Invalid expression: " + error.message); } + } } // Function-based calculator (alternative approach) function simpleCalculator() { - const operations = { - '+': (a, b) => a + b, - '-': (a, b) => a - b, - '*': (a, b) => a * b, - '/': (a, b) => { - if (b === 0) throw new Error("Division by zero"); - return a / b; - } - }; - - return { - calculate: (a, operator, b) => { - if (!operations[operator]) { - throw new Error("Unsupported operator"); - } - return operations[operator](a, b); - } - }; + const operations = { + "+": (a, b) => a + b, + "-": (a, b) => a - b, + "*": (a, b) => a * b, + "/": (a, b) => { + if (b === 0) throw new Error("Division by zero"); + return a / b; + }, + }; + + return { + calculate: (a, operator, b) => { + if (!operations[operator]) { + throw new Error("Unsupported operator"); + } + return operations[operator](a, b); + }, + }; } // Interactive calculator function for console usage function interactiveCalculator() { - const calc = new Calculator(); - - console.log("=== Simple Calculator ==="); - console.log("Available operations:"); - console.log("1. Basic arithmetic: add, subtract, multiply, divide"); - console.log("2. Advanced: power, sqrt, percentage"); - console.log("3. Expression evaluation"); - console.log("Examples:"); - console.log("calc.add(5, 3) = " + calc.add(5, 3)); - console.log("calc.subtract(10, 4) = " + calc.subtract(10, 4)); - console.log("calc.multiply(6, 7) = " + calc.multiply(6, 7)); - console.log("calc.divide(15, 3) = " + calc.divide(15, 3)); - console.log("calc.power(2, 3) = " + calc.power(2, 3)); - console.log("calc.sqrt(16) = " + calc.sqrt(16)); - console.log("calc.percentage(20, 15) = " + calc.percentage(20, 15)); - console.log("calc.calculate('(5 + 3) * 2') = " + calc.calculate('(5 + 3) * 2')); - - return calc; + const calc = new Calculator(); + + console.log("=== Simple Calculator ==="); + console.log("Available operations:"); + console.log("1. Basic arithmetic: add, subtract, multiply, divide"); + console.log("2. Advanced: power, sqrt, percentage"); + console.log("3. Expression evaluation"); + console.log("Examples:"); + console.log("calc.add(5, 3) = " + calc.add(5, 3)); + console.log("calc.subtract(10, 4) = " + calc.subtract(10, 4)); + console.log("calc.multiply(6, 7) = " + calc.multiply(6, 7)); + console.log("calc.divide(15, 3) = " + calc.divide(15, 3)); + console.log("calc.power(2, 3) = " + calc.power(2, 3)); + console.log("calc.sqrt(16) = " + calc.sqrt(16)); + console.log("calc.percentage(20, 15) = " + calc.percentage(20, 15)); + console.log( + "calc.calculate('(5 + 3) * 2') = " + calc.calculate("(5 + 3) * 2"), + ); + + return calc; } // Usage examples -if (typeof window === 'undefined') { - // Running in Node.js environment - const calc = interactiveCalculator(); - - // Additional examples - console.log("\n=== More Examples ==="); - try { - console.log("20 + 15 =", calc.add(20, 15)); - console.log("100 - 25 =", calc.subtract(100, 25)); - console.log("12 * 8 =", calc.multiply(12, 8)); - console.log("144 / 12 =", calc.divide(144, 12)); - console.log("3^4 =", calc.power(3, 4)); - console.log("√64 =", calc.sqrt(64)); - console.log("15% of 200 =", calc.percentage(200, 15)); - console.log("Complex: (10 + 5) * 3 - 8 =", calc.calculate("(10 + 5) * 3 - 8")); - } catch (error) { - console.error("Error:", error.message); - } +if (typeof window === "undefined") { + // Running in Node.js environment + const calc = interactiveCalculator(); + + // Additional examples + console.log("\n=== More Examples ==="); + try { + console.log("20 + 15 =", calc.add(20, 15)); + console.log("100 - 25 =", calc.subtract(100, 25)); + console.log("12 * 8 =", calc.multiply(12, 8)); + console.log("144 / 12 =", calc.divide(144, 12)); + console.log("3^4 =", calc.power(3, 4)); + console.log("√64 =", calc.sqrt(64)); + console.log("15% of 200 =", calc.percentage(200, 15)); + console.log( + "Complex: (10 + 5) * 3 - 8 =", + calc.calculate("(10 + 5) * 3 - 8"), + ); + } catch (error) { + console.error("Error:", error.message); + } } else { - // Running in browser environment - console.log("Calculator loaded! Create an instance: const calc = new Calculator();"); + // Running in browser environment + console.log( + "Calculator loaded! Create an instance: const calc = new Calculator();", + ); } // Export for module usage -if (typeof module !== 'undefined' && module.exports) { - module.exports = { Calculator, simpleCalculator }; -} \ No newline at end of file +if (typeof module !== "undefined" && module.exports) { + module.exports = { Calculator, simpleCalculator }; +} diff --git a/javascript/countdowntimer.js b/javascript/countdowntimer.js new file mode 100644 index 00000000..b70010bc --- /dev/null +++ b/javascript/countdowntimer.js @@ -0,0 +1,10 @@ +let count = 5; + +let timer = setInterval(() => { + console.log(count); + count--; + if (count < 0) { + clearInterval(timer); + console.log("Time's up!"); + } +}, 1000); diff --git a/javascript/developer-arnab/README.md b/javascript/developer-arnab/README.md new file mode 100644 index 00000000..3b868d41 --- /dev/null +++ b/javascript/developer-arnab/README.md @@ -0,0 +1,63 @@ +# Problem: Longest Substring Without Repeating Characters + +## Difficulty + +**Medium** + +## Category + +- Strings +- Sliding Window +- Hash Map + +--- + +## Problem Statement + +Given a string `s`, find the **length of the longest substring** without repeating characters. + +--- + +## Input + +- A string `s` consisting of English letters, digits, symbols, and spaces. +- `1 <= s.length <= 10^4` + +--- + +## Output + +- An integer representing the **length of the longest substring without repeating characters**. + +--- + +## Examples + +### Example 1: + +- **Input:** `"abcabcbb"` +- **Output:** `3` +- **Explanation:** The answer is `"abc"`, with the length of 3. + +### Example 2: + +- **Input:** `"bbbbb"` +- **Output:** `1` +- **Explanation:** The answer is `"b"`, with the length of 1. + +### Example 3: + +- **Input:** `"pwwkew"` +- **Output:** `3` +- **Explanation:** The answer is `"wke"`, with the length of 3. + +--- + +## Usage + +```javascript +console.log(lengthOfLongestSubstring("abcabcbb")); // 3 +console.log(lengthOfLongestSubstring("bbbbb")); // 1 +console.log(lengthOfLongestSubstring("pwwkew")); // 3 +console.log(lengthOfLongestSubstring("")); // 0 +``` diff --git a/javascript/developer-arnab/code.js b/javascript/developer-arnab/code.js new file mode 100644 index 00000000..02cc09ae --- /dev/null +++ b/javascript/developer-arnab/code.js @@ -0,0 +1,16 @@ +function lengthOfLongestSubstring(s) { + let charSet = new Set(); + let left = 0; + let maxLength = 0; + + for (let right = 0; right < s.length; right++) { + while (charSet.has(s[right])) { + charSet.delete(s[left]); + left++; + } + charSet.add(s[right]); + maxLength = Math.max(maxLength, right - left + 1); + } + + return maxLength; +} diff --git a/javascript/dfs.js b/javascript/dfs.js new file mode 100644 index 00000000..8a676945 --- /dev/null +++ b/javascript/dfs.js @@ -0,0 +1,58 @@ +// Graph class using adjacency list +class Graph { + constructor() { + this.adjList = new Map(); + } + + // Add a vertex + addVertex(vertex) { + if (!this.adjList.has(vertex)) { + this.adjList.set(vertex, []); + } + } + + // Add an edge (undirected graph) + addEdge(v, w) { + if (this.adjList.has(v)) this.adjList.get(v).push(w); + if (this.adjList.has(w)) this.adjList.get(w).push(v); + } + + // Depth-First Search + dfs(startingVertex) { + const visited = new Set(); + const result = []; + + const dfsRecursive = (vertex) => { + visited.add(vertex); + result.push(vertex); + + const neighbors = this.adjList.get(vertex); + for (const neighbor of neighbors) { + if (!visited.has(neighbor)) { + dfsRecursive(neighbor); + } + } + }; + + dfsRecursive(startingVertex); + return result; + } +} + +// Example usage +const g = new Graph(); + +// Add vertices +['A', 'B', 'C', 'D', 'E', 'F'].forEach(v => g.addVertex(v)); + +// Add edges +g.addEdge('A', 'B'); +g.addEdge('A', 'C'); +g.addEdge('B', 'D'); +g.addEdge('B', 'E'); +g.addEdge('C', 'F'); + +// Perform DFS starting from vertex 'A' +const dfsResult = g.dfs('A'); +console.log("DFS Traversal Order:", dfsResult.join(' -> ')); +// Output: DFS Traversal Order: A -> B -> D -> E -> C -> F diff --git a/javascript/dijkstra.js b/javascript/dijkstra.js new file mode 100644 index 00000000..3a5a2426 --- /dev/null +++ b/javascript/dijkstra.js @@ -0,0 +1,120 @@ +class Graph { + constructor() { + this.adjList = new Map(); // Adjacency list to store the graph + } + + // Add a vertex to the graph + addVertex(vertex) { + if (!this.adjList.has(vertex)) { + this.adjList.set(vertex, []); + } + } + + // Add an edge [neighbor, weight] + addEdge(vertex1, vertex2, weight) { + this.addVertex(vertex1); + this.addVertex(vertex2); + + this.adjList.get(vertex1).push([vertex2, weight]); + this.adjList.get(vertex2).push([vertex1, weight]); // Undirected graph + } + + // Dijkstra's algorithm to find the shortest paths from source + dijkstra(source) { + const distances = {}; + const prev = {}; + const pq = new PriorityQueue(); + const visited = new Set(); + + for (let vertex of this.adjList.keys()) { + distances[vertex] = Infinity; + prev[vertex] = null; + } + distances[source] = 0; + pq.enqueue(source, 0); + + while (!pq.isEmpty()) { + let { element: currentVertex } = pq.dequeue(); + if (visited.has(currentVertex)) continue; + visited.add(currentVertex); + + for (let [neighbor, weight] of this.adjList.get(currentVertex)) { + let alt = distances[currentVertex] + weight; + if (alt < distances[neighbor]) { + distances[neighbor] = alt; + prev[neighbor] = currentVertex; + pq.enqueue(neighbor, alt); + } + } + } + + return { distances, prev }; + } + + // Helper function to reconstruct the shortest path + getPath(prev, target) { + let path = []; + let currentNode = target; + + while (currentNode !== null) { + path.unshift(currentNode); + currentNode = prev[currentNode]; + } + + return path.length === 1 ? [] : path; // If no path found, return an empty array + } +} + +// Priority Queue for Dijkstra's Algorithm (Min-Heap) +class PriorityQueue { + constructor() { + this.queue = []; + } + + enqueue(element, priority) { + this.queue.push({ element, priority }); + this.sort(); + } + + dequeue() { + return this.queue.shift(); // Removes the element with the highest priority (lowest value) + } + + isEmpty() { + return this.queue.length === 0; + } + + sort() { + this.queue.sort((a, b) => a.priority - b.priority); + } +} + +// Example usage: +const graph = new Graph(); + +// Add edges (Undirected graph) +graph.addEdge("A", "B", 4); +graph.addEdge("A", "C", 2); +graph.addEdge("B", "C", 5); +graph.addEdge("B", "D", 10); +graph.addEdge("C", "D", 3); +graph.addEdge("D", "E", 7); +graph.addEdge("C", "E", 1); + +// Run Dijkstra's algorithm from source node 'A' +const { distances, prev } = graph.dijkstra("A"); + +// Output the shortest distances from A to all nodes +console.log("Shortest Distances from A:", distances); + +// Output the shortest path from A to D +const path = graph.getPath(prev, "D"); +console.log("Shortest Path from A to D:", path); + +// To check: +// Navigate to the javascript directory and run the file using Node.js: +// Terminal: node dijkstra.js + +// Expected Output: +// Shortest Distances from A: { A: 0, B: 4, C: 2, D: 5, E: 3 } +// Shortest Path from A to D: [ 'A', 'C', 'D' ] diff --git a/javascript/disjoint_set_union.js b/javascript/disjoint_set_union.js new file mode 100644 index 00000000..33eaf578 --- /dev/null +++ b/javascript/disjoint_set_union.js @@ -0,0 +1,99 @@ +/* +Disjoint Set Union (Union-Find) implementation in JavaScript + +Supports: +- find with path compression +- union by rank/size +- connected queries +- component size + +Use-cases: +- Kruskal's MST +- Connected components +- Cycle detection in undirected graphs +- Dynamic connectivity +*/ + +class DisjointSetUnion { + constructor(n) { + if (typeof n !== 'number' || n <= 0 || !Number.isInteger(n)) { + throw new Error('DisjointSetUnion requires a positive integer size'); + } + this.parent = new Array(n); + this.rank = new Array(n).fill(0); + this.sizeArr = new Array(n).fill(1); + for (let i = 0; i < n; i += 1) this.parent[i] = i; + this.numComponents = n; + } + + // Find representative with path compression + find(x) { + this.#validateIndex(x); + if (this.parent[x] !== x) { + this.parent[x] = this.find(this.parent[x]); + } + return this.parent[x]; + } + + // Union by rank; returns true if merged, false if already same set + union(a, b) { + this.#validateIndex(a); + this.#validateIndex(b); + let ra = this.find(a); + let rb = this.find(b); + if (ra === rb) return false; + + if (this.rank[ra] < this.rank[rb]) { + [ra, rb] = [rb, ra]; + } + this.parent[rb] = ra; + this.sizeArr[ra] += this.sizeArr[rb]; + if (this.rank[ra] === this.rank[rb]) this.rank[ra] += 1; + this.numComponents -= 1; + return true; + } + + // Are a and b in the same component? + connected(a, b) { + return this.find(a) === this.find(b); + } + + // Size of the component containing x + componentSize(x) { + const r = this.find(x); + return this.sizeArr[r]; + } + + // Total number of components + components() { + return this.numComponents; + } + + #validateIndex(x) { + if (!Number.isInteger(x) || x < 0 || x >= this.parent.length) { + throw new Error(`index out of bounds: ${x}`); + } + } +} + +// Demo +function demoDSU() { + const dsu = new DisjointSetUnion(7); + dsu.union(0, 1); + dsu.union(1, 2); + dsu.union(3, 4); + dsu.union(5, 6); + console.log('connected(0,2):', dsu.connected(0, 2)); // true + console.log('connected(0,3):', dsu.connected(0, 3)); // false + console.log('size(0):', dsu.componentSize(0)); // 3 + dsu.union(2, 3); + console.log('components:', dsu.components()); // fewer components +} + +if (require.main === module) { + demoDSU(); +} + +module.exports = { DisjointSetUnion }; + + diff --git a/javascript/evenoroddcheck.js b/javascript/evenoroddcheck.js new file mode 100644 index 00000000..996ffd12 --- /dev/null +++ b/javascript/evenoroddcheck.js @@ -0,0 +1,6 @@ +let num = 7; +if (num % 2 === 0) { + console.log(num, "is Even"); +} else { + console.log(num, "is Odd"); +} diff --git a/javascript/fibonnacci.js b/javascript/fibonnacci.js index cd7f0b4e..050aff41 100644 --- a/javascript/fibonnacci.js +++ b/javascript/fibonnacci.js @@ -1,6 +1,7 @@ function fibonacciSeries(n) { const series = []; - let a = 0, b = 1; + let a = 0, + b = 1; for (let i = 0; i < n; i++) { series.push(a); @@ -8,4 +9,4 @@ function fibonacciSeries(n) { } return series; -} \ No newline at end of file +} diff --git a/javascript/findmax.js b/javascript/findmax.js index 42032c19..17a65479 100644 --- a/javascript/findmax.js +++ b/javascript/findmax.js @@ -1,11 +1,11 @@ function findMax(arr) { - let max = arr[0]; - for (let i = 1; i < arr.length; i++) { - if (arr[i] > max) { - max = arr[i]; - } + let max = arr[0]; + for (let i = 1; i < arr.length; i++) { + if (arr[i] > max) { + max = arr[i]; } - return max; + } + return max; } const nums = [12, 45, 2, 67, 34]; diff --git a/javascript/githubUsernameValidator.js b/javascript/githubUsernameValidator.js new file mode 100644 index 00000000..6cabadb7 --- /dev/null +++ b/javascript/githubUsernameValidator.js @@ -0,0 +1,5 @@ +function isValidGithubUsername(username) { + // 1-39 chars, alphanumeric or hyphen, not start/end with hyphen, no consecutive hyphens + const pattern = /^(?!-)(?!.*--)[A-Za-z0-9-]{1,39}(? { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === '0') + return; + + grid[r][c] = '0'; + for (const [dr, dc] of directions) { + dfs(r + dr, c + dc); + } + }; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === '1') { + dfs(r, c); + islands++; + } + } + } + + return islands; + } +} \ No newline at end of file diff --git a/javascript/graphs/clonegraph.js b/javascript/graphs/clonegraph.js new file mode 100644 index 00000000..23ae2562 --- /dev/null +++ b/javascript/graphs/clonegraph.js @@ -0,0 +1,44 @@ +/** + * // Definition for a Node. + * class Node { + * constructor(val = 0, neighbors = []) { + * this.val = val; + * this.neighbors = neighbors; + * } + * } + */ + +class Solution { + /** + * @param {Node} node + * @return {Node} + */ + cloneGraph(node) { + const oldToNew = new Map(); + return this.dfs(node, oldToNew); + } + + /** + * @param {Node} node + * @param {Map} oldToNew + * @return {Node} + */ + dfs(node, oldToNew) { + if (node === null) { + return null; + } + + if (oldToNew.has(node)) { + return oldToNew.get(node); + } + + const copy = new Node(node.val); + oldToNew.set(node, copy); + + for (const nei of node.neighbors) { + copy.neighbors.push(this.dfs(nei, oldToNew)); + } + + return copy; + } +} \ No newline at end of file diff --git a/javascript/graphs/maxareaofislands.js b/javascript/graphs/maxareaofislands.js new file mode 100644 index 00000000..0df79ce3 --- /dev/null +++ b/javascript/graphs/maxareaofislands.js @@ -0,0 +1,54 @@ +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxAreaOfIsland(grid) { + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const ROWS = grid.length, + COLS = grid[0].length; + let area = 0; + + const bfs = (r, c) => { + const q = new Queue(); + q.push([r, c]); + grid[r][c] = 0; + let res = 1; + + while (!q.isEmpty()) { + const [row, col] = q.pop(); + for (const [dr, dc] of directions) { + const nr = row + dr, + nc = col + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === 1 + ) { + q.push([nr, nc]); + grid[nr][nc] = 0; + res++; + } + } + } + return res; + }; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 1) { + area = Math.max(area, bfs(r, c)); + } + } + } + + return area; + } +} \ No newline at end of file diff --git a/javascript/guess.js b/javascript/guess.js new file mode 100644 index 00000000..f59b5cfe --- /dev/null +++ b/javascript/guess.js @@ -0,0 +1,40 @@ +// Simple Number Guessing Game for Node.js + +const readline = require("readline"); + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, +}); + +const secret = Math.floor(Math.random() * 100) + 1; +let attempts = 0; + +console.log("🎯 Welcome to the Number Guessing Game!"); +console.log("Guess a number between 1 and 100."); + +function ask() { + rl.question("Enter your guess: ", (input) => { + const guess = Number(input); + attempts++; + + if (isNaN(guess)) { + console.log("Please enter a valid number!"); + return ask(); + } + + if (guess > secret) { + console.log("Too high! Try again."); + ask(); + } else if (guess < secret) { + console.log("Too low! Try again."); + ask(); + } else { + console.log(`🎉 Correct! The number was ${secret}.`); + console.log(`You guessed it in ${attempts} tries.`); + rl.close(); + } + }); +} + +ask(); diff --git a/javascript/hellowordl.js b/javascript/helloWorld.js similarity index 72% rename from javascript/hellowordl.js rename to javascript/helloWorld.js index 42e9550d..431d6599 100644 --- a/javascript/hellowordl.js +++ b/javascript/helloWorld.js @@ -1,4 +1,4 @@ console.log("Hello, World!"); let a = 10; let b = 20; -console.log(a+b); \ No newline at end of file +console.log(a + b); diff --git a/javascript/largenoinarray.js b/javascript/largenoinarray.js new file mode 100644 index 00000000..5621b4bd --- /dev/null +++ b/javascript/largenoinarray.js @@ -0,0 +1,3 @@ +let numbers = [12, 45, 3, 67, 23]; +let largest = Math.max(...numbers); +console.log("Largest Number:", largest); diff --git a/javascript/largestNumber.js b/javascript/largestNumber.js new file mode 100644 index 00000000..1db3fd89 --- /dev/null +++ b/javascript/largestNumber.js @@ -0,0 +1,9 @@ +const numbers = [10, 5, 20, 15]; +let largest = numbers[0]; + +for (let i = 1; i < numbers.length; i++) { + if (numbers[i] > largest) { + largest = numbers[i]; + } +} +console.log(largest); diff --git a/javascript/lengthOfLongestSubstring.js b/javascript/lengthOfLongestSubstring.js new file mode 100644 index 00000000..ff45a2c0 --- /dev/null +++ b/javascript/lengthOfLongestSubstring.js @@ -0,0 +1,14 @@ +// Time: O(n), Space: O(n) +var lengthOfLongestSubstring = function (s) { + let set = new Set(), + left = 0, + maxLength = 0; + for (let right = 0; right < s.length; right++) { + while (set.has(s[right])) { + set.delete(s[left++]); + } + set.add(s[right]); + maxLength = Math.max(maxLength, right - left + 1); + } + return maxLength; +}; diff --git a/javascript/longestValidParentheses.js b/javascript/longestValidParentheses.js new file mode 100644 index 00000000..3a6f9932 --- /dev/null +++ b/javascript/longestValidParentheses.js @@ -0,0 +1,44 @@ +/** + * @param {string} s + * @return {number} + */ +var = function(s) { + let ans = 0; + let open = 0; + let close = 0; + let n = s.length; + + // Left to right pass + for (let i = 0; i < n; i++) { + if (s[i] === '(') { + open++; + } else { + close++; + } + + if (open === close) { + ans = Math.max(ans, 2 * close); + } else if (close > open) { + open = close = 0; + } + } + + open = close = 0; + + // Right to left pass + for (let i = n - 1; i >= 0; i--) { + if (s[i] === '(') { + open++; + } else { + close++; + } + + if (open === close) { + ans = Math.max(ans, 2 * open); + } else if (open > close) { + open = close = 0; + } + } + + return ans; +}; diff --git a/javascript/maxProfit.js b/javascript/maxProfit.js new file mode 100644 index 00000000..18988df2 --- /dev/null +++ b/javascript/maxProfit.js @@ -0,0 +1,10 @@ +// Time: O(n), Space: O(1) +var maxProfit = function (prices) { + let minPrice = Infinity; + let maxProfit = 0; + for (let price of prices) { + minPrice = Math.min(minPrice, price); + maxProfit = Math.max(maxProfit, price - minPrice); + } + return maxProfit; +}; diff --git a/javascript/merge-sort-algo.js b/javascript/mergeSortAlgo.js similarity index 100% rename from javascript/merge-sort-algo.js rename to javascript/mergeSortAlgo.js diff --git a/javascript/mergeTwoLists.js b/javascript/mergeTwoLists.js new file mode 100644 index 00000000..08456ddc --- /dev/null +++ b/javascript/mergeTwoLists.js @@ -0,0 +1,17 @@ +// Time: O(m+n), Space: O(1) +var mergeTwoLists = function (list1, list2) { + let dummy = { val: -1, next: null }; + let current = dummy; + while (list1 && list2) { + if (list1.val < list2.val) { + current.next = list1; + list1 = list1.next; + } else { + current.next = list2; + list2 = list2.next; + } + current = current.next; + } + current.next = list1 || list2; + return dummy.next; +}; diff --git a/javascript/nonzero.js b/javascript/nonzero.js new file mode 100644 index 00000000..8d71e135 --- /dev/null +++ b/javascript/nonzero.js @@ -0,0 +1,33 @@ +// this code is to Convert Integer to the Sum of Two No-Zero Integers +const readline = require("readline"); + + function getNoZeroIntegers(n){ + function noZero(x){ + while(x>0){ + if (x % 10===0) return false; + x=Math.floor(x/10); + } + return true; + } + + + for(let a=1;a{ + const n = parseInt(answer); + const result= getNoZeroIntegers(n); + console.log("Results",result); + rl.close(); + }); \ No newline at end of file diff --git a/javascript/1darray.js b/javascript/oneDArray.js similarity index 51% rename from javascript/1darray.js rename to javascript/oneDArray.js index 3a3259e2..f99c4904 100644 --- a/javascript/1darray.js +++ b/javascript/oneDArray.js @@ -6,58 +6,57 @@ console.log("Original Array:", arr); // 1. Traversal function traverseArray(arr) { - console.log("Traversed Array:"); - for (let i = 0; i < arr.length; i++) { - console.log(`Index ${i} => ${arr[i]}`); - } + console.log("Traversed Array:"); + for (let i = 0; i < arr.length; i++) { + console.log(`Index ${i} => ${arr[i]}`); + } } traverseArray(arr); // 2. Insertion at specific position function insertElement(arr, element, position) { - if (position < 0 || position > arr.length) { - console.log("Invalid Position!"); - return arr; - } - arr.splice(position, 0, element); // insert at position + if (position < 0 || position > arr.length) { + console.log("Invalid Position!"); return arr; + } + arr.splice(position, 0, element); // insert at position + return arr; } arr = insertElement(arr, 25, 2); console.log("After Insertion (25 at index 2):", arr); // 3. Deletion from specific position function deleteElement(arr, position) { - if (position < 0 || position >= arr.length) { - console.log("Invalid Position!"); - return arr; - } - arr.splice(position, 1); // remove 1 element at index + if (position < 0 || position >= arr.length) { + console.log("Invalid Position!"); return arr; + } + arr.splice(position, 1); // remove 1 element at index + return arr; } arr = deleteElement(arr, 4); console.log("After Deletion (index 4):", arr); // 4. Searching an element function searchElement(arr, key) { - let index = arr.indexOf(key); - if (index !== -1) { - console.log(`${key} found at index ${index}`); - } else { - console.log(`${key} not found in array`); - } + let index = arr.indexOf(key); + if (index !== -1) { + console.log(`${key} found at index ${index}`); + } else { + console.log(`${key} not found in array`); + } } searchElement(arr, 30); searchElement(arr, 99); // 5. Updating an element function updateElement(arr, position, newValue) { - if (position < 0 || position >= arr.length) { - console.log("Invalid Position!"); - return arr; - } - arr[position] = newValue; + if (position < 0 || position >= arr.length) { + console.log("Invalid Position!"); return arr; + } + arr[position] = newValue; + return arr; } arr = updateElement(arr, 1, 200); console.log("After Updating (index 1 → 200):", arr); - diff --git a/javascript/palindrome.js b/javascript/palindrome.js new file mode 100644 index 00000000..b3f962bb --- /dev/null +++ b/javascript/palindrome.js @@ -0,0 +1,21 @@ +/* + Implement a function in JavaScript that checks whether a given string is a palindrome (reads the same backward and forward). + The function should ignore case sensitivity and non-alphanumeric characters. + + */ + +function isPalindrome(str) { + str = str.toLowerCase().replace(/[^a-z0-9]/g, ""); + let left = 0, right = str.length - 1; + + while (left < right) { + if (str[left] !== str[right]) return false; + left++; + right--; + } + return true; +} + +console.log(isPalindrome("level")); // true +console.log(isPalindrome("world")); // false + diff --git a/javascript/passwordChecker.js b/javascript/passwordChecker.js index eef6a7b1..baa1291e 100644 --- a/javascript/passwordChecker.js +++ b/javascript/passwordChecker.js @@ -8,9 +8,12 @@ function checkPasswordStrength(password) { switch (strength) { case 0: - case 1: return 'Weak'; + case 1: + return "Weak"; case 2: - case 3: return 'Medium'; - case 4: return 'Strong'; + case 3: + return "Medium"; + case 4: + return "Strong"; } -} \ No newline at end of file +} diff --git a/javascript/perfectSquare.js b/javascript/perfectSquare.js new file mode 100644 index 00000000..f2e1b986 --- /dev/null +++ b/javascript/perfectSquare.js @@ -0,0 +1,45 @@ +/* +Question: +Check whether a given number is a perfect square +(using Binary Search instead of Math.sqrt). + +Time Complexity: O(log n) +Space Complexity: O(1) + +Examples: +Input: num = 16 +Output: true +Explanation: 4 * 4 = 16 → perfect square + +Input: num = 14 +Output: false +Explanation: There is no integer x such that x * x = 14 +*/ + +var isPerfectSquare = function (num) { + // Special case: 1 is a perfect square + if (num === 1) return true; + + // Search space: from 2 up to num/2 + let low = 2; + let high = Math.floor(num / 2); + + while (low <= high) { + let mid = Math.floor((low + high) / 2); + let sq = mid * mid; + + if (sq === num) + return true; // found exact square + else if (sq > num) + high = mid - 1; // mid^2 too large → search left + else low = mid + 1; // mid^2 too small → search right + } + + // No perfect square found + return false; +}; + +// Example runs: +console.log(isPerfectSquare(16)); // true (4 * 4 = 16) +console.log(isPerfectSquare(14)); // false (no integer square root) +console.log(isPerfectSquare(1)); // true (1 * 1 = 1) diff --git a/javascript/predecessor.js b/javascript/predecessor.js new file mode 100644 index 00000000..ec8262a7 --- /dev/null +++ b/javascript/predecessor.js @@ -0,0 +1,36 @@ +/* +Question: +Given a sorted array and a target, find the index of the largest element +that is strictly smaller than the target (Predecessor). + +If no such element exists, return -1. + +Example: +Input: arr = [2, 4, 6, 8, 10], target = 7 +Output: 6 +Explanation: 6 is the largest element < 7 +*/ + +function predecessor(arr, target) { + let low = 0; + let high = arr.length - 1; + + while (low <= high) { + let mid = Math.floor((low + high) / 2); + + if (arr[mid] < target) { + // arr[mid] is a valid candidate, but maybe there's a larger one + low = mid + 1; // move right to find a larger candidate + } else { + // arr[mid] >= target → go left + high = mid - 1; + } + } + + return high >= 0 ? high : -1; +} + +// Example runs: +console.log(predecessor([2, 4, 4, 6, 6, 8, 10], 7)); // Output: 4 +console.log(predecessor([2, 4, 6, 8, 10], 1)); // Output: -1 (no smaller element) +console.log(predecessor([2, 4, 6, 8, 10, 10], 10)); // Output: 3 diff --git a/javascript/prime.js b/javascript/prime.js new file mode 100644 index 00000000..4b6c479d --- /dev/null +++ b/javascript/prime.js @@ -0,0 +1,10 @@ +function isPrimeBasic(n) { + if (n <= 1) return false; + for (let i = 2; i < n; i++) { + if (n % i === 0) return false; + } + return true; +} + +// ઉદાહરણ +console.log(isPrimeBasic(17)); // true diff --git a/javascript/productExceptSelf.js b/javascript/productExceptSelf.js new file mode 100644 index 00000000..5115a607 --- /dev/null +++ b/javascript/productExceptSelf.js @@ -0,0 +1,18 @@ +// Time: O(n), Space: O(1) (excluding output array) +var productExceptSelf = function (nums) { + let res = Array(nums.length).fill(1); + let left = 1, + right = 1; + + for (let i = 0; i < nums.length; i++) { + res[i] *= left; + left *= nums[i]; + } + + for (let i = nums.length - 1; i >= 0; i--) { + res[i] *= right; + right *= nums[i]; + } + + return res; +}; diff --git a/javascript/promises.js b/javascript/promises.js new file mode 100644 index 00000000..fa9bfd14 --- /dev/null +++ b/javascript/promises.js @@ -0,0 +1,37 @@ +function divide(dividend,divisor) +{ + var p=new Promise(function(doneNotifier,errorNotifier) +{ + setTimeout(function(){ + if(divisor==0){ + errorNotifier('can not divide by 0'); + } + + else{ + var r={ + quotient:Math.floor(dividend/divisor), + remainder:dividend%divisor + } + doneNotifier(r); + } + },5000); +}); +return p; +} + +var a=10; +var b=0; + +var promise=divide(a,b); + +promise.then(function(result){ + var quotient=result.quotient; + var remainder=result.remainder; + console.log(`after dividing ${a} by ${b} quotient if ${quotient} & remainder is ${remainder}`); +}).catch(function(error){ + console.log(`problem: ${error}`); +}).then(function(){ + console.log("very cool"); +}).then(function(){ + console.log("super cool"); +}); \ No newline at end of file diff --git a/javascript/quickSort.js b/javascript/quickSort.js new file mode 100644 index 00000000..6583ba84 --- /dev/null +++ b/javascript/quickSort.js @@ -0,0 +1,28 @@ +function quickSort(arr, low = 0, high = arr.length - 1) { + if (low < high) { + const pivotIndex = partition(arr, low, high); + quickSort(arr, low, pivotIndex - 1); + quickSort(arr, pivotIndex + 1, high); + } + return arr; +} + +function partition(arr, low, high) { + const pivot = arr[high]; + let i = low - 1; + + for (let j = low; j < high; j++) { + if (arr[j] < pivot) { + i++; + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + } + + [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; + return i + 1; +} + +const arr = [64, 34, 25, 12, 22, 11, 90]; +console.log("Original:", arr); +quickSort(arr); +console.log("Sorted:", arr); diff --git a/javascript/reverseString.js b/javascript/reverseString.js new file mode 100644 index 00000000..fd51045a --- /dev/null +++ b/javascript/reverseString.js @@ -0,0 +1,17 @@ +// Filename: reverseString.js + +// Function to reverse a string +function reverseString(str) { + // Step 1: Convert string into an array + // Step 2: Reverse the array + // Step 3: Join the array back into a string + return str.split('').reverse().join(''); + } + + // Test the function + const input = "hello"; + const result = reverseString(input); + + console.log("Input:", input); + console.log("Reversed:", result); + \ No newline at end of file diff --git a/javascript/reverse_string.js b/javascript/reverse_string.js new file mode 100644 index 00000000..56626076 --- /dev/null +++ b/javascript/reverse_string.js @@ -0,0 +1,3 @@ +let str = "hello"; +let reversed = str.split("").reverse().join(""); +console.log("Reversed:", reversed); diff --git a/javascript/rhombusPattern.js b/javascript/rhombusPattern.js new file mode 100644 index 00000000..aea5bafc --- /dev/null +++ b/javascript/rhombusPattern.js @@ -0,0 +1,32 @@ +/* +Question: Print a solid rhombus pattern of stars. + +Example: +Input: n = 5 +Output: + * * * * * + * * * * * + * * * * * + * * * * * +* * * * * +*/ + +function printRhombus(n) { + for (let i = 1; i <= n; i++) { + let row = ""; + + // spaces + for (let j = 1; j <= n - i; j++) { + row += " "; // double spaces for alignment + } + + // stars + for (let j = 1; j <= n; j++) { + row += "* "; + } + + console.log(row); // print row + } +} + +printRhombus(5); diff --git a/javascript/singleNumber.js b/javascript/singleNumber.js new file mode 100644 index 00000000..2892b7d5 --- /dev/null +++ b/javascript/singleNumber.js @@ -0,0 +1,15 @@ +/* Question: Every element appears twice except for one unique element that appears only once. + Example - + Input: nums = [4,1,2,1,2] + Output: 4 +*/ + +var singleNumber = function (nums) { + let unique = nums[0]; // start with the first element + for (let i = 1; i < nums.length; i++) { + unique = unique ^ nums[i]; // XOR with every other element + } + return unique; // the unique number +}; + +console.log(singleNumber([4, 1, 2, 4, 1, 2, 3])); // Output: 3 diff --git a/javascript/smallestNumber.js b/javascript/smallestNumber.js new file mode 100644 index 00000000..0dffa3bc --- /dev/null +++ b/javascript/smallestNumber.js @@ -0,0 +1,9 @@ +let numbers = [20, 90, 10, 324, 9, 73]; +let smallest = numbers[0]; + +for (let i = 1; i < numbers.length; i++) { + if (numbers[i] < smallest) { + smallest = numbers[i]; + } +} +console.log(smallest); diff --git a/javascript/spiral_matrix.js b/javascript/spiral_matrix.js new file mode 100644 index 00000000..26073408 --- /dev/null +++ b/javascript/spiral_matrix.js @@ -0,0 +1,98 @@ +let mtrx = [[1, 2, 3, 4], +[4, 5, 6, 7], +[7, 8, 9, 10], +[10, 11, 12, 13]]; + +class Matrix { + #mat = []; + constructor(matrix = []) { + this.#mat = matrix; + } + + showMatrix() { + console.log(this.#mat); + } + + + + addRow(row = []) { + this.#mat.push(row); + this.#padRows(); + } + + #padRows() { + let max_row_length = 0; + + for (let i = 0; i < this.#mat.length; i++) { + if (this.#mat[i].length > max_row_length) { + max_row_length = this.#mat[i].length + } + } + + for (let i = 0; i < this.#mat.length; i++) { + while (this.#mat[i].length < max_row_length) { + this.#mat[i].push(0); + } + } + + return max_row_length; + } + + getMatrix() { + return this.#mat; + } + + spiralTraversal(show_traversal=false) { + let res = []; + let mtrx = this.#mat; + + let top = 0; + let bottom = mtrx.length; + let left = 0; + let right = mtrx[0].length; + + while (top < bottom && left < right) { + for (let i = left; i < right; i++) { + res.push(mtrx[top][i]); + } + top += 1; + + for (let i = top; i < bottom; i++) { + res.push(mtrx[i][right - 1]); + } + right -= 1; + + if (top < bottom) { + + for (let i = right - 1; i >= left; i--) { + res.push(mtrx[bottom - 1][i]); + } + bottom -= 1; + + } + + if (left < right) { + for (let i = bottom - 1; i >= top; i--) { + res.push(mtrx[i][left]); + } + left += 1; + } + } + + if(show_traversal){ + //Gotta make it more beautiful with actual spiral + console.log(res.join(" -> ")); + } + + return res; + } +} + +let m = new Matrix(); + +m.addRow([0, 0, 0, 0, 0, 0,]) +m.addRow([1, 2, 3, 4, 5]) +m.addRow([1, 2, 3, 4]) +m.addRow([1, 2, 3, 4]) + +console.log(m.spiralTraversal(true)) \ No newline at end of file diff --git a/javascript/sum.js b/javascript/sum.js index 78a97854..644e653e 100644 --- a/javascript/sum.js +++ b/javascript/sum.js @@ -1,61 +1,61 @@ // Definition for singly-linked list node class ListNode { - constructor(val, next = null) { - this.val = val; - this.next = next; - } + constructor(val, next = null) { + this.val = val; + this.next = next; + } } // Function to add two numbers represented by linked lists function addTwoNumbers(l1, l2) { - let dummy = new ListNode(0); - let current = dummy; - let carry = 0; - - while (l1 !== null || l2 !== null || carry > 0) { - let sum = carry; - - if (l1 !== null) { - sum += l1.val; - l1 = l1.next; - } - if (l2 !== null) { - sum += l2.val; - l2 = l2.next; - } - - carry = Math.floor(sum / 10); - current.next = new ListNode(sum % 10); - current = current.next; + let dummy = new ListNode(0); + let current = dummy; + let carry = 0; + + while (l1 !== null || l2 !== null || carry > 0) { + let sum = carry; + + if (l1 !== null) { + sum += l1.val; + l1 = l1.next; + } + if (l2 !== null) { + sum += l2.val; + l2 = l2.next; } - return dummy.next; + carry = Math.floor(sum / 10); + current.next = new ListNode(sum % 10); + current = current.next; + } + + return dummy.next; } // Utility function to create a linked list from an array function createLinkedList(arr) { - let dummy = new ListNode(0); - let current = dummy; - for (let num of arr) { - current.next = new ListNode(num); - current = current.next; - } - return dummy.next; + let dummy = new ListNode(0); + let current = dummy; + for (let num of arr) { + current.next = new ListNode(num); + current = current.next; + } + return dummy.next; } // Utility function to print linked list function printLinkedList(head) { - let result = []; - while (head) { - result.push(head.val); - head = head.next; - } - console.log(result.join(" -> ")); + let result = []; + while (head) { + result.push(head.val); + head = head.next; + } + console.log(result.join(" -> ")); } // Example Usage: let l1 = createLinkedList([2, 4, 3]); // represents number 342 let l2 = createLinkedList([5, 6, 4]); // represents number 465 -let sumList = addTwoNumbers(l1, l2); +let sumList = addTwoNumbers(l1, l2); printLinkedList(sumList); // Output: 7 -> 0 -> 8 (807) diff --git a/javascript/topKFrequent.js b/javascript/topKFrequent.js new file mode 100644 index 00000000..7c85ed67 --- /dev/null +++ b/javascript/topKFrequent.js @@ -0,0 +1,8 @@ +// Time: O(n log k), Space: O(n) +var topKFrequent = function (nums, k) { + const freqMap = new Map(); + nums.forEach((num) => freqMap.set(num, (freqMap.get(num) || 0) + 1)); + + const heap = [...freqMap.entries()].sort((a, b) => b[1] - a[1]); + return heap.slice(0, k).map((entry) => entry[0]); +}; diff --git a/javascript/upperLeftTriangle.js b/javascript/upperLeftTriangle.js new file mode 100644 index 00000000..d31e8885 --- /dev/null +++ b/javascript/upperLeftTriangle.js @@ -0,0 +1,5 @@ +let n = 5; +for (let i = 1; i <= n; i++) { + let str = "* "; + console.log(str.repeat(i)); +} diff --git a/javascript/upperRightTriangle.js b/javascript/upperRightTriangle.js new file mode 100644 index 00000000..c8ebbf88 --- /dev/null +++ b/javascript/upperRightTriangle.js @@ -0,0 +1,6 @@ +let n = 5; +for (let i = 1; i <= n; i++) { + let str = "* "; + let space = " "; + console.log(space.repeat(n - i) + str.repeat(i)); +} diff --git a/javascript/warshallsAlgo.js b/javascript/warshallsAlgo.js new file mode 100644 index 00000000..5fea1c9a --- /dev/null +++ b/javascript/warshallsAlgo.js @@ -0,0 +1,24 @@ +function warshall(graph) { + const n = graph.length; + const reach = Array.from({ length: n }, (_, i) => [...graph[i]]); + + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]); + } + } + } + + return reach; +} + +const graph = [ + [1, 1, 0, 0], + [0, 1, 1, 0], + [0, 0, 1, 1], + [0, 0, 0, 1], +]; + +const closure = warshall(graph); +console.log(closure); diff --git a/javascript/zigzagpattern.js b/javascript/zigzagpattern.js index c8def3f4..838d914a 100644 --- a/javascript/zigzagpattern.js +++ b/javascript/zigzagpattern.js @@ -1,24 +1,24 @@ // write string "PAYPALISHIRING" in a zigzag pattern -var convert = function(s, numRows) { - if (numRows == 1) return s; - let arr = new Array(numRows); - for (let i = 0; i < numRows; i++) arr[i] = []; - let mi = 0, - isDown = true; - for (const c of s) { - arr[mi].push(c); +var convert = function (s, numRows) { + if (numRows == 1) return s; + let arr = new Array(numRows); + for (let i = 0; i < numRows; i++) arr[i] = []; + let mi = 0, + isDown = true; + for (const c of s) { + arr[mi].push(c); - if (mi >= numRows - 1) isDown = false; - else if (mi <= 0) isDown = true; + if (mi >= numRows - 1) isDown = false; + else if (mi <= 0) isDown = true; - if (isDown) mi++; - else mi--; - } - let ans = []; - for (let item of arr) { - ans = ans.concat(item); - } - return ans.join(''); + if (isDown) mi++; + else mi--; + } + let ans = []; + for (let item of arr) { + ans = ans.concat(item); + } + return ans.join(""); }; -console.log(convert("PAYPALISHIRING", 3)); // "PAHNAPLSIIGYIR" \ No newline at end of file +console.log(convert("PAYPALISHIRING", 3)); // "PAHNAPLSIIGYIR" diff --git a/jspwTest.cpp b/jspwTest.cpp new file mode 100644 index 00000000..a087fe1e --- /dev/null +++ b/jspwTest.cpp @@ -0,0 +1,11 @@ +#include +using namespace std; + +int main() { + //with two same dataTypes + + pair p1 = {1,3}; + + cout< arr[j + 1]) { + // Swap arr[j] and arr[j+1] + val temp = arr[j] + arr[j] = arr[j + 1] + arr[j + 1] = temp + swapped = true + } + } + // If no two elements were swapped by the inner loop, the array is already sorted. + if (!swapped) { + break + } + } +} + +/** + * The main function to demonstrate the bubble sort functionality interactively. + */ +fun main() { + val scanner = Scanner(System.`in`) + + println("--- Interactive Bubble Sort in Kotlin ---") + print("Enter the number of elements in the array: ") + val n = scanner.nextInt() + + if (n <= 0) { + println("Array size must be positive. Exiting.") + return + } + + val arr = IntArray(n) + println("Enter the elements of the array:") + for (i in 0 until n) { + print("Element ${i + 1}: ") + arr[i] = scanner.nextInt() + } + + println("\nOriginal array: ${arr.joinToString(separator = ", ", prefix = "[", postfix = "]")}") + + bubbleSort(arr) + + println("Sorted array: ${arr.joinToString(separator = ", ", prefix = "[", postfix = "]")}") + + scanner.close() +} diff --git a/kotlin/Graph_BFS_DFS.kt b/kotlin/Graph_BFS_DFS.kt new file mode 100644 index 00000000..2ff4c4ed --- /dev/null +++ b/kotlin/Graph_BFS_DFS.kt @@ -0,0 +1,39 @@ +import java.util.Scanner +import java.util.ArrayDeque + +class Graph(private val n: Int) { + private val g = Array(n) { mutableListOf() } + fun add(u: Int, v: Int) { g[u].add(v); g[v].add(u) } + + fun bfs(s: Int): List { + val vis = BooleanArray(n) + val q: ArrayDeque = ArrayDeque() + val ord = mutableListOf() + vis[s] = true; q.add(s) + while (q.isNotEmpty()) { + val u = q.removeFirst(); ord += u + for (v in g[u]) if (!vis[v]) { vis[v] = true; q.add(v) } + } + return ord + } + fun dfs(s: Int): List { + val vis = BooleanArray(n); val ord = mutableListOf() + fun go(u: Int) { + vis[u] = true; ord += u + for (v in g[u]) if (!vis[v]) go(v) + } + go(s); return ord + } +} + +fun main() { + val sc = Scanner(System.`in`) + // input: n m, then m edges (0-indexed u v), then start + val n = sc.nextInt() + val m = sc.nextInt() + val gr = Graph(n) + repeat(m) { gr.add(sc.nextInt(), sc.nextInt()) } + val start = sc.nextInt() + println("BFS: " + gr.bfs(start).joinToString(" ")) + println("DFS: " + gr.dfs(start).joinToString(" ")) +} diff --git a/kotlin/HelloConfetti.kt b/kotlin/HelloConfetti.kt new file mode 100644 index 00000000..522fa6a5 --- /dev/null +++ b/kotlin/HelloConfetti.kt @@ -0,0 +1,72 @@ +import kotlin.math.* +import kotlin.random.Random + +fun main() { + val hello = "Hello, Kotlin!" + typewrite("Launching...", 18) + progressBar("Boot", 28) + println() + fancyTitle(hello) + confetti(24) + println() + typewrite("Have a great day 🌈", 20) +} + +fun typewrite(text: String, delayMs: Long) { + for (ch in text) { + print(ch) + System.out.flush() + Thread.sleep(delayMs) + } + println() +} + +fun progressBar(label: String, totalSteps: Int) { + for (i in 0..totalSteps) { + val width = 24 + val filled = ((i / totalSteps.toDouble()) * width).roundToInt().coerceIn(0, width) + val bar = "█".repeat(filled) + " ".repeat(width - filled) + val pct = (i * 100) / totalSteps + print("\r$label [$bar] $pct%") + System.out.flush() + Thread.sleep(70) + } +} + +fun fancyTitle(text: String) { + val colors = listOf(196, 202, 208, 214, 220, 190, 154, 118, 82, 46, 47, 48, 49, 50, 51, 45, 39, 33, 27, 21, 57, 93, 129, 165, 201) + val pad = 2 + val border = "═".repeat(text.length + pad * 2) + println("╔$border╗") + print("║") + repeat(pad) { print(" ") } + val step = max(1, colors.size / max(1, text.length)) + for ((idx, ch) in text.withIndex()) { + val color = colors[min(idx * step, colors.size - 1)] + print("\u001B[38;5;${color}m$ch\u001B[0m") + } + repeat(pad) { print(" ") } + println("║") + println("╚$border╝") +} + +fun confetti(lines: Int) { + val symbols = listOf("✨","★","✦","✧","❖","❉","❋","❇","⋆","✺","❀","✿","❁","✾","❂","☼","•","◦","∙","●","○","◆","◇","■","□","▲","△","❣","❤","🎉","🎊","🎈") + val r = Random(System.currentTimeMillis()) + val width = 48 + repeat(lines) { + val count = r.nextInt(10, 18) + val positions = (0 until count).map { r.nextInt(0, width) }.sorted() + val row = CharArray(width) { ' ' } + for (pos in positions) { + val s = symbols[r.nextInt(symbols.size)] + val fragment = s + val bytes = fragment.toByteArray().size + if (pos < width) { + print("\u001B[38;5;${r.nextInt(16, 231)}m$fragment\u001B[0m") + } + } + println() + Thread.sleep(40) + } +} diff --git a/kotlin/IntroSort.kt b/kotlin/IntroSort.kt new file mode 100644 index 00000000..0f4cd34f --- /dev/null +++ b/kotlin/IntroSort.kt @@ -0,0 +1,173 @@ +import java.util.Scanner +import kotlin.math.floor +import kotlin.math.log2 + +/** + * Main entry point for the Introsort algorithm. + * It calculates the depth limit and calls the recursive sorter. + * + * @param arr The array to be sorted. + */ +fun introsort(arr: IntArray) { + if (arr.isEmpty()) return + val depthLimit = (2 * floor(log2(arr.size.toDouble()))).toInt() + introsortRecursive(arr, 0, arr.size - 1, depthLimit) +} + +/** + * The core recursive function for Introsort. + * It switches to Heap Sort if recursion depth is exceeded, + * and to Insertion Sort for small partitions. + * + * @param arr The array to sort. + * @param begin The starting index of the partition. + * @param end The ending index of the partition. + * @param depthLimit The maximum recursion depth. + */ +private fun introsortRecursive(arr: IntArray, begin: Int, end: Int, depthLimit: Int) { + if (end - begin <= 16) { + insertionSort(arr, begin, end) + return + } + + if (depthLimit == 0) { + heapSort(arr, begin, end) + return + } + + val pivotIndex = partition(arr, begin, end) + introsortRecursive(arr, begin, pivotIndex - 1, depthLimit - 1) + introsortRecursive(arr, pivotIndex + 1, end, depthLimit - 1) +} + +/** + * Partitions the array for Quick Sort. + * Uses the last element as the pivot. + * + * @param arr The array to partition. + * @param low The starting index. + * @param high The ending index. + * @return The index of the pivot after partitioning. + */ +private fun partition(arr: IntArray, low: Int, high: Int): Int { + val pivot = arr[high] + var i = low - 1 + for (j in low until high) { + if (arr[j] <= pivot) { + i++ + arr.swap(i, j) + } + } + arr.swap(i + 1, high) + return i + 1 +} + +/** + * Sorts a small partition of the array using Insertion Sort. + * + * @param arr The array containing the partition. + * @param left The starting index of the partition. + * @param right The ending index of the partition. + */ +private fun insertionSort(arr: IntArray, left: Int, right: Int) { + for (i in left + 1..right) { + val key = arr[i] + var j = i - 1 + while (j >= left && arr[j] > key) { + arr[j + 1] = arr[j] + j-- + } + arr[j + 1] = key + } +} + +/** + * Sorts a partition of the array using Heap Sort. + * + * @param arr The array containing the partition. + * @param begin The starting index of the partition. + * @param end The ending index of the partition. + */ +private fun heapSort(arr: IntArray, begin: Int, end: Int) { + val n = end - begin + 1 + // Build heap (rearrange array) + for (i in n / 2 - 1 downTo 0) { + heapify(arr, n, i, begin) + } + + // One by one extract an element from heap + for (i in n - 1 downTo 0) { + // Move current root to end + arr.swap(begin, begin + i) + // call max heapify on the reduced heap + heapify(arr, i, 0, begin) + } +} + +/** + * Helper function to heapify a subtree rooted with node i which is an index in arr[]. + * + * @param arr The array. + * @param n The size of the heap. + * @param i The root of the subtree. + * @param offset The offset for the start of the array partition. + */ +private fun heapify(arr: IntArray, n: Int, i: Int, offset: Int) { + var largest = i + val left = 2 * i + 1 + val right = 2 * i + 2 + + if (left < n && arr[offset + left] > arr[offset + largest]) { + largest = left + } + + if (right < n && arr[offset + right] > arr[offset + largest]) { + largest = right + } + + if (largest != i) { + arr.swap(offset + i, offset + largest) + heapify(arr, n, largest, offset) + } +} + +/** + * Swaps two elements in an IntArray. + */ +private fun IntArray.swap(i: Int, j: Int) { + val temp = this[i] + this[i] = this[j] + this[j] = temp +} + + +/** + * The main function to demonstrate the introsort functionality interactively. + */ +fun main() { + val scanner = Scanner(System.`in`) + + println("--- Interactive Introsort in Kotlin ---") + print("Enter the number of elements in the array: ") + val n = scanner.nextInt() + + if (n <= 0) { + println("Array size must be positive. Exiting.") + return + } + + val arr = IntArray(n) + println("Enter the elements of the array:") + for (i in 0 until n) { + print("Element ${i + 1}: ") + arr[i] = scanner.nextInt() + } + + println("\nOriginal array: ${arr.joinToString(separator = ", ", prefix = "[", postfix = "]")}") + + introsort(arr) + + println("Sorted array: ${arr.joinToString(separator = ", ", prefix = "[", postfix = "]")}") + + scanner.close() +} diff --git a/kotlin/QuickSort.kt b/kotlin/QuickSort.kt new file mode 100644 index 00000000..bead1756 --- /dev/null +++ b/kotlin/QuickSort.kt @@ -0,0 +1,24 @@ +import java.util.Scanner + +fun quickSort(a: IntArray, l: Int = 0, r: Int = a.lastIndex) { + if (l >= r) return + var i = l + var j = r + val pivot = a[(l + r) ushr 1] + while (i <= j) { + while (a[i] < pivot) i++ + while (a[j] > pivot) j-- + if (i <= j) { val t = a[i]; a[i] = a[j]; a[j] = t; i++; j-- } + } + quickSort(a, l, j) + quickSort(a, i, r) +} + +fun main() { + val sc = Scanner(System.`in`) + // input: n then n integers + val n = sc.nextInt() + val arr = IntArray(n) { sc.nextInt() } + quickSort(arr) + println(arr.joinToString(" ")) +} diff --git a/kotlin/binary_search.kt b/kotlin/binary_search.kt new file mode 100644 index 00000000..c1b29f26 --- /dev/null +++ b/kotlin/binary_search.kt @@ -0,0 +1,37 @@ +fun binarySearch(arr: IntArray, target: Int): Int { + var left = 0 + var right = arr.size - 1 + + while (left <= right) { + val mid = left + (right - left) / 2 + + when { + arr[mid] == target -> return mid // Element found + arr[mid] < target -> left = mid + 1 // Search right half + else -> right = mid - 1 // Search left half + } + } + + return -1 // Element not found +} + +fun main() { + print("Enter number of elements: ") + val n = readln().toInt() + + val arr = IntArray(n) + println("Enter elements in sorted order:") + for (i in 0 until n) { + arr[i] = readln().toInt() + } + + print("Enter element to search: ") + val target = readln().toInt() + + val result = binarySearch(arr, target) + + if (result != -1) + println("Element found at index $result") + else + println("Element not found in array") +} diff --git a/kotlin/counting_sort.kt b/kotlin/counting_sort.kt new file mode 100644 index 00000000..f8425c24 --- /dev/null +++ b/kotlin/counting_sort.kt @@ -0,0 +1,39 @@ +fun countingSort(arr: IntArray): IntArray { + if (arr.isEmpty()) return arr + + // Step 1: Find the maximum element to determine range + val max = arr.maxOrNull() ?: return arr + + // Step 2: Create a count array + val count = IntArray(max + 1) + + // Step 3: Count the occurrences of each number + for (num in arr) { + count[num]++ + } + + // Step 4: Reconstruct the sorted array + var index = 0 + for (i in count.indices) { + repeat(count[i]) { + arr[index++] = i + } + } + + return arr +} + +fun main() { + print("Enter number of elements: ") + val n = readln().toInt() + + val arr = IntArray(n) + println("Enter elements:") + for (i in 0 until n) { + arr[i] = readln().toInt() + } + + println("Original array: ${arr.joinToString(" ")}") + val sorted = countingSort(arr) + println("Sorted array: ${sorted.joinToString(" ")}") +} diff --git a/kotlin/ddays.kt b/kotlin/ddays.kt new file mode 100644 index 00000000..a1f94478 --- /dev/null +++ b/kotlin/ddays.kt @@ -0,0 +1,37 @@ +impl Solution { + fn can_ship_within_days(weights: &Vec, capacity: i32, days: i32) -> bool { + let mut current_weight = 0; + let mut days_needed = 1; + + for &weight in weights.iter() { + if current_weight + weight > capacity { + days_needed += 1; + current_weight = weight; + if days_needed > days { + return false; + } + } else { + current_weight += weight; + } + } + true + } + + pub fn ship_within_days(weights: Vec, days: i32) -> i32 { + let mut left = *weights.iter().max().unwrap(); + let mut right: i32 = weights.iter().sum(); + + while left < right { + let mid = left + (right - left) / 2; + if Solution::can_ship_within_days(&weights, mid, days) { + right = mid; + } else { + left = mid + 1; + } + } + + left + } +} + +struct Solution; diff --git a/kotlin/linked_list.kt b/kotlin/linked_list.kt new file mode 100644 index 00000000..2614cd7d --- /dev/null +++ b/kotlin/linked_list.kt @@ -0,0 +1,63 @@ +/** + * Represents a single node in the Linked List. + */ +data class Node( + var data: T, + var next: Node? = null // Reference to the next node +) + +/** + * Basic singly Linked List implementation. + */ +class LinkedList { + private var head: Node? = null + + /** + * Adds an element to the front of the list (Prepend). + */ + fun addFirst(data: T) { + val newNode = Node(data, head) + head = newNode + } + + /** + * Adds an element to the end of the list (Append). + */ + fun addLast(data: T) { + val newNode = Node(data) + if (head == null) { + head = newNode + return + } + var current = head + while (current?.next != null) { + current = current.next + } + current?.next = newNode + } + + /** + * Prints all elements in the list. + */ + fun printList() { + var current = head + print("List: ") + while (current != null) { + print("${current.data} -> ") + current = current.next + } + println("null") + } +} + +// --- Usage Example --- +fun runLinkedListExample() { + println("\n--- Linked List ---") + val list = LinkedList() + list.addFirst(10) + list.addFirst(5) + list.addLast(20) + list.addLast(30) + list.printList() // Output: List: 5 -> 10 -> 20 -> 30 -> null +} +// runLinkedListExample() \ No newline at end of file diff --git a/kotlin/selection_sort.kt b/kotlin/selection_sort.kt new file mode 100644 index 00000000..4fd26134 --- /dev/null +++ b/kotlin/selection_sort.kt @@ -0,0 +1,31 @@ +fun selectionSort(arr: IntArray) { + val n = arr.size + for (i in 0 until n - 1) { + // Find the minimum element in unsorted array + var minIndex = i + for (j in i + 1 until n) { + if (arr[j] < arr[minIndex]) { + minIndex = j + } + } + // Swap the found minimum element with the first element + val temp = arr[i] + arr[i] = arr[minIndex] + arr[minIndex] = temp + } +} + +fun main() { + print("Enter number of elements: ") + val n = readln().toInt() + + val arr = IntArray(n) + println("Enter elements:") + for (i in 0 until n) { + arr[i] = readln().toInt() + } + + println("Original array: ${arr.joinToString(" ")}") + selectionSort(arr) + println("Sorted array: ${arr.joinToString(" ")}") +} diff --git a/leetcode_778.cpp b/leetcode_778.cpp new file mode 100644 index 00000000..8c840b7a --- /dev/null +++ b/leetcode_778.cpp @@ -0,0 +1,86 @@ +#include +#include +#include +#include +#include + +using namespace std; + +/** + * Solution for LeetCode 778: Swim in Rising Water. + * * This problem asks for the minimum 'time' t such that a path exists from (0, 0) + * to (N-1, N-1), where all cells on the path have an elevation <= t. + * This is equivalent to finding the path with the minimum bottleneck capacity, + * which is solved efficiently using Dijkstra's algorithm. + */ +class Solution { +public: + int swimInWater(vector>& grid) { + if (grid.empty()) return 0; + + int N = grid.size(); + + // Priority Queue for Dijkstra's Algorithm: + // Stores {max_elevation_so_far, row, col}. + // We use std::greater to create a Min-Heap. The priority queue always + // retrieves the unvisited cell that has the smallest current required max elevation (time). + priority_queue< + tuple, + vector>, + greater> + > pq; + + // dist[r][c] stores the minimum time (max elevation) required to reach cell (r, c). + vector> dist(N, vector(N, INT_MAX)); + + // Start at (0, 0). The required time to be at (0, 0) is at least its elevation. + dist[0][0] = grid[0][0]; + pq.push({grid[0][0], 0, 0}); + + // Directions for movement: Right, Left, Down, Up + int dr[] = {0, 0, 1, -1}; + int dc[] = {1, -1, 0, 0}; + + while (!pq.empty()) { + // Get the cell with the smallest required maximum elevation so far. + auto [time, r, c] = pq.top(); + pq.pop(); + + // Optimization: If a path with a lower or equal time has already + // been processed, skip this one. + if (time > dist[r][c]) { + continue; + } + + // Target check: If we reached the end, return the time. + if (r == N - 1 && c == N - 1) { + return time; + } + + // Explore neighbors + for (int i = 0; i < 4; ++i) { + int nr = r + dr[i]; + int nc = c + dc[i]; + + // Check boundary conditions + if (nr >= 0 && nr < N && nc >= 0 && nc < N) { + + // The time required to enter the new cell (nr, nc) is the + // maximum of the current path's required time (time) and the + // elevation of the destination cell (grid[nr][nc]). + int new_time = max(time, grid[nr][nc]); + + // Relaxation step: If we found a path with a better (smaller) + // maximum elevation, update the distance and push it to the queue. + if (new_time < dist[nr][nc]) { + dist[nr][nc] = new_time; + pq.push({new_time, nr, nc}); + } + } + } + } + + // The problem guarantees a path exists, so this return should ideally not be reached. + return dist[N - 1][N - 1]; + } +}; diff --git a/out/production/DSA-Project/Main.class b/out/production/DSA-Project/Main.class new file mode 100644 index 00000000..9f5efe80 Binary files /dev/null and b/out/production/DSA-Project/Main.class differ diff --git a/out/production/DSA-Project/Task.class b/out/production/DSA-Project/Task.class new file mode 100644 index 00000000..5276bb4b Binary files /dev/null and b/out/production/DSA-Project/Task.class differ diff --git a/out/production/DSA-Project/TodoList.class b/out/production/DSA-Project/TodoList.class new file mode 100644 index 00000000..5b3ab9dd Binary files /dev/null and b/out/production/DSA-Project/TodoList.class differ diff --git a/pandas/Average Salary of Each Department.py b/pandas/Average Salary of Each Department.py new file mode 100644 index 00000000..ac282d5d --- /dev/null +++ b/pandas/Average Salary of Each Department.py @@ -0,0 +1,14 @@ +Employee = pd.DataFrame({ + 'id': [1, 2, 3, 4], + 'name': ['Alice', 'Bob', 'Charlie', 'David'], + 'salary': [5000, 7000, 6000, 8000], + 'departmentId': [1, 1, 2, 2] +}) +Department = pd.DataFrame({ + 'id': [1, 2], + 'name': ['HR', 'Engineering'] +}) + +merged = Employee.merge(Department, left_on='departmentId', right_on='id') +result = merged.groupby('name_y', as_index=False)['salary'].mean().rename(columns={'name_y': 'department'}) +print(result) diff --git a/pandas/Customers Who Never Ordered.py b/pandas/Customers Who Never Ordered.py new file mode 100644 index 00000000..89152990 --- /dev/null +++ b/pandas/Customers Who Never Ordered.py @@ -0,0 +1,12 @@ +Customers = pd.DataFrame({ + 'id': [1, 2, 3], + 'name': ['Alice', 'Bob', 'Charlie'] +}) +Orders = pd.DataFrame({ + 'id': [1, 2], + 'customerId': [1, 2] +}) + +merged = Customers.merge(Orders, left_on='id', right_on='customerId', how='left') +result = merged[merged['customerId'].isna()][['name']] +print(result) diff --git a/pandas/Department Highest Salary.py b/pandas/Department Highest Salary.py new file mode 100644 index 00000000..56c1b8c2 --- /dev/null +++ b/pandas/Department Highest Salary.py @@ -0,0 +1,16 @@ +Employee = pd.DataFrame({ + 'id': [1, 2, 3, 4], + 'name': ['Alice', 'Bob', 'Charlie', 'David'], + 'salary': [5000, 7000, 6000, 7000], + 'departmentId': [1, 1, 2, 2] +}) + +Department = pd.DataFrame({ + 'id': [1, 2], + 'name': ['HR', 'Engineering'] +}) + +merged = Employee.merge(Department, left_on='departmentId', right_on='id', suffixes=('', '_dept')) +max_salary = merged.groupby('departmentId')['salary'].transform('max') +result = merged[merged['salary'] == max_salary][['name_dept', 'name', 'salary']] +print(result) diff --git a/pandas/Employees Earning More Than Their Managers.py b/pandas/Employees Earning More Than Their Managers.py new file mode 100644 index 00000000..fcc173cb --- /dev/null +++ b/pandas/Employees Earning More Than Their Managers.py @@ -0,0 +1,13 @@ +import pandas as pd + +data = { + 'id': [1, 2, 3, 4], + 'name': ['Alice', 'Bob', 'Charlie', 'David'], + 'salary': [5000, 7000, 6000, 8000], + 'managerId': [None, 1, 1, 2] +} +Employee = pd.DataFrame(data) + +df = Employee.merge(Employee, left_on='managerId', right_on='id', suffixes=('', '_manager')) +result = df[df['salary'] > df['salary_manager']][['name']] +print(result) diff --git a/pandas/Second Highest Salary.py b/pandas/Second Highest Salary.py new file mode 100644 index 00000000..037febac --- /dev/null +++ b/pandas/Second Highest Salary.py @@ -0,0 +1,6 @@ +Employee = pd.DataFrame({ + 'id': [1, 2, 3], + 'salary': [100, 200, 300] +}) +second_highest = Employee['salary'].drop_duplicates().nlargest(2).min() +print(second_highest) diff --git a/php/LinearSearch.php b/php/LinearSearch.php new file mode 100644 index 00000000..3bd99197 --- /dev/null +++ b/php/LinearSearch.php @@ -0,0 +1,28 @@ + $value) { + if ($value == $target) { + return $index; // found + } + } + return -1; // not found +} + +// Example array +$arr = [12, 34, 54, 2, 3]; + +// Element to search +$target = 54; + +// Perform search +$result = linearSearch($arr, $target); + +// Display results in a user-friendly way +echo "Searching for $target in the array: [" . implode(", ", $arr) . "]\n\n"; + +if ($result != -1) { + echo "✅ Found $target at position " . ($result + 1) . " (index $result)"; +} else { + echo "❌ Sorry, $target was not found in the array."; +} +?> diff --git a/php/WordSearch.php b/php/WordSearch.php new file mode 100644 index 00000000..f1fbd1da --- /dev/null +++ b/php/WordSearch.php @@ -0,0 +1,63 @@ += $rows || $j < 0 || $j >= $cols) { + return false; + } + + if ($board[$i][$j] !== $word[$index] || $visited[$i][$j]) { + return false; + } + + $visited[$i][$j] = true; + + $found = ( + dfs($board, $word, $i + 1, $j, $index + 1, $visited, $rows, $cols) || + dfs($board, $word, $i - 1, $j, $index + 1, $visited, $rows, $cols) || + dfs($board, $word, $i, $j + 1, $index + 1, $visited, $rows, $cols) || + dfs($board, $word, $i, $j - 1, $index + 1, $visited, $rows, $cols) + ); + + $visited[$i][$j] = false; + return $found; +} + +// Run the function and print result +if (exist($board, $word)) { + echo "Word '$word' exists in the board.\n"; +} else { + echo "Word '$word' does NOT exist in the board.\n"; +} diff --git a/php/bellman_ford.php b/php/bellman_ford.php new file mode 100644 index 00000000..867cd555 --- /dev/null +++ b/php/bellman_ford.php @@ -0,0 +1,53 @@ + $d) { + $dStr = ($d == INF) ? "∞" : $d; + echo "$i\t$dStr\n"; + } +} diff --git a/php/even.php b/php/even.php new file mode 100644 index 00000000..8a78d32a --- /dev/null +++ b/php/even.php @@ -0,0 +1,24 @@ + + + + Even or Odd Checker + + +
    + Enter a number: + +
    + + + + diff --git a/php/fibonacci.php b/php/fibonacci.php new file mode 100644 index 00000000..bde54299 --- /dev/null +++ b/php/fibonacci.php @@ -0,0 +1,29 @@ + + + + Fibonacci Series + + +
    + Enter how many terms: + +
    + + "; + + for ($i = 1; $i <= $terms; $i++) { + echo $num1 . " "; + $next = $num1 + $num2; + $num1 = $num2; + $num2 = $next; + } + } + ?> + + diff --git a/php/kruskal's_algo.php b/php/kruskal's_algo.php new file mode 100644 index 00000000..ee5c4963 --- /dev/null +++ b/php/kruskal's_algo.php @@ -0,0 +1,81 @@ +parent[$i] = $i; + $this->rank[$i] = 0; + } + } + + public function find($x) { + if ($this->parent[$x] != $x) { + $this->parent[$x] = $this->find($this->parent[$x]); // Path compression + } + return $this->parent[$x]; + } + + public function union($x, $y) { + $rootX = $this->find($x); + $rootY = $this->find($y); + + if ($rootX == $rootY) return false; + + // Union by rank + if ($this->rank[$rootX] < $this->rank[$rootY]) { + $this->parent[$rootX] = $rootY; + } elseif ($this->rank[$rootX] > $this->rank[$rootY]) { + $this->parent[$rootY] = $rootX; + } else { + $this->parent[$rootY] = $rootX; + $this->rank[$rootX]++; + } + + return true; + } +} + +function kruskalMST($vertices, $edges) { + // Sort edges by weight + usort($edges, function($a, $b) { + return $a[2] <=> $b[2]; + }); + + $dsu = new DisjointSet($vertices); + $mst = []; + $totalWeight = 0; + + foreach ($edges as [$u, $v, $w]) { + if ($dsu->union($u, $v)) { + $mst[] = [$u, $v, $w]; + $totalWeight += $w; + } + } + + return [$mst, $totalWeight]; +} + +// Example Usage: +$vertices = 6; +$edges = [ + [0, 1, 4], + [0, 2, 4], + [1, 2, 2], + [1, 0, 4], + [2, 3, 3], + [2, 5, 2], + [2, 4, 4], + [3, 4, 3], + [5, 4, 3] +]; + +list($mst, $totalWeight) = kruskalMST($vertices, $edges); + +echo "Edges in the Minimum Spanning Tree:\n"; +foreach ($mst as [$u, $v, $w]) { + echo "$u - $v : $w\n"; +} +echo "Total weight of MST = $totalWeight\n"; diff --git a/php/palindrome.php b/php/palindrome.php new file mode 100644 index 00000000..e59e91d2 --- /dev/null +++ b/php/palindrome.php @@ -0,0 +1,16 @@ + diff --git a/php/prime.php b/php/prime.php new file mode 100644 index 00000000..5d174a90 --- /dev/null +++ b/php/prime.php @@ -0,0 +1,36 @@ + + + + Prime Number Checker + + +
    + Enter a number: + +
    + + + + diff --git a/php/radix_sort.php b/php/radix_sort.php new file mode 100644 index 00000000..b1b1582c --- /dev/null +++ b/php/radix_sort.php @@ -0,0 +1,47 @@ += 0; $i--) { + $digit = intdiv($arr[$i], $exp) % 10; + $output[$count[$digit] - 1] = $arr[$i]; + $count[$digit]--; + } + + // Copy output to original array + for ($i = 0; $i < $n; $i++) { + $arr[$i] = $output[$i]; + } +} + +function radixSort(&$arr) { + // Find the maximum number + $max = max($arr); + + // Do counting sort for every digit + $exp = 1; + while (intdiv($max, $exp) > 0) { + countingSortByDigit($arr, $exp); + $exp *= 10; + } +} + +// Example usage +$arr = [170, 45, 75, 90, 802, 24, 2, 66]; +radixSort($arr); +echo "Sorted array: " . implode(", ", $arr) . "\n"; diff --git a/python/10_Regular_Expression_Matching.py b/python/10_Regular_Expression_Matching.py new file mode 100644 index 00000000..3049fa6d --- /dev/null +++ b/python/10_Regular_Expression_Matching.py @@ -0,0 +1,57 @@ +# 10. Regular Expression Matching +# Hard +# Topics +# premium lock icon +# Companies +# Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where: + +# '.' Matches any single character.​​​​ +# '*' Matches zero or more of the preceding element. +# The matching should cover the entire input string (not partial). + + + +# Example 1: + +# Input: s = "aa", p = "a" +# Output: false +# Explanation: "a" does not match the entire string "aa". +# Example 2: + +# Input: s = "aa", p = "a*" +# Output: true +# Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa". +# Example 3: + +# Input: s = "ab", p = ".*" +# Output: true +# Explanation: ".*" means "zero or more (*) of any character (.)". + + +# Constraints: + +# 1 <= s.length <= 20 +# 1 <= p.length <= 20 +# s contains only lowercase English letters. +# p contains only lowercase English letters, '.', and '*'. +# It is guaranteed for each appearance of the character '*', there will be a previous valid character to match. + +class Solution(object): + def isMatch(self, text: str, pattern: str) -> bool: + memo = {} + + def dp(i: int, j: int) -> bool: + if (i, j) not in memo: + if j == len(pattern): + ans = i == len(text) + else: + first_match = i < len(text) and pattern[j] in {text[i], "."} + if j + 1 < len(pattern) and pattern[j + 1] == "*": + ans = dp(i, j + 2) or first_match and dp(i + 1, j) + else: + ans = first_match and dp(i + 1, j + 1) + + memo[i, j] = ans + return memo[i, j] + + return dp(0, 0) \ No newline at end of file diff --git a/python/27_lc_remove_element.py b/python/27_lc_remove_element.py new file mode 100644 index 00000000..d98ddb6d --- /dev/null +++ b/python/27_lc_remove_element.py @@ -0,0 +1,11 @@ +class Solution: + def removeElement(self, nums: List[int], val: int) -> int: + t = [] + p=[] + count=0 + for i in range(len(nums)): + if nums[i] != val: + nums[count]=nums[i] + count+=1 + + return count \ No newline at end of file diff --git a/python/4Sum.py b/python/4Sum.py index dbc5f1ac..e317a0aa 100644 --- a/python/4Sum.py +++ b/python/4Sum.py @@ -1,33 +1,57 @@ -from typing import List +class Solution: + def fourSum(self, nums, target): + """ + Finds all unique quadruplets in the list that sum up to the target. -def fourSum(nums: List[int], target: int) -> List[List[int]]: - nums.sort() - res = [] - n = len(nums) - - for i in range(n - 3): - if i > 0 and nums[i] == nums[i - 1]: - continue - for j in range(i + 1, n - 2): - if j > i + 1 and nums[j] == nums[j - 1]: + :param nums: List[int] - input list of integers + :param target: int - the target sum + :return: List[List[int]] - list of unique quadruplets + """ + nums.sort() # Sort the array for two-pointer approach and duplicate handling + n = len(nums) + results = [] + + # Loop for the first number + for i in range(n - 3): + # Skip duplicates for the first number + if i > 0 and nums[i] == nums[i - 1]: + continue + + # Early termination if smallest possible sum is already greater than target + if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target: + break + # Skip if the largest possible sum starting from nums[i] is still less than target + if nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target: continue - left, right = j + 1, n - 1 - while left < right: - total = nums[i] + nums[j] + nums[left] + nums[right] - if total == target: - res.append([nums[i], nums[j], nums[left], nums[right]]) - left += 1 - right -= 1 - while left < right and nums[left] == nums[left - 1]: + + # Loop for the second number + for j in range(i + 1, n - 2): + # Skip duplicates for the second number + if j > i + 1 and nums[j] == nums[j - 1]: + continue + + # Early termination for second number + if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target: + break + if nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target: + continue + + # Two pointers for the remaining two numbers + left, right = j + 1, n - 1 + while left < right: + total = nums[i] + nums[j] + nums[left] + nums[right] + if total == target: + results.append([nums[i], nums[j], nums[left], nums[right]]) + left += 1 + right -= 1 + # Skip duplicates + while left < right and nums[left] == nums[left - 1]: + left += 1 + while left < right and nums[right] == nums[right + 1]: + right -= 1 + elif total < target: left += 1 - while left < right and nums[right] == nums[right + 1]: + else: right -= 1 - elif total < target: - left += 1 - else: - right -= 1 - return res -nums = [1, 0, -1, 0, -2, 2] -target = 0 -print(fourSum(nums, target)) + return results diff --git a/python/ARRAY_twosum.py b/python/ARRAY_twosum.py new file mode 100644 index 00000000..27a883e0 --- /dev/null +++ b/python/ARRAY_twosum.py @@ -0,0 +1,11 @@ +# Problem: Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. + +def twoSum(nums, target): + hashmap = {} + for i, num in enumerate(nums): + diff = target - num + if diff in hashmap: + return [hashmap[diff], i] + hashmap[num] = i + +print(twoSum([2,7,11,15], 9)) # Output: [0,1] diff --git a/python/A_Skibidus_and_Amog_u.py b/python/A_Skibidus_and_Amog_u.py new file mode 100644 index 00000000..04cf0013 --- /dev/null +++ b/python/A_Skibidus_and_Amog_u.py @@ -0,0 +1,10 @@ +t = int(input()) +for _ in range(t): + word = input() + letters = list(word) + letters.reverse() + letters[0] = "" + letters[1] = "i" + letters.reverse() + ans = "".join(letters) + print(ans) diff --git a/python/A_star.py b/python/A_star.py new file mode 100644 index 00000000..61e32cef --- /dev/null +++ b/python/A_star.py @@ -0,0 +1,103 @@ +import heapq +from typing import List, Tuple, Optional + +def heuristic(a: Tuple[int, int], b: Tuple[int, int]) -> int: + """Manhattan distance heuristic""" + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + +def astar(grid: List[List[int]], + start: Tuple[int, int], + goal: Tuple[int, int]) -> Optional[List[Tuple[int, int]]]: + """ + A* pathfinding algorithm + + Args: + grid: 2D grid where 0 is walkable, 1 is wall + start: Starting position (row, col) + goal: Goal position (row, col) + + Returns: + List of positions forming the path, or None if no path exists + """ + rows, cols = len(grid), len(grid[0]) + directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + + # Priority queue: (f_score, g_score, position) + open_set = [(heuristic(start, goal), 0, start)] + came_from = {} + g_score = {start: 0} + + while open_set: + _, curr_g, curr = heapq.heappop(open_set) + + if curr == goal: + # Reconstruct path + path = [goal] + while path[-1] in came_from: + path.append(came_from[path[-1]]) + return path[::-1] + + # Skip if we've found a better path already + if curr_g > g_score.get(curr, float('inf')): + continue + + for dx, dy in directions: + neighbor = (curr[0] + dx, curr[1] + dy) + + # Check bounds and walls + if (0 <= neighbor[0] < rows and + 0 <= neighbor[1] < cols and + grid[neighbor[0]][neighbor[1]] == 0): + + tentative_g = curr_g + 1 + + if tentative_g < g_score.get(neighbor, float('inf')): + came_from[neighbor] = curr + g_score[neighbor] = tentative_g + f_score = tentative_g + heuristic(neighbor, goal) + heapq.heappush(open_set, (f_score, tentative_g, neighbor)) + + return None + +def print_grid_with_path(grid: List[List[int]], path: List[Tuple[int, int]]): + """Visualize the grid with the path""" + path_set = set(path) + for i, row in enumerate(grid): + for j, cell in enumerate(row): + if (i, j) in path_set: + if (i, j) == path[0]: + print("S", end=" ") + elif (i, j) == path[-1]: + print("G", end=" ") + else: + print("*", end=" ") + elif cell == 1: + print("█", end=" ") + else: + print("·", end=" ") + print() + +if __name__ == "__main__": + grid = [ + [0, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + [0, 0, 0, 0, 0], + [0, 1, 0, 1, 0], + [0, 0, 0, 0, 0], + ] + + start = (0, 0) + goal = (4, 4) + + path = astar(grid, start, goal) + + if path: + print("Path found:") + for pos in path: + print(f"({pos[0]},{pos[1]})", end=" ") + print(f"\nSteps: {len(path) - 1}\n") + + print("Grid visualization:") + print_grid_with_path(grid, path) + else: + print("No path found") \ No newline at end of file diff --git a/python/Activity_Day.py b/python/Activity_Day.py new file mode 100644 index 00000000..8a47c579 --- /dev/null +++ b/python/Activity_Day.py @@ -0,0 +1,136 @@ +import collections + +def solve_activity_day(): + """ + Solves the Activity Day problem by identifying boxes from partition lines, + ranking them based on area and coordinates, and then calculating the value + of the string in the box corresponding to a given rank. + """ + + # --- 1. READ INPUT --- + try: + n, m = map(int, input().split()) + l = int(input()) + all_lines = [list(map(int, input().split())) for _ in range(l)] + raghu_rank = int(input()) + strings = input().split() + except (IOError, ValueError): + return + + # --- 2. IDENTIFY BOXES --- + horizontal_lines = [] + vertical_lines = [] + x_coords_set = {0, n} + y_coords_set = {0, m} + + for x1, y1, x2, y2 in all_lines: + if x1 == x2: # Vertical line + vertical_lines.append((x1, min(y1, y2), x2, max(y1, y2))) + x_coords_set.add(x1) + else: # Horizontal line + horizontal_lines.append((min(x1, x2), y1, max(x1, x2), y2)) + y_coords_set.add(y1) + + x_coords = sorted(list(x_coords_set)) + y_coords = sorted(list(y_coords_set)) + + num_x_cells = len(x_coords) - 1 + num_y_cells = len(y_coords) - 1 + + + vertical_walls_by_x = collections.defaultdict(list) + for x, y_start, _, y_end in vertical_lines: + vertical_walls_by_x[x].append((y_start, y_end)) + + horizontal_walls_by_y = collections.defaultdict(list) + for x_start, y, x_end, _ in horizontal_lines: + horizontal_walls_by_y[y].append((x_start, x_end)) + + def has_vertical_wall(i, j): + """Check for a vertical partition to the right of cell (i, j).""" + wall_x = x_coords[i + 1] + if wall_x not in vertical_walls_by_x: + return False + cell_y_start, cell_y_end = y_coords[j], y_coords[j + 1] + for line_y_start, line_y_end in vertical_walls_by_x[wall_x]: + + if max(line_y_start, cell_y_start) < min(line_y_end, cell_y_end): + return True + return False + + def has_horizontal_wall(i, j): + """Check for a horizontal partition above cell (i, j).""" + wall_y = y_coords[j + 1] + if wall_y not in horizontal_walls_by_y: + return False + cell_x_start, cell_x_end = x_coords[i], x_coords[i + 1] + for line_x_start, line_x_end in horizontal_walls_by_y[wall_y]: + if max(line_x_start, cell_x_start) < min(line_x_end, cell_x_end): + return True + return False + + # 2c. Use BFS to find all connected components (boxes) + found_boxes = [] + visited = [[False for _ in range(num_x_cells)] for _ in range(num_y_cells)] + + for j_start in range(num_y_cells): + for i_start in range(num_x_cells): + if not visited[j_start][i_start]: + q = collections.deque([(i_start, j_start)]) + visited[j_start][i_start] = True + + min_i, max_i = i_start, i_start + min_j, max_j = j_start, j_start + + while q: + ci, cj = q.popleft() + + min_i, max_i = min(min_i, ci), max(max_i, ci) + min_j, max_j = min(min_j, cj), max(max_j, cj) + + + if ci + 1 < num_x_cells and not visited[cj][ci + 1] and not has_vertical_wall(ci, cj): + visited[cj][ci + 1] = True; q.append((ci + 1, cj)) + if ci - 1 >= 0 and not visited[cj][ci - 1] and not has_vertical_wall(ci - 1, cj): + visited[cj][ci - 1] = True; q.append((ci - 1, cj)) + if cj + 1 < num_y_cells and not visited[cj + 1][ci] and not has_horizontal_wall(ci, cj): + visited[cj + 1][ci] = True; q.append((ci, cj + 1)) + if cj - 1 >= 0 and not visited[cj - 1][ci] and not has_horizontal_wall(ci, cj - 1): + visited[cj - 1][ci] = True; q.append((ci, cj - 1)) + + # After BFS, define the found box by its corner coordinates + bottom_left_x = x_coords[min_i] + bottom_left_y = y_coords[min_j] + top_right_x = x_coords[max_i + 1] + top_right_y = y_coords[max_j + 1] + + found_boxes.append({ + "x": bottom_left_x, + "y": bottom_left_y, + "w": top_right_x - bottom_left_x, + "h": top_right_y - bottom_left_y + }) + + # --- 3. ASSIGN STRINGS & CALCULATE AREA --- + # Sort boxes by y, then x, to match the specified string assignment order + sorted_for_strings = sorted(found_boxes, key=lambda b: (b['y'], b['x'])) + + all_box_data = [] + for i, box in enumerate(sorted_for_strings): + box['string'] = strings[i] + box['area'] = box['w'] * box['h'] + all_box_data.append(box) + + # --- 4. RANK BOXES --- + # Sort using the specified ranking criteria: Area (desc), x (asc), y (asc) + ranked_boxes = sorted(all_box_data, key=lambda b: (-b['area'], b['x'], b['y'])) + + # --- 5. OUTPUT THE RESULT --- + + if 1 <= raghu_rank <= len(ranked_boxes): + raghus_string = ranked_boxes[raghu_rank - 1]['string'] + value = sum(ord(c) for c in raghus_string) + print(value) + +# Call the main function to run the solution +solve_activity_day() diff --git a/python/Ancient_Library.py b/python/Ancient_Library.py new file mode 100644 index 00000000..d2dabe15 --- /dev/null +++ b/python/Ancient_Library.py @@ -0,0 +1,41 @@ +# The Ancient Library Scroll Grouping Problem +# You've stumbled upon a collection of ancient scrolls in a long-forgotten library. +# Each scroll is represented by a string of symbols. You quickly realize that many +# scrolls are just different arrangements of the same set of symbols—meaning they are +# fragments of the same original manuscript. +# +# Your task is to group the scrolls that are anagrams of each other. +# +# For example, if you have the scrolls: +# ["arc", "car", "cat", "act", "race", "acre"] +# +# The correct grouping would be: +# [["arc", "car"], ["cat", "act"], ["race", "acre"]] +# +# The Question : Write a function that takes a list of scroll strings and returns a list of +# these groups. The order of the groups and the scrolls within them doesn't matter. + +from collections import defaultdict + +def ancient_scrolls_group(scrolls): + groups = defaultdict(list) + + for scroll in scrolls: + signature = "".join(sorted(scroll)) + groups[signature].append(scroll) + + return list(groups.values()) + +if __name__ == '__main__': + discovered_scrolls = [ + "tea", "map", "eat", "ate", "pam", "pat", "tap" + ] + + manuscripts = ancient_scrolls_group(discovered_scrolls) + + print("Discovered scrolls:", discovered_scrolls) + print("\nGrouped into original manuscripts:") + for group in manuscripts: + print(group) + +#this is my attempt , it can be improved. \ No newline at end of file diff --git a/python/AvoidFloodInTheCity.py b/python/AvoidFloodInTheCity.py new file mode 100644 index 00000000..aeae9ef1 --- /dev/null +++ b/python/AvoidFloodInTheCity.py @@ -0,0 +1,26 @@ +class Solution(object): + def avoidFlood(self, rains): + """ + :type rains: List[int] + :rtype: List[int] + """ + n = len(rains) + full = {} + dry_days = [] + ans = [-1] * n + + for i, lake in enumerate(rains): + if lake == 0: + dry_days.append(i) + ans[i] = 1 + else: + if lake in full: + j = bisect_right(dry_days, full[lake]) + if j == len(dry_days): + return [] + dry_day = dry_days.pop(j) + ans[dry_day] = lake + full[lake] = i + ans[i] = -1 + + return ans diff --git a/python/BinarySearch.py b/python/BinarySearch.py new file mode 100644 index 00000000..b01780c1 --- /dev/null +++ b/python/BinarySearch.py @@ -0,0 +1,26 @@ +def binarySearch(arr, targetVal): + left = 0 + right = len(arr) - 1 + + while left <= right: + mid = (left + right) // 2 + + if arr[mid] == targetVal: + return mid + + if arr[mid] < targetVal: + left = mid + 1 + else: + right = mid - 1 + + return -1 + +mylist = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] +x = 11 + +result = binarySearch(mylist, x) + +if result != -1: + print("Found at index", result) +else: + print("Not found") diff --git a/python/Binary_Search_Implementation.py b/python/Binary_Search_Implementation.py new file mode 100644 index 00000000..997c1ce3 --- /dev/null +++ b/python/Binary_Search_Implementation.py @@ -0,0 +1,23 @@ +# File name: Binary_Search_Implementation.py + +def binary_search(arr, target): + left, right = 0, len(arr) - 1 + while left <= right: + mid = (left + right) // 2 + if arr[mid] == target: + return mid + elif arr[mid] < target: + left = mid + 1 + else: + right = mid - 1 + return -1 + +# Example usage: +if __name__ == "__main__": + array = [1, 3, 5, 7, 9, 11, 13] + target = 7 + result = binary_search(array, target) + if result != -1: + print(f"Element {target} found at index {result}") + else: + print(f"Element {target} not found in array") diff --git a/python/Binarytreetraversal.py b/python/Binarytreetraversal.py new file mode 100644 index 00000000..5db3a679 --- /dev/null +++ b/python/Binarytreetraversal.py @@ -0,0 +1,30 @@ +# Define a tree node +class Node: + def __init__(self, value): + self.value = value + self.left = None + self.right = None + +# Inorder traversal function +def inorder(root): + if root: + inorder(root.left) + print(root.value, end=' ') + inorder(root.right) + +# Build a simple tree +# 10 +# / \ +# 5 15 +# / \ +# 12 20 + +root = Node(10) +root.left = Node(5) +root.right = Node(15) +root.right.left = Node(12) +root.right.right = Node(20) + +# Traverse tree +print("Inorder Traversal:") +inorder(root) diff --git a/python/ClimbingStairs.py b/python/ClimbingStairs.py deleted file mode 100644 index 3cf56aa1..00000000 --- a/python/ClimbingStairs.py +++ /dev/null @@ -1,8 +0,0 @@ -class Solution: - def climbStairs(self, n: int) -> int: - one, two = 1, 1 - for i in range(n - 1): - temp = one - one = two + one - two = temp - return one diff --git a/python/Coin_Change2.py b/python/Coin_Change2.py new file mode 100644 index 00000000..e69de29b diff --git a/python/Custom HashMap.py b/python/Custom HashMap.py new file mode 100644 index 00000000..0f536139 --- /dev/null +++ b/python/Custom HashMap.py @@ -0,0 +1,62 @@ +class HashMap: + def __init__(self, size=10): + self.size = size + self.map = [[] for _ in range(size)] + + def _get_hash(self, key): + return hash(key) % self.size + + def add(self, key, value): + key_hash = self._get_hash(key) + bucket = self.map[key_hash] + + for i, (k, v) in enumerate(bucket): + if k == key: + bucket[i] = (key, value) # update value + return + bucket.append((key, value)) + + def get(self, key): + key_hash = self._get_hash(key) + bucket = self.map[key_hash] + + for k, v in bucket: + if k == key: + return v + return None # key not found + + def remove(self, key): + key_hash = self._get_hash(key) + bucket = self.map[key_hash] + + for i, (k, v) in enumerate(bucket): + if k == key: + del bucket[i] + return True + return False + + def display(self): + # Show hashmap contents + for i, bucket in enumerate(self.map): + if bucket: + print(f"Bucket {i}: {bucket}") + + +# 🔹 Example Usage +hashmap = HashMap() + +hashmap.add("name", "Gaurav") +hashmap.add("role", "Full Stack Developer") +hashmap.add("language", "Python") +hashmap.add("experience", 3) + +print("Name:", hashmap.get("name")) +print("Role:", hashmap.get("role")) + +hashmap.add("experience", 4) # update value +print("Updated experience:", hashmap.get("experience")) + +hashmap.remove("language") + +print("\nHashMap Contents:") +hashmap.display() \ No newline at end of file diff --git a/python/DNA_Finder.py b/python/DNA_Finder.py new file mode 100644 index 00000000..c9c6dcbc --- /dev/null +++ b/python/DNA_Finder.py @@ -0,0 +1,93 @@ +# Problem: DNA Sequence Pattern Finder using KMP + Rabin-Karp Hybrid + +# Description: +# Efficiently finds all occurrences of a DNA sequence pattern (substring) +# within a longer DNA string using a hybrid of Rabin-Karp (for hashing) +# and KMP (for prefix optimization). + +# Why hybrid? +# Rabin-Karp provides fast rolling hash comparisons. +# KMP ensures correctness by avoiding false positives from hash collisions. + +# Example use-cases: +# Genome research: searching for specific gene patterns in DNA sequences. +# Bioinformatics pipelines: DNA motif detection. + +BASE = 4 # DNA alphabet size: A, C, G, T +MOD = 10**9 + 7 + +# Map DNA characters to numbers +DNA_MAP = {'A': 0, 'C': 1, 'G': 2, 'T': 3} + +def rabin_karp_hash(s): + """Compute hash for a DNA sequence string.""" + h = 0 + for ch in s: + h = (h * BASE + DNA_MAP[ch]) % MOD + return h + + +def compute_lps(pattern): + """Compute Longest Prefix Suffix (LPS) array for KMP algorithm.""" + lps = [0] * len(pattern) + length = 0 + i = 1 + while i < len(pattern): + if pattern[i] == pattern[length]: + length += 1 + lps[i] = length + i += 1 + else: + if length != 0: + length = lps[length - 1] + else: + lps[i] = 0 + i += 1 + return lps + + +def dna_pattern_finder(text, pattern): + """ + Hybrid algorithm to find all occurrences of 'pattern' in 'text'. + Uses Rabin-Karp for fast hash matching + KMP for exact validation. + """ + if len(pattern) == 0 or len(text) < len(pattern): + return [] + + m, n = len(pattern), len(text) + pattern_hash = rabin_karp_hash(pattern) + current_hash = rabin_karp_hash(text[:m]) + positions = [] + + power = pow(BASE, m - 1, MOD) # precompute power for rolling hash + lps = compute_lps(pattern) + + for i in range(n - m + 1): + if i > 0: + # Roll the hash + current_hash = ( + (current_hash - DNA_MAP[text[i - 1]] * power) * BASE + DNA_MAP[text[i + m - 1]] + ) % MOD + + # Hash match — verify with KMP-like check + if current_hash == pattern_hash: + j = 0 + k = i + while j < m and k < n and text[k] == pattern[j]: + j += 1 + k += 1 + if j == m: + positions.append(i) + + return positions + + +if __name__ == "__main__": + # Example DNA sequence and pattern + dna_sequence = "ACGTACGTGACGTTACG" + pattern = "ACGT" + + result = dna_pattern_finder(dna_sequence, pattern) + print(f"DNA Sequence: {dna_sequence}") + print(f"Pattern: {pattern}") + print(f"Occurrences found at indices: {result}") diff --git a/python/D_Fixed_Password.py b/python/D_Fixed_Password.py new file mode 100644 index 00000000..85bb5a5a --- /dev/null +++ b/python/D_Fixed_Password.py @@ -0,0 +1,7 @@ +for _ in range(10000): + a = int(input()) + if a != 1999: + print("Wrong") + elif a == 1999: + print("Correct") + break \ No newline at end of file diff --git a/python/Dijikta's algo.py b/python/Dijikta's algo.py new file mode 100644 index 00000000..4ab32034 --- /dev/null +++ b/python/Dijikta's algo.py @@ -0,0 +1,28 @@ +import heapq + +def dijkstra(graph, start): + distances = {node: float("inf") for node in graph} + distances[start] = 0 + pq = [(0, start)] # (distance, node) + + while pq: + current_dist, node = heapq.heappop(pq) + + if current_dist > distances[node]: + continue + + for neighbor, weight in graph[node]: + distance = current_dist + weight + if distance < distances[neighbor]: + distances[neighbor] = distance + heapq.heappush(pq, (distance, neighbor)) + + return distances + +graph = { + 0: [(1, 4), (2, 1)], + 1: [(3, 1)], + 2: [(1, 2), (3, 5)], + 3: [] +} +print("\nShortest distances from node 0:", dijkstra(graph, 0)) diff --git a/python/Dijkstra's_code.py b/python/Dijkstra's_code.py new file mode 100644 index 00000000..e402077a --- /dev/null +++ b/python/Dijkstra's_code.py @@ -0,0 +1,28 @@ +import heapq + +def dijkstra(graph, start): + distances = {node: float("inf") for node in graph} + distances[start] = 0 + pq = [(0, start)] # (distance, node) + + while pq: + current_dist, node = heapq.heappop(pq) + + if current_dist > distances[node]: + continue + + for neighbor, weight in graph[node]: + distance = current_dist + weight + if distance < distances[neighbor]: + distances[neighbor] = distance + heapq.heappush(pq, (distance, neighbor)) + + return distances + +graph = { + 0: [(1, 4), (2, 1)], + 1: [(3, 1)], + 2: [(1, 2), (3, 5)], + 3: [] +} +print("\nShortest distances from node 0:", dijkstra(graph, 0)) \ No newline at end of file diff --git "a/python/Dijkstra\342\200\231sAlgorithm.py" "b/python/Dijkstra\342\200\231sAlgorithm.py" new file mode 100644 index 00000000..d7a4d641 --- /dev/null +++ "b/python/Dijkstra\342\200\231sAlgorithm.py" @@ -0,0 +1,27 @@ +import heapq + +def dijkstra(graph, start): + pq = [(0, start)] # (distance, node) + dist = {node: float('inf') for node in graph} + dist[start] = 0 + + while pq: + cur_dist, node = heapq.heappop(pq) + if cur_dist > dist[node]: + continue + for nei, weight in graph[node]: + new_dist = cur_dist + weight + if new_dist < dist[nei]: + dist[nei] = new_dist + heapq.heappush(pq, (new_dist, nei)) + return dist + + +# Example usage: +graph = { + 'A': [('B', 2), ('C', 5)], + 'B': [('C', 1), ('D', 4)], + 'C': [('D', 1)], + 'D': [] +} +print("Shortest Distances:", dijkstra(graph, 'A')) \ No newline at end of file diff --git "a/python/Dijkstra\342\200\231s_Algo.py" "b/python/Dijkstra\342\200\231s_Algo.py" new file mode 100644 index 00000000..4ab32034 --- /dev/null +++ "b/python/Dijkstra\342\200\231s_Algo.py" @@ -0,0 +1,28 @@ +import heapq + +def dijkstra(graph, start): + distances = {node: float("inf") for node in graph} + distances[start] = 0 + pq = [(0, start)] # (distance, node) + + while pq: + current_dist, node = heapq.heappop(pq) + + if current_dist > distances[node]: + continue + + for neighbor, weight in graph[node]: + distance = current_dist + weight + if distance < distances[neighbor]: + distances[neighbor] = distance + heapq.heappush(pq, (distance, neighbor)) + + return distances + +graph = { + 0: [(1, 4), (2, 1)], + 1: [(3, 1)], + 2: [(1, 2), (3, 5)], + 3: [] +} +print("\nShortest distances from node 0:", dijkstra(graph, 0)) diff --git a/Dsa-code.py b/python/Dsa-code.py similarity index 85% rename from Dsa-code.py rename to python/Dsa-code.py index dbe1a230..33e6e63a 100644 --- a/Dsa-code.py +++ b/python/Dsa-code.py @@ -1,6 +1,6 @@ -I Make Change In Code In Easy Ways +# I Make Change In Code In Easy Ways -1. Code ( link list _Sum.py ) +# 1. Code ( link list _Sum.py ) class Node: def __init__(self, data): @@ -20,7 +20,8 @@ def sum_linked_list(head): head.next.next = Node(15) print("Linked List Sum:", sum_linked_list(head)) -2. Code ( half- linklist.py ) + +# 2. Code ( half- linklist.py ) def print_half(head): slow, fast = head, head @@ -34,7 +35,8 @@ def print_half(head): head.next.next.next = Node(4); head.next.next.next.next = Node(5) print_half(head) # prints 1 -> 2 -> END -3. Code ( helloWorld.py ) + +# 3. Code ( helloWorld.py ) def hello_world(): codes = [72,101,108,108,111,32,87,111,114,108,100] @@ -42,7 +44,8 @@ def hello_world(): print(hello_world()) -4. Code ( Sum of 1d arrays.py ) + +# 4. Code ( Sum of 1d arrays.py ) def sum_array(arr): total = 0 diff --git a/python/Dynamic Programming patterns/complex_pattern b/python/Dynamic Programming patterns/complex_pattern new file mode 100644 index 00000000..d737d053 --- /dev/null +++ b/python/Dynamic Programming patterns/complex_pattern @@ -0,0 +1,62 @@ +# Dynamic program pattern problem: + +# Example for n = 3 +# Output: +# * +# ** * +# ******** +# ** * +# * +# Example for n = 5 +# Output: +# * +# ** +# *** +# **** * +# ************ +# **** * +# *** +# ** +# * + +# Solution in Python +def pattern(n): + # Check if the number is odd and greater than or equal to 3 + if n % 2 == 0 or n < 3: + print("Please enter an odd number") + else: + # Calculate total columns in the widest part of the pattern + row_length = (n * 2) - 1 + # Calculate total columns in the middle solid line + col_length = (n * 2) + 2 + + # ----------------------------- + # Upper top part of the pattern + # ----------------------------- + # Print increasing stars for top-left side (first (n-2) lines) + for row in range(n - 2): + print("*" * (row + 1)) + + # Print the line having gap in between and star at both sides + for row in range(1): + print("*" * (n - 1) + " " * (n + 1) + "*") + + # Print the solid middle line (full stars) + for row in range(1): + print("*" * col_length) + + # Print the line below the solid one (same as above gap line) + for row in range(1): + print("*" * (n - 1) + " " * (n + 1) + "*") + + # ----------------------------- + # Lower bottom part of the pattern + # ----------------------------- + # Print decreasing stars for bottom-left side (mirror of top part) + for row in range(n - 2): + print("*" * (n - row - 2)) + + +# Take input from user +number = int(input("Enter the odd number : ")) +pattern(number) diff --git a/python/DynamicProgramming/Climbing_Stairs/1_recursiveSolution.py b/python/DynamicProgramming/Climbing_Stairs/1_recursiveSolution.py new file mode 100644 index 00000000..74b79ab2 --- /dev/null +++ b/python/DynamicProgramming/Climbing_Stairs/1_recursiveSolution.py @@ -0,0 +1,30 @@ +# Problem: Climbing Stairs +# Approach: Simple Recursion +# Time Complexity: O(2^n) - Exponential, due to redundant calculations +# Space Complexity: O(n) - For the recursion stack + +def dfs(n): + """ + Calculates the number of ways to climb n stairs using recursion. + Base cases: + - If n is 0 or 1, there's only one way. + """ + if n < 2: + return 1 + + # The number of ways to reach step 'n' is the sum of ways to reach 'n-1' and 'n-2'. + one_step = dfs(n - 1) + two_steps = dfs(n - 2) + + return one_step + two_steps + +def climbStairs(n): + """ + Main function to initiate the recursive calculation. + """ + return dfs(n) + +# Example usage: +if __name__ == "__main__": + num_stairs = 4 + print(f"Number of ways to climb {num_stairs} stairs: {climbStairs(num_stairs)}") # Outputs: 5 diff --git a/python/DynamicProgramming/Climbing_Stairs/2_memmoization.py b/python/DynamicProgramming/Climbing_Stairs/2_memmoization.py new file mode 100644 index 00000000..f38f7e09 --- /dev/null +++ b/python/DynamicProgramming/Climbing_Stairs/2_memmoization.py @@ -0,0 +1,35 @@ +# Problem: Climbing Stairs +# Approach: Memoization (Top-Down Dynamic Programming) +# Time Complexity: O(n) - Each subproblem is solved only once. +# Space Complexity: O(n) - For the recursion stack and the dp array. + +def dfs(n, dp): + """ + Calculates the number of ways to climb n stairs using recursion with memoization. + """ + if n < 2: + return 1 + + # If the result for 'n' is already computed, return it. + if dp[n] != -1: + return dp[n] + + # Compute and store the result before returning. + one_step = dfs(n - 1, dp) + two_steps = dfs(n - 2, dp) + dp[n] = one_step + two_steps + + return dp[n] + +def climbStairs(n): + """ + Main function to initiate the memoized calculation. + Initializes a dp array with -1 to store results of subproblems. + """ + dp = [-1] * (n + 1) + return dfs(n, dp) + +# Example usage: +if __name__ == "__main__": + num_stairs = 4 + print(f"Number of ways to climb {num_stairs} stairs: {climbStairs(num_stairs)}") # Outputs: 5 diff --git a/python/DynamicProgramming/Climbing_Stairs/3_tabulation.py b/python/DynamicProgramming/Climbing_Stairs/3_tabulation.py new file mode 100644 index 00000000..9ce6c130 --- /dev/null +++ b/python/DynamicProgramming/Climbing_Stairs/3_tabulation.py @@ -0,0 +1,27 @@ +# Problem: Climbing Stairs +# Approach: Tabulation (Bottom-Up Dynamic Programming) +# Time Complexity: O(n) - We iterate from 2 to n. +# Space Complexity: O(n) - For the dp array. + +def climbStairs(n): + """ + Calculates the number of ways to climb n stairs using tabulation. + """ + if n < 2: + return 1 + + # dp[i] will store the number of ways to reach stair i. + dp = [0] * (n + 1) + dp[0] = 1 # Base case: 1 way to be at the start + dp[1] = 1 # Base case: 1 way to reach the first stair + + # Fill the dp table from the bottom up. + for i in range(2, n + 1): + dp[i] = dp[i - 1] + dp[i - 2] + + return dp[n] + +# Example usage: +if __name__ == "__main__": + num_stairs = 4 + print(f"Number of ways to climb {num_stairs} stairs: {climbStairs(num_stairs)}") # Outputs: 5 diff --git a/python/DynamicProgramming/Climbing_Stairs/4_spaceOptimized.py b/python/DynamicProgramming/Climbing_Stairs/4_spaceOptimized.py new file mode 100644 index 00000000..8a312bb1 --- /dev/null +++ b/python/DynamicProgramming/Climbing_Stairs/4_spaceOptimized.py @@ -0,0 +1,26 @@ +# Problem: Climbing Stairs +# Approach: Space-Optimized Dynamic Programming +# Time Complexity: O(n) - Single loop up to n. +# Space Complexity: O(1) - Only two variables are used to store previous results. + +def climbStairs(n): + """ + Calculates the number of ways to climb n stairs using space optimization. + """ + if n < 2: + return 1 + + prev = 1 # Represents ways to climb (i-1) stairs, initially for n=1 + prev2 = 1 # Represents ways to climb (i-2) stairs, initially for n=0 + + for i in range(2, n + 1): + curr = prev + prev2 + prev2 = prev + prev = curr + + return prev + +# Example usage: +if __name__ == "__main__": + num_stairs = 4 + print(f"Number of ways to climb {num_stairs} stairs: {climbStairs(num_stairs)}") # Outputs: 5 diff --git a/python/DynamicProgramming/Climbing_Stairs/readme.md b/python/DynamicProgramming/Climbing_Stairs/readme.md new file mode 100644 index 00000000..2db85eb9 --- /dev/null +++ b/python/DynamicProgramming/Climbing_Stairs/readme.md @@ -0,0 +1,106 @@ +Climbing Stairs + +This directory contains multiple solutions to the classic "Climbing Stairs" problem, showcasing different algorithmic approaches and optimizations. + +Problem Link: LeetCode 70. Climbing Stairs + +Intuition + +You are climbing a staircase that has n steps. You can either climb 1 or 2 steps at a time. The goal is to find the total number of distinct ways you can reach the top. + +Let's analyze the core logic: + +To reach the n-th step, you must have come from either the (n-1)-th step or the (n-2)-th step. + +There are no other possibilities. + +Therefore, the total number of ways to reach step n is the sum of the ways to reach step (n-1) and the ways to reach step (n-2). + +This gives us the recurrence relation: +ways(n) = ways(n-1) + ways(n-2) + +This is the exact formula for the Fibonacci sequence. + +Base Cases: + +ways(0) = 1 (There is one way to be at the ground floor: do nothing). + +ways(1) = 1 (There is one way to reach the first step: take one step). + +Approaches + +1. Simple Recursion + +This is the most straightforward approach where we directly translate the recurrence relation into a recursive function. + +Code: recursiveSolution.py + +def dfs(n): + if n < 2: + return 1 + oneStep = dfs(n-1) + twoSteps = dfs(n-2) + return oneStep + twoSteps + + +Time Complexity: O(2^n). This is very inefficient because the same subproblems (e.g., dfs(2)) are calculated multiple times. + +Space Complexity: O(n) for the recursion call stack. + +2. Memoization (Top-Down DP) + +To optimize the recursive solution, we can store the results of subproblems in a data structure (like an array or hash map) and reuse them. This is a top-down approach. + +Code: memoization.py + +def dfs(n, dp): + if n < 2: + return 1 + if dp[n] != -1: + return dp[n] + dp[n] = dfs(n-1, dp) + dfs(n-2, dp) + return dp[n] + + +Time Complexity: O(n). Each subproblem from n down to 0 is solved only once. + +Space Complexity: O(n) for the dp array and O(n) for the recursion stack. + +3. Tabulation (Bottom-Up DP) + +Instead of recursion, we can solve the problem iteratively. We build the solution from the base cases up to n. + +Code: tabulation.py + +def climbStairs(n): + dp = [0] * (n+1) + dp[0] = 1 + dp[1] = 1 + for i in range(2, n+1): + dp[i] = dp[i-1] + dp[i-2] + return dp[n] + + +Time Complexity: O(n). We iterate through the loop n-1 times. + +Space Complexity: O(n) for the dp array. + +4. Space-Optimized DP + +Looking at the tabulation approach, we see that to calculate dp[i], we only need the values of dp[i-1] and dp[i-2]. We don't need the entire dp array. We can optimize the space by only storing the last two values. + +Code: spaceOptimized.py + +def climbStairs(n): + prev = 1 + prev2 = 1 + for i in range(2, n+1): + curr = prev + prev2 + prev2 = prev + prev = curr + return prev + + +Time Complexity: O(n). + +Space Complexity: O(1). We only use a few variables to store the state. \ No newline at end of file diff --git a/python/DynamicProgramming/CoinChange.py b/python/DynamicProgramming/CoinChange.py new file mode 100644 index 00000000..2b5a231f --- /dev/null +++ b/python/DynamicProgramming/CoinChange.py @@ -0,0 +1,48 @@ +""" +Name: Coin Change Problem (Optimal Space & Time) + +Problem: Given an integer array coins representing coins of different denominations +and an integer amount, return the fewest number of coins needed to make up that amount. +If that amount cannot be made up by any combination of the coins, return -1. + +Optimal Approach: Uses a single 1D DP array for space efficiency and bottom-up calculation. + +Link: https://leetcode.com/problems/coin-change/ +""" + +# Solution +def coinChange(coins, amount): + dp = [amount + 1] * (amount + 1) # line 12 + dp[0] = 0 + for i in range(1, amount + 1): + for coin in coins: + if coin <= i: + dp[i] = min(dp[i], dp[i - coin] + 1) + return dp[amount] if dp[amount] <= amount else -1 + +#Input +if __name__ == "__main__": + coins = [1, 2, 5] + amount = 11 + print("Minimum coins needed:", coinChange(coins, amount)) # Output: 3 (5 + 5 + 1) + + +# Explanation: +# - Function to compute the minimum number of coins needed to make up a given amount using optimal 1D DP - line 14 +# - Step 1: Initialize a DP array of size amount+1 with amount+1 as placeholder, dp[0] = 0 - line 15-16 +# - Step 2: Fill the DP array bottom-up - line 17-18 +# - Step 2a: For each coin, update dp[i] as the minimum between current and dp[i - coin] + 1 - line 19-20 +# - Step 3: Return dp[amount] if it is ≤ amount, else return -1 - line 21 +# - Step 4: Example usage - line 24-27 +# - Step 5: Call the coinChange function and print the result - line 27 + +""" +Complexity Analysis: + +Time Complexity: O(n * amount) + - n = number of coins, amount = target amount + - Each amount is processed for every coin + +Space Complexity: O(amount) + - Only a 1D DP array of size amount + 1 is used +""" diff --git a/python/DynamicProgramming/Frog_Jump/1_recursiveSolution.py b/python/DynamicProgramming/Frog_Jump/1_recursiveSolution.py new file mode 100644 index 00000000..adb57ade --- /dev/null +++ b/python/DynamicProgramming/Frog_Jump/1_recursiveSolution.py @@ -0,0 +1,15 @@ +def frog_jump(index, heights): + if index == 0: + return 0 + + one_jump = frog_jump(index - 1, heights) + abs(heights[index] - heights[index - 1]) + + two_jumps = float('inf') + if index > 1: + two_jumps = frog_jump(index - 2, heights) + abs(heights[index] - heights[index - 2]) + + return min(one_jump, two_jumps) + +if __name__ == "__main__": + heights = [20, 30, 40, 20] + print(frog_jump(len(heights) - 1, heights)) # Output: 20 \ No newline at end of file diff --git a/python/DynamicProgramming/Frog_Jump/2_memoization.py b/python/DynamicProgramming/Frog_Jump/2_memoization.py new file mode 100644 index 00000000..d1f2b329 --- /dev/null +++ b/python/DynamicProgramming/Frog_Jump/2_memoization.py @@ -0,0 +1,19 @@ +def frog_jump(index, heights, dp): + if index == 0: + return 0 + if dp[index] != -1: + return dp[index] + + one = frog_jump(index - 1, heights, dp) + abs(heights[index] - heights[index - 1]) + two = float('inf') + if index > 1: + two = frog_jump(index - 2, heights, dp) + abs(heights[index] - heights[index - 2]) + + dp[index] = min(one, two) + return dp[index] + +if __name__ == "__main__": + heights = [10, 30, 40, 20] + n = len(heights) + dp = [-1] * n + print(frog_jump(n - 1, heights, dp)) # Output: 30 \ No newline at end of file diff --git a/python/DynamicProgramming/Frog_Jump/3_tabulation.py b/python/DynamicProgramming/Frog_Jump/3_tabulation.py new file mode 100644 index 00000000..c11b8705 --- /dev/null +++ b/python/DynamicProgramming/Frog_Jump/3_tabulation.py @@ -0,0 +1,15 @@ +def frog_jump(heights): + n = len(heights) + dp = [0] * n + dp[0] = 0 + + for i in range(1, n): + one = dp[i - 1] + abs(heights[i] - heights[i - 1]) + two = dp[i - 2] + abs(heights[i] - heights[i - 2]) if i > 1 else float('inf') + dp[i] = min(one, two) + + return dp[-1] + +if __name__ == "__main__": + heights = [10, 30, 40, 20] + print(frog_jump(heights)) # Output: 30 \ No newline at end of file diff --git a/python/DynamicProgramming/Frog_Jump/4_space_optimized.py b/python/DynamicProgramming/Frog_Jump/4_space_optimized.py new file mode 100644 index 00000000..81861757 --- /dev/null +++ b/python/DynamicProgramming/Frog_Jump/4_space_optimized.py @@ -0,0 +1,16 @@ +def frog_jump(heights): + prev = 0 + prev2 = 0 + + for i in range(1, len(heights)): + one = prev + abs(heights[i] - heights[i - 1]) + two = prev2 + abs(heights[i] - heights[i - 2]) if i > 1 else float('inf') + curr = min(one, two) + prev2 = prev + prev = curr + + return prev + +if __name__ == "__main__": + heights = [10, 30, 40, 20] + print(frog_jump(heights)) # Output: 30 \ No newline at end of file diff --git a/python/DynamicProgramming/Frog_Jump/readme.md b/python/DynamicProgramming/Frog_Jump/readme.md new file mode 100644 index 00000000..ee1a9186 --- /dev/null +++ b/python/DynamicProgramming/Frog_Jump/readme.md @@ -0,0 +1,36 @@ +# 🐸 Frog Jump – DSA Problem + +This folder contains four solutions to the classic **Frog Jump** problem, demonstrating a progression from naive recursion to space-optimized dynamic programming. + +--- + +## 📘 Problem Statement + +A frog is at the first stone of a river represented by an array `heights[]`. It wants to reach the last stone. The frog can jump either **1 or 2 steps forward**. The cost of a jump is the **absolute difference** in height between the current stone and the destination stone. + +**Goal:** Minimize the total cost to reach the last stone. + +--- + +## 🧠 Core Logic + +To reach stone `i`, the frog can jump from: +- Stone `i-1` → cost = `dp[i-1] + abs(heights[i] - heights[i-1])` +- Stone `i-2` → cost = `dp[i-2] + abs(heights[i] - heights[i-2])` + +--- + +## 🛠️ Approaches + +| File | Approach | Time Complexity | Space Complexity | +|------|----------|------------------|------------------| +| `1_recursion.py` | Naive recursion | O(2^n) | O(n) | +| `2_memoization.py` | Top-down DP | O(n) | O(n) | +| `3_tabulation.py` | Bottom-up DP | O(n) | O(n) | +| `4_space_optimized.py` | DP with constant space | O(n) | O(1) | + +--- + +## 🧪 Sample Input +```python +heights = [10, 30, 40, 20] \ No newline at end of file diff --git a/python/DynamicProgramming/Knapsack01.py b/python/DynamicProgramming/Knapsack01.py new file mode 100644 index 00000000..564d33d6 --- /dev/null +++ b/python/DynamicProgramming/Knapsack01.py @@ -0,0 +1,53 @@ +""" +Name: 0/1 Knapsack Problem + +Problem: Given weights and values of n items, put these items in a knapsack of capacity W +to get the maximum total value in the knapsack. You cannot break items; each item is either +taken or not taken (0/1 property). + +Link: 'https://leetcode.com/discuss/post/1152328/01-knapsack-problem-and-dynamic-programm-4had/' + +Try: 'https://leetcode.com/problems/ones-and-zeroes/solutions/95808/0-1-knapsack-in-python/' +""" + +# Solution +def knapsack(values, weights, W): + n = len(values) + dp = [[0] * (W + 1) for _ in range(n + 1)] + for i in range(1, n + 1): + for w in range(1, W + 1): + if weights[i - 1] <= w: + dp[i][w] = max(values[i - 1] + dp[i - 1][w - weights[i - 1]], dp[i - 1][w]) + else: + dp[i][w] = dp[i - 1][w] + return dp[n][W] + +# Input +if __name__ == "__main__": + values = [60, 100, 120] + weights = [10, 20, 30] + W = 50 + print("Maximum value in Knapsack:", knapsack(values, weights, W)) # Output: 220 + +# Explanation: +# - Function to compute the maximum value that can be put in a knapsack of capacity W +# using Dynamic Programming - line 14 +# - Step 1: Get number of items - line 15 +# - Step 2: Initialize a 2D DP table with zeros - line 16 +# - Step 3: Build the DP table in a bottom-up manner - line 19-22 +# - Step 3a: If current item can be included, take the max of including or skipping it - line 19-20 +# - Step 3b: If item cannot be included, copy the value from above - line 21-22 +# - Step 4: Return the value in the bottom-right cell, which is the maximum value - line 23 +# - Step 5: Example usage - line 26-29 +# - Step 6: Call the knapsack function and print the result - line 30 + + +""" +Complexity Analysis: + +Time Complexity: O(n * W) + - n = number of items, W = capacity of knapsack + +Space Complexity: O(n * W) + - 2D DP table of size (n+1) x (W+1) is used +""" diff --git a/python/DynamicProgramming/LongestCommonSubsequence.py b/python/DynamicProgramming/LongestCommonSubsequence.py new file mode 100644 index 00000000..93ce9be0 --- /dev/null +++ b/python/DynamicProgramming/LongestCommonSubsequence.py @@ -0,0 +1,50 @@ +""" +Name: Longest Common Subsequence (LCS) + +Problem: Find the length of the longest subsequence common to two strings. + +Link: https://leetcode.com/problems/longest-common-subsequence/description/ +""" + +# Solution +def lcs(X, Y): + m, n = len(X), len(Y) + dp = [[0] * (n + 1) for _ in range(m + 1)] + for i in range(1, m + 1): + for j in range(1, n + 1): + if X[i - 1] == Y[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + 1 + else: + dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + return dp[m][n] + + +# Input +if __name__ == "__main__": + X = "ABCBDAB" + Y = "BDCAB" + print("Length of LCS:", lcs(X, Y)) # Output: 4 + + +# Explanation: +# - Function to compute the length of the Longest Common Subsequence (LCS) +# between two strings X and Y using Dynamic Programming. - line 10 +# - Step 1: Get lengths of input strings - line 11 +# - Step 2: Initialize a 2D DP table with zeros - line 12 +# - Step 3: Build the DP table in a bottom-up manner - line 13-14 +# - Step 3a: If current characters match, add 1 to the result from previous indices - line 15-16 +# - Step 3b: If no match, take the max of ignoring one character from either string - line 17-18 +# - Step 4: Return the value in the bottom-right cell, which is the length of LCS - line 19 +# - Step 5: Example usage - line 23-25 +# - Step 6: Call the lcs function and print the result - line 26 + + +""" +Complexity Analysis: + +Time Complexity: O(m * n) + - m = len(X), n = len(Y) + +Space Complexity: O(m * n) + - 2D DP table of size (m+1) x (n+1) is used. +""" diff --git a/python/DynamicProgramming/LongestPalindromicSubsequence.py b/python/DynamicProgramming/LongestPalindromicSubsequence.py new file mode 100644 index 00000000..b26d587a --- /dev/null +++ b/python/DynamicProgramming/LongestPalindromicSubsequence.py @@ -0,0 +1,28 @@ +def longest_palindromic_subsequence(s: str) -> int: + n = len(s) + # dp[i][j] = length of longest palindromic subsequence in s[i..j] + dp = [[0] * n for _ in range(n)] + + # Base case: single letters are palindromes of length 1 + for i in range(n): + dp[i][i] = 1 + + # Build the table in bottom-up manner + for length in range(2, n+1): # substring lengths + for i in range(n - length + 1): + j = i + length - 1 + if s[i] == s[j]: + if length == 2: + dp[i][j] = 2 + else: + dp[i][j] = dp[i+1][j-1] + 2 + else: + dp[i][j] = max(dp[i+1][j], dp[i][j-1]) + + return dp[0][n-1] + +# Example usage +if __name__ == "__main__": + s = input("Enter string: ").strip() + length = longest_palindromic_subsequence(s) + print(f"Length of longest palindromic subsequence: {length}") diff --git a/python/DynamicProgramming/n_queens.py b/python/DynamicProgramming/n_queens.py new file mode 100644 index 00000000..b193637d --- /dev/null +++ b/python/DynamicProgramming/n_queens.py @@ -0,0 +1,51 @@ +def solve_n_queens(n): + def is_safe(board, row, col): + for i in range(col): + if board[row][i] == 1: + return False + + i, j = row, col + while i >= 0 and j >= 0: + if board[i][j] == 1: + return False + i -= 1 + j -= 1 + + i, j = row, col + while i < n and j >= 0: + if board[i][j] == 1: + return False + i += 1 + j -= 1 + + return True + + def solve(board, col): + if col >= n: + return True + + for i in range(n): + if is_safe(board, i, col): + board[i][col] = 1 + if solve(board, col + 1): + solutions.append([row[:] for row in board]) + board[i][col] = 0 + + return False + + solutions = [] + board = [[0 for x in range(n)] for y in range(n)] + solve(board, 0) + return solutions + +def print_solution(board): + for row in board: + print(' '.join(['Q' if x == 1 else '.' for x in row])) + print() + + +n = 4 +solutions = solve_n_queens(n) +for i, solution in enumerate(solutions, 1): + print(f"Solution {i}:") + print_solution(solution) \ No newline at end of file diff --git a/python/EmailValidation.py b/python/EmailValidation.py new file mode 100644 index 00000000..03cc27bd --- /dev/null +++ b/python/EmailValidation.py @@ -0,0 +1,17 @@ +import re + +def is_valid_email(email: str) -> bool: + pattern = re.compile( + r"^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+" + r"(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + r"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+" + r"[A-Za-z]{2,}$" + ) + return bool(pattern.fullmatch(email.strip())) + +email = "Enter your Email here ..." + +if is_valid_email(email): + print("✅ Valid email address") +else: + print("❌ Invalid email address") diff --git a/python/Expense_Tracker.py b/python/Expense_Tracker.py new file mode 100644 index 00000000..395896e4 --- /dev/null +++ b/python/Expense_Tracker.py @@ -0,0 +1,123 @@ +import csv +from datetime import datetime +import os + +FILE_NAME = "expenses.csv" +CATEGORIES = ["Food", "Transport", "Entertainment", "Bills", "Others"] + +# --------------------------------------------------------- +# Function to initialize CSV file if not exists +# --------------------------------------------------------- +def initialize_file(): + if not os.path.exists(FILE_NAME): + with open(FILE_NAME, "w", newline="") as file: + writer = csv.writer(file) + writer.writerow(["Date", "Category", "Amount", "Description"]) + + +# --------------------------------------------------------- +# Function to add a new expense +# --------------------------------------------------------- +def add_expense(): + date_input = input("Enter date (YYYY-MM-DD) [Leave empty for today]: ").strip() + if date_input == "": + date_input = datetime.today().strftime("%Y-%m-%d") + try: + datetime.strptime(date_input, "%Y-%m-%d") + except ValueError: + print("Invalid date format! Use YYYY-MM-DD.") + return + + print("Categories:", ", ".join(CATEGORIES)) + category = input("Enter category: ").strip().title() + if category not in CATEGORIES: + print("Invalid category! Defaulting to 'Others'.") + category = "Others" + + try: + amount = float(input("Enter amount: ").strip()) + except ValueError: + print("Invalid amount! Must be a number.") + return + + description = input("Enter description (optional): ").strip() + + with open(FILE_NAME, "a", newline="") as file: + writer = csv.writer(file) + writer.writerow([date_input, category, amount, description]) + + print("Expense added successfully!\n") + + +# --------------------------------------------------------- +# Function to view all expenses +# --------------------------------------------------------- +def view_expenses(): + if not os.path.exists(FILE_NAME): + print("No expenses recorded yet.") + return + + print("\nAll Expenses:\n") + total = 0 + with open(FILE_NAME, "r") as file: + reader = csv.DictReader(file) + for row in reader: + print(f"{row['Date']} | {row['Category']} | ${row['Amount']} | {row['Description']}") + total += float(row['Amount']) + print(f"\nTotal Spent: ${total:.2f}\n") + + +# --------------------------------------------------------- +# Function to view expenses filtered by category +# --------------------------------------------------------- +def view_by_category(): + category = input("Enter category to filter: ").strip().title() + if category not in CATEGORIES: + print("Invalid category! Showing 'Others' instead.") + category = "Others" + + total = 0 + found = False + print(f"\nExpenses for category: {category}\n") + with open(FILE_NAME, "r") as file: + reader = csv.DictReader(file) + for row in reader: + if row["Category"] == category: + print(f"{row['Date']} | ${row['Amount']} | {row['Description']}") + total += float(row["Amount"]) + found = True + + if not found: + print("No expenses found for this category.") + else: + print(f"\nTotal Spent in {category}: ${total:.2f}\n") + + +# --------------------------------------------------------- +# Main Menu +# --------------------------------------------------------- +def main(): + initialize_file() + while True: + print("===== Expense Tracker Menu =====") + print("1. Add Expense") + print("2. View All Expenses") + print("3. View Expenses by Category") + print("4. Exit") + choice = input("Enter your choice: ").strip() + + if choice == "1": + add_expense() + elif choice == "2": + view_expenses() + elif choice == "3": + view_by_category() + elif choice == "4": + print("Exiting... Goodbye!") + break + else: + print("Invalid choice! Please select 1-4.\n") + + +if __name__ == "__main__": + main() diff --git a/python/FileSystem_Organizer.py b/python/FileSystem_Organizer.py new file mode 100644 index 00000000..e7d5b2da --- /dev/null +++ b/python/FileSystem_Organizer.py @@ -0,0 +1,115 @@ +import os +import shutil +from tqdm import tqdm +from datetime import datetime +import sys + +# --------------------------------------------------------- +# File System Organizer +# --------------------------------------------------------- +# This script organizes files in a given directory +# into categorized folders such as Images, Videos, Documents, etc. +# --------------------------------------------------------- + + +# Define file type categories +CATEGORIES = { + "Images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg"], + "Videos": [".mp4", ".mkv", ".mov", ".avi", ".flv", ".wmv"], + "Documents": [".pdf", ".docx", ".doc", ".txt", ".pptx", ".xlsx"], + "Code": [".py", ".js", ".cpp", ".java", ".html", ".css", ".ts"], + "Archives": [".zip", ".rar", ".7z", ".tar", ".gz"], + "Audio": [".mp3", ".wav", ".flac", ".m4a"] +} + +LOG_FILE = "organizer_log.txt" + + +def get_category(filename): + """Return the category of a file based on its extension.""" + _, ext = os.path.splitext(filename.lower()) + for category, extensions in CATEGORIES.items(): + if ext in extensions: + return category + return "Others" + + +def log_action(src, dest): + """Log each file movement for future undo operations.""" + with open(LOG_FILE, "a") as log: + log.write(f"{datetime.now()} | {src} -> {dest}\n") + + +def organize_directory(directory): + """Organize files inside the given directory.""" + if not os.path.exists(directory): + print("Error: The provided directory does not exist.") + return + + files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))] + + if not files: + print("No files found in this directory.") + return + + print(f"Organizing {len(files)} files from: {directory}\n") + + for file in tqdm(files, desc="Organizing files"): + src_path = os.path.join(directory, file) + category = get_category(file) + dest_folder = os.path.join(directory, category) + os.makedirs(dest_folder, exist_ok=True) + dest_path = os.path.join(dest_folder, file) + + try: + shutil.move(src_path, dest_path) + log_action(src_path, dest_path) + except Exception as e: + print(f"\nError moving {file}: {e}") + + print("\nOrganization complete.") + print(f"Log file created: {os.path.abspath(LOG_FILE)}") + + +def undo_last_organization(): + """Undo the last organization using the log file.""" + if not os.path.exists(LOG_FILE): + print("No log file found. Nothing to undo.") + return + + print("Undoing last organization...\n") + + with open(LOG_FILE, "r") as log: + lines = log.readlines()[::-1] # Reverse to move files back in correct order + + for entry in tqdm(lines, desc="Restoring files"): + try: + _, path_data = entry.split("|") + src, dest = path_data.strip().split("->") + src, dest = src.strip(), dest.strip() + + if os.path.exists(dest): + shutil.move(dest, src) + except Exception: + continue + + os.remove(LOG_FILE) + print("\nUndo complete. All files restored to original locations.") + + +def main(): + if len(sys.argv) == 1: + print("\nUsage:") + print(" python FileSystem_Organizer.py ") + print(" python FileSystem_Organizer.py undo\n") + return + + if sys.argv[1].lower() == "undo": + undo_last_organization() + else: + directory = sys.argv[1] + organize_directory(directory) + + +if __name__ == "__main__": + main() diff --git a/python/Graphs/__init__.py b/python/Graphs/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python/Graphs/a_star.py b/python/Graphs/a_star.py new file mode 100644 index 00000000..1d7063cc --- /dev/null +++ b/python/Graphs/a_star.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +DIRECTIONS = [ + [-1, 0], # left + [0, -1], # down + [1, 0], # right + [0, 1], # up +] + + +# function to search the path +def search( + grid: list[list[int]], + init: list[int], + goal: list[int], + cost: int, + heuristic: list[list[int]], +) -> tuple[list[list[int]], list[list[int]]]: + """ + Search for a path on a grid avoiding obstacles. + >>> grid = [[0, 1, 0, 0, 0, 0], + ... [0, 1, 0, 0, 0, 0], + ... [0, 1, 0, 0, 0, 0], + ... [0, 1, 0, 0, 1, 0], + ... [0, 0, 0, 0, 1, 0]] + >>> init = [0, 0] + >>> goal = [len(grid) - 1, len(grid[0]) - 1] + >>> cost = 1 + >>> heuristic = [[0] * len(grid[0]) for _ in range(len(grid))] + >>> heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))] + >>> for i in range(len(grid)): + ... for j in range(len(grid[0])): + ... heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1]) + ... if grid[i][j] == 1: + ... heuristic[i][j] = 99 + >>> path, action = search(grid, init, goal, cost, heuristic) + >>> path # doctest: +NORMALIZE_WHITESPACE + [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [4, 1], [4, 2], [4, 3], [3, 3], + [2, 3], [2, 4], [2, 5], [3, 5], [4, 5]] + >>> action # doctest: +NORMALIZE_WHITESPACE + [[0, 0, 0, 0, 0, 0], [2, 0, 0, 0, 0, 0], [2, 0, 0, 0, 3, 3], + [2, 0, 0, 0, 0, 2], [2, 3, 3, 3, 0, 2]] + """ + closed = [ + [0 for col in range(len(grid[0]))] for row in range(len(grid)) + ] # the reference grid + closed[init[0]][init[1]] = 1 + action = [ + [0 for col in range(len(grid[0]))] for row in range(len(grid)) + ] # the action grid + + x = init[0] + y = init[1] + g = 0 + f = g + heuristic[x][y] # cost from starting cell to destination cell + cell = [[f, g, x, y]] + + found = False # flag that is set when search is complete + resign = False # flag set if we can't find expand + + while not found and not resign: + if len(cell) == 0: + raise ValueError("Algorithm is unable to find solution") + else: # to choose the least costliest action so as to move closer to the goal + cell.sort() + cell.reverse() + next_cell = cell.pop() + x = next_cell[2] + y = next_cell[3] + g = next_cell[1] + + if x == goal[0] and y == goal[1]: + found = True + else: + for i in range(len(DIRECTIONS)): # to try out different valid actions + x2 = x + DIRECTIONS[i][0] + y2 = y + DIRECTIONS[i][1] + if ( + x2 >= 0 + and x2 < len(grid) + and y2 >= 0 + and y2 < len(grid[0]) + and closed[x2][y2] == 0 + and grid[x2][y2] == 0 + ): + g2 = g + cost + f2 = g2 + heuristic[x2][y2] + cell.append([f2, g2, x2, y2]) + closed[x2][y2] = 1 + action[x2][y2] = i + invpath = [] + x = goal[0] + y = goal[1] + invpath.append([x, y]) # we get the reverse path from here + while x != init[0] or y != init[1]: + x2 = x - DIRECTIONS[action[x][y]][0] + y2 = y - DIRECTIONS[action[x][y]][1] + x = x2 + y = y2 + invpath.append([x, y]) + + path = [] + for i in range(len(invpath)): + path.append(invpath[len(invpath) - 1 - i]) + return path, action + + +if __name__ == "__main__": + grid = [ + [0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0], # 0 are free path whereas 1's are obstacles + [0, 1, 0, 0, 0, 0], + [0, 1, 0, 0, 1, 0], + [0, 0, 0, 0, 1, 0], + ] + + init = [0, 0] + # all coordinates are given in format [y,x] + goal = [len(grid) - 1, len(grid[0]) - 1] + cost = 1 + + # the cost map which pushes the path closer to the goal + heuristic = [[0 for row in range(len(grid[0]))] for col in range(len(grid))] + for i in range(len(grid)): + for j in range(len(grid[0])): + heuristic[i][j] = abs(i - goal[0]) + abs(j - goal[1]) + if grid[i][j] == 1: + # added extra penalty in the heuristic map + heuristic[i][j] = 99 + + path, action = search(grid, init, goal, cost, heuristic) + + print("ACTION MAP") + for i in range(len(action)): + print(action[i]) + + for i in range(len(path)): + print(path[i]) diff --git a/python/Graphs/ant_colony_optimization_algorithms.py b/python/Graphs/ant_colony_optimization_algorithms.py new file mode 100644 index 00000000..753f4c09 --- /dev/null +++ b/python/Graphs/ant_colony_optimization_algorithms.py @@ -0,0 +1,224 @@ +""" +Use an ant colony optimization algorithm to solve the travelling salesman problem (TSP) +which asks the following question: +"Given a list of cities and the distances between each pair of cities, what is the + shortest possible route that visits each city exactly once and returns to the origin + city?" + +https://en.wikipedia.org/wiki/Ant_colony_optimization_algorithms +https://en.wikipedia.org/wiki/Travelling_salesman_problem + +Author: Clark +""" + +import copy +import random + +cities = { + 0: [0, 0], + 1: [0, 5], + 2: [3, 8], + 3: [8, 10], + 4: [12, 8], + 5: [12, 4], + 6: [8, 0], + 7: [6, 2], +} + + +def main( + cities: dict[int, list[int]], + ants_num: int, + iterations_num: int, + pheromone_evaporation: float, + alpha: float, + beta: float, + q: float, # Pheromone system parameters Q, which is a constant +) -> tuple[list[int], float]: + """ + Ant colony algorithm main function + >>> main(cities=cities, ants_num=10, iterations_num=20, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + ([0, 1, 2, 3, 4, 5, 6, 7, 0], 37.909778143828696) + >>> main(cities={0: [0, 0], 1: [2, 2]}, ants_num=5, iterations_num=5, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + ([0, 1, 0], 5.656854249492381) + >>> main(cities={0: [0, 0], 1: [2, 2], 4: [4, 4]}, ants_num=5, iterations_num=5, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> main(cities={}, ants_num=5, iterations_num=5, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + Traceback (most recent call last): + ... + StopIteration + >>> main(cities={0: [0, 0], 1: [2, 2]}, ants_num=0, iterations_num=5, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + ([], inf) + >>> main(cities={0: [0, 0], 1: [2, 2]}, ants_num=5, iterations_num=0, + ... pheromone_evaporation=0.7, alpha=1.0, beta=5.0, q=10) + ([], inf) + >>> main(cities={0: [0, 0], 1: [2, 2]}, ants_num=5, iterations_num=5, + ... pheromone_evaporation=1, alpha=1.0, beta=5.0, q=10) + ([0, 1, 0], 5.656854249492381) + >>> main(cities={0: [0, 0], 1: [2, 2]}, ants_num=5, iterations_num=5, + ... pheromone_evaporation=0, alpha=1.0, beta=5.0, q=10) + ([0, 1, 0], 5.656854249492381) + """ + # Initialize the pheromone matrix + cities_num = len(cities) + pheromone = [[1.0] * cities_num] * cities_num + + best_path: list[int] = [] + best_distance = float("inf") + for _ in range(iterations_num): + ants_route = [] + for _ in range(ants_num): + unvisited_cities = copy.deepcopy(cities) + current_city = {next(iter(cities.keys())): next(iter(cities.values()))} + del unvisited_cities[next(iter(current_city.keys()))] + ant_route = [next(iter(current_city.keys()))] + while unvisited_cities: + current_city, unvisited_cities = city_select( + pheromone, current_city, unvisited_cities, alpha, beta + ) + ant_route.append(next(iter(current_city.keys()))) + ant_route.append(0) + ants_route.append(ant_route) + + pheromone, best_path, best_distance = pheromone_update( + pheromone, + cities, + pheromone_evaporation, + ants_route, + q, + best_path, + best_distance, + ) + return best_path, best_distance + + +def distance(city1: list[int], city2: list[int]) -> float: + """ + Calculate the distance between two coordinate points + >>> distance([0, 0], [3, 4] ) + 5.0 + >>> distance([0, 0], [-3, 4] ) + 5.0 + >>> distance([0, 0], [-3, -4] ) + 5.0 + """ + return (((city1[0] - city2[0]) ** 2) + ((city1[1] - city2[1]) ** 2)) ** 0.5 + + +def pheromone_update( + pheromone: list[list[float]], + cities: dict[int, list[int]], + pheromone_evaporation: float, + ants_route: list[list[int]], + q: float, # Pheromone system parameters Q, which is a constant + best_path: list[int], + best_distance: float, +) -> tuple[list[list[float]], list[int], float]: + """ + Update pheromones on the route and update the best route + >>> + >>> pheromone_update(pheromone=[[1.0, 1.0], [1.0, 1.0]], + ... cities={0: [0,0], 1: [2,2]}, pheromone_evaporation=0.7, + ... ants_route=[[0, 1, 0]], q=10, best_path=[], + ... best_distance=float("inf")) + ([[0.7, 4.235533905932737], [4.235533905932737, 0.7]], [0, 1, 0], 5.656854249492381) + >>> pheromone_update(pheromone=[], + ... cities={0: [0,0], 1: [2,2]}, pheromone_evaporation=0.7, + ... ants_route=[[0, 1, 0]], q=10, best_path=[], + ... best_distance=float("inf")) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> pheromone_update(pheromone=[[1.0, 1.0], [1.0, 1.0]], + ... cities={}, pheromone_evaporation=0.7, + ... ants_route=[[0, 1, 0]], q=10, best_path=[], + ... best_distance=float("inf")) + Traceback (most recent call last): + ... + KeyError: 0 + """ + for a in range(len(cities)): # Update the volatilization of pheromone on all routes + for b in range(len(cities)): + pheromone[a][b] *= pheromone_evaporation + for ant_route in ants_route: + total_distance = 0.0 + for i in range(len(ant_route) - 1): # Calculate total distance + total_distance += distance(cities[ant_route[i]], cities[ant_route[i + 1]]) + delta_pheromone = q / total_distance + for i in range(len(ant_route) - 1): # Update pheromones + pheromone[ant_route[i]][ant_route[i + 1]] += delta_pheromone + pheromone[ant_route[i + 1]][ant_route[i]] = pheromone[ant_route[i]][ + ant_route[i + 1] + ] + + if total_distance < best_distance: + best_path = ant_route + best_distance = total_distance + + return pheromone, best_path, best_distance + + +def city_select( + pheromone: list[list[float]], + current_city: dict[int, list[int]], + unvisited_cities: dict[int, list[int]], + alpha: float, + beta: float, +) -> tuple[dict[int, list[int]], dict[int, list[int]]]: + """ + Choose the next city for ants + >>> city_select(pheromone=[[1.0, 1.0], [1.0, 1.0]], current_city={0: [0, 0]}, + ... unvisited_cities={1: [2, 2]}, alpha=1.0, beta=5.0) + ({1: [2, 2]}, {}) + >>> city_select(pheromone=[], current_city={0: [0,0]}, + ... unvisited_cities={1: [2, 2]}, alpha=1.0, beta=5.0) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> city_select(pheromone=[[1.0, 1.0], [1.0, 1.0]], current_city={}, + ... unvisited_cities={1: [2, 2]}, alpha=1.0, beta=5.0) + Traceback (most recent call last): + ... + StopIteration + >>> city_select(pheromone=[[1.0, 1.0], [1.0, 1.0]], current_city={0: [0, 0]}, + ... unvisited_cities={}, alpha=1.0, beta=5.0) + Traceback (most recent call last): + ... + IndexError: list index out of range + """ + probabilities = [] + for city, value in unvisited_cities.items(): + city_distance = distance(value, next(iter(current_city.values()))) + probability = (pheromone[city][next(iter(current_city.keys()))] ** alpha) * ( + (1 / city_distance) ** beta + ) + probabilities.append(probability) + + chosen_city_i = random.choices( + list(unvisited_cities.keys()), weights=probabilities + )[0] + chosen_city = {chosen_city_i: unvisited_cities[chosen_city_i]} + del unvisited_cities[next(iter(chosen_city.keys()))] + return chosen_city, unvisited_cities + + +if __name__ == "__main__": + best_path, best_distance = main( + cities=cities, + ants_num=10, + iterations_num=20, + pheromone_evaporation=0.7, + alpha=1.0, + beta=5.0, + q=10, + ) + + print(f"{best_path = }") + print(f"{best_distance = }") diff --git a/python/Graphs/articulation_points.py b/python/Graphs/articulation_points.py new file mode 100644 index 00000000..0bf16e55 --- /dev/null +++ b/python/Graphs/articulation_points.py @@ -0,0 +1,55 @@ +# Finding Articulation Points in Undirected Graph +def compute_ap(graph): + n = len(graph) + out_edge_count = 0 + low = [0] * n + visited = [False] * n + is_art = [False] * n + + def dfs(root, at, parent, out_edge_count): + if parent == root: + out_edge_count += 1 + visited[at] = True + low[at] = at + + for to in graph[at]: + if to == parent: + pass + elif not visited[to]: + out_edge_count = dfs(root, to, at, out_edge_count) + low[at] = min(low[at], low[to]) + + # AP found via bridge + if at < low[to]: + is_art[at] = True + # AP found via cycle + if at == low[to]: + is_art[at] = True + else: + low[at] = min(low[at], to) + return out_edge_count + + for i in range(n): + if not visited[i]: + out_edge_count = 0 + out_edge_count = dfs(i, i, -1, out_edge_count) + is_art[i] = out_edge_count > 1 + + for x in range(len(is_art)): + if is_art[x] is True: + print(x) + + +# Adjacency list of graph +graph = { + 0: [1, 2], + 1: [0, 2], + 2: [0, 1, 3, 5], + 3: [2, 4], + 4: [3], + 5: [2, 6, 8], + 6: [5, 7], + 7: [6, 8], + 8: [5, 7], +} +compute_ap(graph) diff --git a/python/Graphs/basic_graphs.py b/python/Graphs/basic_graphs.py new file mode 100644 index 00000000..286e9b19 --- /dev/null +++ b/python/Graphs/basic_graphs.py @@ -0,0 +1,409 @@ +from collections import deque + + +def _input(message): + return input(message).strip().split(" ") + + +def initialize_unweighted_directed_graph( + node_count: int, edge_count: int +) -> dict[int, list[int]]: + graph: dict[int, list[int]] = {} + for i in range(node_count): + graph[i + 1] = [] + + for e in range(edge_count): + x, y = (int(i) for i in _input(f"Edge {e + 1}: ")) + graph[x].append(y) + return graph + + +def initialize_unweighted_undirected_graph( + node_count: int, edge_count: int +) -> dict[int, list[int]]: + graph: dict[int, list[int]] = {} + for i in range(node_count): + graph[i + 1] = [] + + for e in range(edge_count): + x, y = (int(i) for i in _input(f"Edge {e + 1}: ")) + graph[x].append(y) + graph[y].append(x) + return graph + + +def initialize_weighted_undirected_graph( + node_count: int, edge_count: int +) -> dict[int, list[tuple[int, int]]]: + graph: dict[int, list[tuple[int, int]]] = {} + for i in range(node_count): + graph[i + 1] = [] + + for e in range(edge_count): + x, y, w = (int(i) for i in _input(f"Edge {e + 1}: ")) + graph[x].append((y, w)) + graph[y].append((x, w)) + return graph + + +if __name__ == "__main__": + n, m = (int(i) for i in _input("Number of nodes and edges: ")) + + graph_choice = int( + _input( + "Press 1 or 2 or 3 \n" + "1. Unweighted directed \n" + "2. Unweighted undirected \n" + "3. Weighted undirected \n" + )[0] + ) + + g = { + 1: initialize_unweighted_directed_graph, + 2: initialize_unweighted_undirected_graph, + 3: initialize_weighted_undirected_graph, + }[graph_choice](n, m) + + +""" +-------------------------------------------------------------------------------- + Depth First Search. + Args : G - Dictionary of edges + s - Starting Node + Vars : vis - Set of visited nodes + S - Traversal Stack +-------------------------------------------------------------------------------- +""" + + +def dfs(g, s): + """ + >>> dfs({1: [2, 3], 2: [4, 5], 3: [], 4: [], 5: []}, 1) + 1 + 2 + 4 + 5 + 3 + """ + vis, _s = {s}, [s] + print(s) + while _s: + flag = 0 + for i in g[_s[-1]]: + if i not in vis: + _s.append(i) + vis.add(i) + flag = 1 + print(i) + break + if not flag: + _s.pop() + + +""" +-------------------------------------------------------------------------------- + Breadth First Search. + Args : G - Dictionary of edges + s - Starting Node + Vars : vis - Set of visited nodes + Q - Traversal Stack +-------------------------------------------------------------------------------- +""" + + +def bfs(g, s): + """ + >>> bfs({1: [2, 3], 2: [4, 5], 3: [6, 7], 4: [], 5: [8], 6: [], 7: [], 8: []}, 1) + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + """ + vis, q = {s}, deque([s]) + print(s) + while q: + u = q.popleft() + for v in g[u]: + if v not in vis: + vis.add(v) + q.append(v) + print(v) + + +""" +-------------------------------------------------------------------------------- + Dijkstra's shortest path Algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to every other node + known - Set of knows nodes + path - Preceding node in path +-------------------------------------------------------------------------------- +""" + + +def dijk(g, s): + """ + dijk({1: [(2, 7), (3, 9), (6, 14)], + 2: [(1, 7), (3, 10), (4, 15)], + 3: [(1, 9), (2, 10), (4, 11), (6, 2)], + 4: [(2, 15), (3, 11), (5, 6)], + 5: [(4, 6), (6, 9)], + 6: [(1, 14), (3, 2), (5, 9)]}, 1) + 7 + 9 + 11 + 20 + 20 + """ + dist, known, path = {s: 0}, set(), {s: 0} + while True: + if len(known) == len(g) - 1: + break + mini = 100000 + for key, value in dist: + if key not in known and value < mini: + mini = value + u = key + known.add(u) + for v in g[u]: + if v[0] not in known and dist[u] + v[1] < dist.get(v[0], 100000): + dist[v[0]] = dist[u] + v[1] + path[v[0]] = u + for key, value in dist.items(): + if key != s: + print(value) + + +""" +-------------------------------------------------------------------------------- + Topological Sort +-------------------------------------------------------------------------------- +""" + + +def topo(g, ind=None, q=None): + if q is None: + q = [1] + if ind is None: + ind = [0] * (len(g) + 1) # SInce oth Index is ignored + for u in g: + for v in g[u]: + ind[v] += 1 + q = deque() + for i in g: + if ind[i] == 0: + q.append(i) + if len(q) == 0: + return + v = q.popleft() + print(v) + for w in g[v]: + ind[w] -= 1 + if ind[w] == 0: + q.append(w) + topo(g, ind, q) + + +""" +-------------------------------------------------------------------------------- + Reading an Adjacency matrix +-------------------------------------------------------------------------------- +""" + + +def adjm(): + r""" + Reading an Adjacency matrix + + Parameters: + None + + Returns: + tuple: A tuple containing a list of edges and number of edges + + Example: + >>> # Simulate user input for 3 nodes + >>> input_data = "4\n0 1 0 1\n1 0 1 0\n0 1 0 1\n1 0 1 0\n" + >>> import sys,io + >>> original_input = sys.stdin + >>> sys.stdin = io.StringIO(input_data) # Redirect stdin for testing + >>> adjm() + ([(0, 1, 0, 1), (1, 0, 1, 0), (0, 1, 0, 1), (1, 0, 1, 0)], 4) + >>> sys.stdin = original_input # Restore original stdin + """ + n = int(input().strip()) + a = [] + for _ in range(n): + a.append(tuple(map(int, input().strip().split()))) + return a, n + + +""" +-------------------------------------------------------------------------------- + Floyd Warshall's algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to every other node + known - Set of knows nodes + path - Preceding node in path + +-------------------------------------------------------------------------------- +""" + + +def floy(a_and_n): + (a, n) = a_and_n + dist = list(a) + path = [[0] * n for i in range(n)] + for k in range(n): + for i in range(n): + for j in range(n): + if dist[i][j] > dist[i][k] + dist[k][j]: + dist[i][j] = dist[i][k] + dist[k][j] + path[i][k] = k + print(dist) + + +""" +-------------------------------------------------------------------------------- + Prim's MST Algorithm + Args : G - Dictionary of edges + s - Starting Node + Vars : dist - Dictionary storing shortest distance from s to nearest node + known - Set of knows nodes + path - Preceding node in path +-------------------------------------------------------------------------------- +""" + + +def prim(g, s): + dist, known, path = {s: 0}, set(), {s: 0} + while True: + if len(known) == len(g) - 1: + break + mini = 100000 + for key, value in dist.items(): + if key not in known and value < mini: + mini = value + u = key + known.add(u) + for v in g[u]: + if v[0] not in known and v[1] < dist.get(v[0], 100000): + dist[v[0]] = v[1] + path[v[0]] = u + return dist + + +""" +-------------------------------------------------------------------------------- + Accepting Edge list + Vars : n - Number of nodes + m - Number of edges + Returns : l - Edge list + n - Number of Nodes +-------------------------------------------------------------------------------- +""" + + +def edglist(): + r""" + Get the edges and number of edges from the user + + Parameters: + None + + Returns: + tuple: A tuple containing a list of edges and number of edges + + Example: + >>> # Simulate user input for 3 edges and 4 vertices: (1, 2), (2, 3), (3, 4) + >>> input_data = "4 3\n1 2\n2 3\n3 4\n" + >>> import sys,io + >>> original_input = sys.stdin + >>> sys.stdin = io.StringIO(input_data) # Redirect stdin for testing + >>> edglist() + ([(1, 2), (2, 3), (3, 4)], 4) + >>> sys.stdin = original_input # Restore original stdin + """ + n, m = tuple(map(int, input().split(" "))) + edges = [] + for _ in range(m): + edges.append(tuple(map(int, input().split(" ")))) + return edges, n + + +""" +-------------------------------------------------------------------------------- + Kruskal's MST Algorithm + Args : E - Edge list + n - Number of Nodes + Vars : s - Set of all nodes as unique disjoint sets (initially) +-------------------------------------------------------------------------------- +""" + + +def krusk(e_and_n): + """ + Sort edges on the basis of distance + """ + (e, n) = e_and_n + e.sort(reverse=True, key=lambda x: x[2]) + s = [{i} for i in range(1, n + 1)] + while True: + if len(s) == 1: + break + print(s) + x = e.pop() + for i in range(len(s)): + if x[0] in s[i]: + break + for j in range(len(s)): + if x[1] in s[j]: + if i == j: + break + s[j].update(s[i]) + s.pop(i) + break + + +def find_isolated_nodes(graph): + """ + Find the isolated node in the graph + + Parameters: + graph (dict): A dictionary representing a graph. + + Returns: + list: A list of isolated nodes. + + Examples: + >>> graph1 = {1: [2, 3], 2: [1, 3], 3: [1, 2], 4: []} + >>> find_isolated_nodes(graph1) + [4] + + >>> graph2 = {'A': ['B', 'C'], 'B': ['A'], 'C': ['A'], 'D': []} + >>> find_isolated_nodes(graph2) + ['D'] + + >>> graph3 = {'X': [], 'Y': [], 'Z': []} + >>> find_isolated_nodes(graph3) + ['X', 'Y', 'Z'] + + >>> graph4 = {1: [2, 3], 2: [1, 3], 3: [1, 2]} + >>> find_isolated_nodes(graph4) + [] + + >>> graph5 = {} + >>> find_isolated_nodes(graph5) + [] + """ + isolated = [] + for node in graph: + if not graph[node]: + isolated.append(node) + return isolated diff --git a/python/Graphs/bellman_ford.py b/python/Graphs/bellman_ford.py new file mode 100644 index 00000000..9ac8bae8 --- /dev/null +++ b/python/Graphs/bellman_ford.py @@ -0,0 +1,73 @@ +from __future__ import annotations + + +def print_distance(distance: list[float], src): + print(f"Vertex\tShortest Distance from vertex {src}") + for i, d in enumerate(distance): + print(f"{i}\t\t{d}") + + +def check_negative_cycle( + graph: list[dict[str, int]], distance: list[float], edge_count: int +): + for j in range(edge_count): + u, v, w = (graph[j][k] for k in ["src", "dst", "weight"]) + if distance[u] != float("inf") and distance[u] + w < distance[v]: + return True + return False + + +def bellman_ford( + graph: list[dict[str, int]], vertex_count: int, edge_count: int, src: int +) -> list[float]: + """ + Returns shortest paths from a vertex src to all + other vertices. + >>> edges = [(2, 1, -10), (3, 2, 3), (0, 3, 5), (0, 1, 4)] + >>> g = [{"src": s, "dst": d, "weight": w} for s, d, w in edges] + >>> bellman_ford(g, 4, 4, 0) + [0.0, -2.0, 8.0, 5.0] + >>> g = [{"src": s, "dst": d, "weight": w} for s, d, w in edges + [(1, 3, 5)]] + >>> bellman_ford(g, 4, 5, 0) + Traceback (most recent call last): + ... + Exception: Negative cycle found + """ + distance = [float("inf")] * vertex_count + distance[src] = 0.0 + + for _ in range(vertex_count - 1): + for j in range(edge_count): + u, v, w = (graph[j][k] for k in ["src", "dst", "weight"]) + + if distance[u] != float("inf") and distance[u] + w < distance[v]: + distance[v] = distance[u] + w + + negative_cycle_exists = check_negative_cycle(graph, distance, edge_count) + if negative_cycle_exists: + raise Exception("Negative cycle found") + + return distance + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + V = int(input("Enter number of vertices: ").strip()) + E = int(input("Enter number of edges: ").strip()) + + graph: list[dict[str, int]] = [{} for _ in range(E)] + + for i in range(E): + print("Edge ", i + 1) + src, dest, weight = ( + int(x) + for x in input("Enter source, destination, weight: ").strip().split(" ") + ) + graph[i] = {"src": src, "dst": dest, "weight": weight} + + source = int(input("\nEnter shortest path source:").strip()) + shortest_distance = bellman_ford(graph, V, E, source) + print_distance(shortest_distance, 0) diff --git a/python/Graphs/bi_directional_dijkstra.py b/python/Graphs/bi_directional_dijkstra.py new file mode 100644 index 00000000..d2c4030b --- /dev/null +++ b/python/Graphs/bi_directional_dijkstra.py @@ -0,0 +1,140 @@ +""" +Bi-directional Dijkstra's algorithm. + +A bi-directional approach is an efficient and +less time consuming optimization for Dijkstra's +searching algorithm + +Reference: shorturl.at/exHM7 +""" + +# Author: Swayam Singh (https://github.com/practice404) + +from queue import PriorityQueue +from typing import Any + +import numpy as np + + +def pass_and_relaxation( + graph: dict, + v: str, + visited_forward: set, + visited_backward: set, + cst_fwd: dict, + cst_bwd: dict, + queue: PriorityQueue, + parent: dict, + shortest_distance: float, +) -> float: + for nxt, d in graph[v]: + if nxt in visited_forward: + continue + old_cost_f = cst_fwd.get(nxt, np.inf) + new_cost_f = cst_fwd[v] + d + if new_cost_f < old_cost_f: + queue.put((new_cost_f, nxt)) + cst_fwd[nxt] = new_cost_f + parent[nxt] = v + if ( + nxt in visited_backward + and cst_fwd[v] + d + cst_bwd[nxt] < shortest_distance + ): + shortest_distance = cst_fwd[v] + d + cst_bwd[nxt] + return shortest_distance + + +def bidirectional_dij( + source: str, destination: str, graph_forward: dict, graph_backward: dict +) -> int: + """ + Bi-directional Dijkstra's algorithm. + + Returns: + shortest_path_distance (int): length of the shortest path. + + Warnings: + If the destination is not reachable, function returns -1 + + >>> bidirectional_dij("E", "F", graph_fwd, graph_bwd) + 3 + """ + shortest_path_distance = -1 + + visited_forward = set() + visited_backward = set() + cst_fwd = {source: 0} + cst_bwd = {destination: 0} + parent_forward = {source: None} + parent_backward = {destination: None} + queue_forward: PriorityQueue[Any] = PriorityQueue() + queue_backward: PriorityQueue[Any] = PriorityQueue() + + shortest_distance = np.inf + + queue_forward.put((0, source)) + queue_backward.put((0, destination)) + + if source == destination: + return 0 + + while not queue_forward.empty() and not queue_backward.empty(): + _, v_fwd = queue_forward.get() + visited_forward.add(v_fwd) + + _, v_bwd = queue_backward.get() + visited_backward.add(v_bwd) + + shortest_distance = pass_and_relaxation( + graph_forward, + v_fwd, + visited_forward, + visited_backward, + cst_fwd, + cst_bwd, + queue_forward, + parent_forward, + shortest_distance, + ) + + shortest_distance = pass_and_relaxation( + graph_backward, + v_bwd, + visited_backward, + visited_forward, + cst_bwd, + cst_fwd, + queue_backward, + parent_backward, + shortest_distance, + ) + + if cst_fwd[v_fwd] + cst_bwd[v_bwd] >= shortest_distance: + break + + if shortest_distance != np.inf: + shortest_path_distance = shortest_distance + return shortest_path_distance + + +graph_fwd = { + "B": [["C", 1]], + "C": [["D", 1]], + "D": [["F", 1]], + "E": [["B", 1], ["G", 2]], + "F": [], + "G": [["F", 1]], +} +graph_bwd = { + "B": [["E", 1]], + "C": [["B", 1]], + "D": [["C", 1]], + "F": [["D", 1], ["G", 1]], + "E": [[None, np.inf]], + "G": [["E", 2]], +} + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/bidirectional_a_star.py b/python/Graphs/bidirectional_a_star.py new file mode 100644 index 00000000..00f623de --- /dev/null +++ b/python/Graphs/bidirectional_a_star.py @@ -0,0 +1,259 @@ +""" +https://en.wikipedia.org/wiki/Bidirectional_search +""" + +from __future__ import annotations + +import time +from math import sqrt + +# 1 for manhattan, 0 for euclidean +HEURISTIC = 0 + +grid = [ + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0], # 0 are free path whereas 1's are obstacles + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0], +] + +delta = [[-1, 0], [0, -1], [1, 0], [0, 1]] # up, left, down, right + +TPosition = tuple[int, int] + + +class Node: + """ + >>> k = Node(0, 0, 4, 3, 0, None) + >>> k.calculate_heuristic() + 5.0 + >>> n = Node(1, 4, 3, 4, 2, None) + >>> n.calculate_heuristic() + 2.0 + >>> l = [k, n] + >>> n == l[0] + False + >>> l.sort() + >>> n == l[0] + True + """ + + def __init__( + self, + pos_x: int, + pos_y: int, + goal_x: int, + goal_y: int, + g_cost: int, + parent: Node | None, + ) -> None: + self.pos_x = pos_x + self.pos_y = pos_y + self.pos = (pos_y, pos_x) + self.goal_x = goal_x + self.goal_y = goal_y + self.g_cost = g_cost + self.parent = parent + self.h_cost = self.calculate_heuristic() + self.f_cost = self.g_cost + self.h_cost + + def calculate_heuristic(self) -> float: + """ + Heuristic for the A* + """ + dy = self.pos_x - self.goal_x + dx = self.pos_y - self.goal_y + if HEURISTIC == 1: + return abs(dx) + abs(dy) + else: + return sqrt(dy**2 + dx**2) + + def __lt__(self, other: Node) -> bool: + return self.f_cost < other.f_cost + + +class AStar: + """ + >>> astar = AStar((0, 0), (len(grid) - 1, len(grid[0]) - 1)) + >>> (astar.start.pos_y + delta[3][0], astar.start.pos_x + delta[3][1]) + (0, 1) + >>> [x.pos for x in astar.get_successors(astar.start)] + [(1, 0), (0, 1)] + >>> (astar.start.pos_y + delta[2][0], astar.start.pos_x + delta[2][1]) + (1, 0) + >>> astar.retrace_path(astar.start) + [(0, 0)] + >>> astar.search() # doctest: +NORMALIZE_WHITESPACE + [(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (2, 3), (3, 3), + (4, 3), (4, 4), (5, 4), (5, 5), (6, 5), (6, 6)] + """ + + def __init__(self, start: TPosition, goal: TPosition): + self.start = Node(start[1], start[0], goal[1], goal[0], 0, None) + self.target = Node(goal[1], goal[0], goal[1], goal[0], 99999, None) + + self.open_nodes = [self.start] + self.closed_nodes: list[Node] = [] + + self.reached = False + + def search(self) -> list[TPosition]: + while self.open_nodes: + # Open Nodes are sorted using __lt__ + self.open_nodes.sort() + current_node = self.open_nodes.pop(0) + + if current_node.pos == self.target.pos: + return self.retrace_path(current_node) + + self.closed_nodes.append(current_node) + successors = self.get_successors(current_node) + + for child_node in successors: + if child_node in self.closed_nodes: + continue + + if child_node not in self.open_nodes: + self.open_nodes.append(child_node) + else: + # retrieve the best current path + better_node = self.open_nodes.pop(self.open_nodes.index(child_node)) + + if child_node.g_cost < better_node.g_cost: + self.open_nodes.append(child_node) + else: + self.open_nodes.append(better_node) + + return [self.start.pos] + + def get_successors(self, parent: Node) -> list[Node]: + """ + Returns a list of successors (both in the grid and free spaces) + """ + successors = [] + for action in delta: + pos_x = parent.pos_x + action[1] + pos_y = parent.pos_y + action[0] + if not (0 <= pos_x <= len(grid[0]) - 1 and 0 <= pos_y <= len(grid) - 1): + continue + + if grid[pos_y][pos_x] != 0: + continue + + successors.append( + Node( + pos_x, + pos_y, + self.target.pos_y, + self.target.pos_x, + parent.g_cost + 1, + parent, + ) + ) + return successors + + def retrace_path(self, node: Node | None) -> list[TPosition]: + """ + Retrace the path from parents to parents until start node + """ + current_node = node + path = [] + while current_node is not None: + path.append((current_node.pos_y, current_node.pos_x)) + current_node = current_node.parent + path.reverse() + return path + + +class BidirectionalAStar: + """ + >>> bd_astar = BidirectionalAStar((0, 0), (len(grid) - 1, len(grid[0]) - 1)) + >>> bd_astar.fwd_astar.start.pos == bd_astar.bwd_astar.target.pos + True + >>> bd_astar.retrace_bidirectional_path(bd_astar.fwd_astar.start, + ... bd_astar.bwd_astar.start) + [(0, 0)] + >>> bd_astar.search() # doctest: +NORMALIZE_WHITESPACE + [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (2, 4), + (2, 5), (3, 5), (4, 5), (5, 5), (5, 6), (6, 6)] + """ + + def __init__(self, start: TPosition, goal: TPosition) -> None: + self.fwd_astar = AStar(start, goal) + self.bwd_astar = AStar(goal, start) + self.reached = False + + def search(self) -> list[TPosition]: + while self.fwd_astar.open_nodes or self.bwd_astar.open_nodes: + self.fwd_astar.open_nodes.sort() + self.bwd_astar.open_nodes.sort() + current_fwd_node = self.fwd_astar.open_nodes.pop(0) + current_bwd_node = self.bwd_astar.open_nodes.pop(0) + + if current_bwd_node.pos == current_fwd_node.pos: + return self.retrace_bidirectional_path( + current_fwd_node, current_bwd_node + ) + + self.fwd_astar.closed_nodes.append(current_fwd_node) + self.bwd_astar.closed_nodes.append(current_bwd_node) + + self.fwd_astar.target = current_bwd_node + self.bwd_astar.target = current_fwd_node + + successors = { + self.fwd_astar: self.fwd_astar.get_successors(current_fwd_node), + self.bwd_astar: self.bwd_astar.get_successors(current_bwd_node), + } + + for astar in [self.fwd_astar, self.bwd_astar]: + for child_node in successors[astar]: + if child_node in astar.closed_nodes: + continue + + if child_node not in astar.open_nodes: + astar.open_nodes.append(child_node) + else: + # retrieve the best current path + better_node = astar.open_nodes.pop( + astar.open_nodes.index(child_node) + ) + + if child_node.g_cost < better_node.g_cost: + astar.open_nodes.append(child_node) + else: + astar.open_nodes.append(better_node) + + return [self.fwd_astar.start.pos] + + def retrace_bidirectional_path( + self, fwd_node: Node, bwd_node: Node + ) -> list[TPosition]: + fwd_path = self.fwd_astar.retrace_path(fwd_node) + bwd_path = self.bwd_astar.retrace_path(bwd_node) + bwd_path.pop() + bwd_path.reverse() + path = fwd_path + bwd_path + return path + + +if __name__ == "__main__": + # all coordinates are given in format [y,x] + init = (0, 0) + goal = (len(grid) - 1, len(grid[0]) - 1) + for elem in grid: + print(elem) + + start_time = time.time() + a_star = AStar(init, goal) + path = a_star.search() + end_time = time.time() - start_time + print(f"AStar execution time = {end_time:f} seconds") + + bd_start_time = time.time() + bidir_astar = BidirectionalAStar(init, goal) + bd_end_time = time.time() - bd_start_time + print(f"BidirectionalAStar execution time = {bd_end_time:f} seconds") diff --git a/python/Graphs/bidirectional_breadth_first_search.py b/python/Graphs/bidirectional_breadth_first_search.py new file mode 100644 index 00000000..71c5a9af --- /dev/null +++ b/python/Graphs/bidirectional_breadth_first_search.py @@ -0,0 +1,188 @@ +""" +https://en.wikipedia.org/wiki/Bidirectional_search +""" + +from __future__ import annotations + +import time + +Path = list[tuple[int, int]] + +grid = [ + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0], # 0 are free path whereas 1's are obstacles + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0], +] + +delta = [[-1, 0], [0, -1], [1, 0], [0, 1]] # up, left, down, right + + +class Node: + def __init__( + self, pos_x: int, pos_y: int, goal_x: int, goal_y: int, parent: Node | None + ): + self.pos_x = pos_x + self.pos_y = pos_y + self.pos = (pos_y, pos_x) + self.goal_x = goal_x + self.goal_y = goal_y + self.parent = parent + + +class BreadthFirstSearch: + """ + # Comment out slow pytests... + # 9.15s call graphs/bidirectional_breadth_first_search.py:: \ + # graphs.bidirectional_breadth_first_search.BreadthFirstSearch + # >>> bfs = BreadthFirstSearch((0, 0), (len(grid) - 1, len(grid[0]) - 1)) + # >>> (bfs.start.pos_y + delta[3][0], bfs.start.pos_x + delta[3][1]) + (0, 1) + # >>> [x.pos for x in bfs.get_successors(bfs.start)] + [(1, 0), (0, 1)] + # >>> (bfs.start.pos_y + delta[2][0], bfs.start.pos_x + delta[2][1]) + (1, 0) + # >>> bfs.retrace_path(bfs.start) + [(0, 0)] + # >>> bfs.search() # doctest: +NORMALIZE_WHITESPACE + [(0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (4, 1), + (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (6, 5), (6, 6)] + """ + + def __init__(self, start: tuple[int, int], goal: tuple[int, int]): + self.start = Node(start[1], start[0], goal[1], goal[0], None) + self.target = Node(goal[1], goal[0], goal[1], goal[0], None) + + self.node_queue = [self.start] + self.reached = False + + def search(self) -> Path | None: + while self.node_queue: + current_node = self.node_queue.pop(0) + + if current_node.pos == self.target.pos: + self.reached = True + return self.retrace_path(current_node) + + successors = self.get_successors(current_node) + + for node in successors: + self.node_queue.append(node) + + if not self.reached: + return [self.start.pos] + return None + + def get_successors(self, parent: Node) -> list[Node]: + """ + Returns a list of successors (both in the grid and free spaces) + """ + successors = [] + for action in delta: + pos_x = parent.pos_x + action[1] + pos_y = parent.pos_y + action[0] + if not (0 <= pos_x <= len(grid[0]) - 1 and 0 <= pos_y <= len(grid) - 1): + continue + + if grid[pos_y][pos_x] != 0: + continue + + successors.append( + Node(pos_x, pos_y, self.target.pos_y, self.target.pos_x, parent) + ) + return successors + + def retrace_path(self, node: Node | None) -> Path: + """ + Retrace the path from parents to parents until start node + """ + current_node = node + path = [] + while current_node is not None: + path.append((current_node.pos_y, current_node.pos_x)) + current_node = current_node.parent + path.reverse() + return path + + +class BidirectionalBreadthFirstSearch: + """ + >>> bd_bfs = BidirectionalBreadthFirstSearch((0, 0), (len(grid) - 1, + ... len(grid[0]) - 1)) + >>> bd_bfs.fwd_bfs.start.pos == bd_bfs.bwd_bfs.target.pos + True + >>> bd_bfs.retrace_bidirectional_path(bd_bfs.fwd_bfs.start, + ... bd_bfs.bwd_bfs.start) + [(0, 0)] + >>> bd_bfs.search() # doctest: +NORMALIZE_WHITESPACE + [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 3), + (2, 4), (3, 4), (3, 5), (3, 6), (4, 6), (5, 6), (6, 6)] + """ + + def __init__(self, start, goal): + self.fwd_bfs = BreadthFirstSearch(start, goal) + self.bwd_bfs = BreadthFirstSearch(goal, start) + self.reached = False + + def search(self) -> Path | None: + while self.fwd_bfs.node_queue or self.bwd_bfs.node_queue: + current_fwd_node = self.fwd_bfs.node_queue.pop(0) + current_bwd_node = self.bwd_bfs.node_queue.pop(0) + + if current_bwd_node.pos == current_fwd_node.pos: + self.reached = True + return self.retrace_bidirectional_path( + current_fwd_node, current_bwd_node + ) + + self.fwd_bfs.target = current_bwd_node + self.bwd_bfs.target = current_fwd_node + + successors = { + self.fwd_bfs: self.fwd_bfs.get_successors(current_fwd_node), + self.bwd_bfs: self.bwd_bfs.get_successors(current_bwd_node), + } + + for bfs in [self.fwd_bfs, self.bwd_bfs]: + for node in successors[bfs]: + bfs.node_queue.append(node) + + if not self.reached: + return [self.fwd_bfs.start.pos] + return None + + def retrace_bidirectional_path(self, fwd_node: Node, bwd_node: Node) -> Path: + fwd_path = self.fwd_bfs.retrace_path(fwd_node) + bwd_path = self.bwd_bfs.retrace_path(bwd_node) + bwd_path.pop() + bwd_path.reverse() + path = fwd_path + bwd_path + return path + + +if __name__ == "__main__": + # all coordinates are given in format [y,x] + import doctest + + doctest.testmod() + init = (0, 0) + goal = (len(grid) - 1, len(grid[0]) - 1) + for elem in grid: + print(elem) + + start_bfs_time = time.time() + bfs = BreadthFirstSearch(init, goal) + path = bfs.search() + bfs_time = time.time() - start_bfs_time + + print("Unidirectional BFS computation time : ", bfs_time) + + start_bd_bfs_time = time.time() + bd_bfs = BidirectionalBreadthFirstSearch(init, goal) + bd_path = bd_bfs.search() + bd_bfs_time = time.time() - start_bd_bfs_time + + print("Bidirectional BFS computation time : ", bd_bfs_time) diff --git a/python/Graphs/bidirectional_search.py b/python/Graphs/bidirectional_search.py new file mode 100644 index 00000000..b3ff9f75 --- /dev/null +++ b/python/Graphs/bidirectional_search.py @@ -0,0 +1,201 @@ +""" +Bidirectional Search Algorithm. + +This algorithm searches from both the source and target nodes simultaneously, +meeting somewhere in the middle. This approach can significantly reduce the +search space compared to a traditional one-directional search. + +Time Complexity: O(b^(d/2)) where b is the branching factor and d is the depth +Space Complexity: O(b^(d/2)) + +https://en.wikipedia.org/wiki/Bidirectional_search +""" + +from collections import deque + + +def expand_search( + graph: dict[int, list[int]], + queue: deque[int], + parents: dict[int, int | None], + opposite_direction_parents: dict[int, int | None], +) -> int | None: + if not queue: + return None + + current = queue.popleft() + for neighbor in graph[current]: + if neighbor in parents: + continue + + parents[neighbor] = current + queue.append(neighbor) + + # Check if this creates an intersection + if neighbor in opposite_direction_parents: + return neighbor + + return None + + +def construct_path(current: int | None, parents: dict[int, int | None]) -> list[int]: + path: list[int] = [] + while current is not None: + path.append(current) + current = parents[current] + return path + + +def bidirectional_search( + graph: dict[int, list[int]], start: int, goal: int +) -> list[int] | None: + """ + Perform bidirectional search on a graph to find the shortest path. + + Args: + graph: A dictionary where keys are nodes and values are lists of adjacent nodes + start: The starting node + goal: The target node + + Returns: + A list representing the path from start to goal, or None if no path exists + + Examples: + >>> graph = { + ... 0: [1, 2], + ... 1: [0, 3, 4], + ... 2: [0, 5, 6], + ... 3: [1, 7], + ... 4: [1, 8], + ... 5: [2, 9], + ... 6: [2, 10], + ... 7: [3, 11], + ... 8: [4, 11], + ... 9: [5, 11], + ... 10: [6, 11], + ... 11: [7, 8, 9, 10], + ... } + >>> bidirectional_search(graph=graph, start=0, goal=11) + [0, 1, 3, 7, 11] + >>> bidirectional_search(graph=graph, start=5, goal=5) + [5] + >>> disconnected_graph = { + ... 0: [1, 2], + ... 1: [0], + ... 2: [0], + ... 3: [4], + ... 4: [3], + ... } + >>> bidirectional_search(graph=disconnected_graph, start=0, goal=3) is None + True + """ + if start == goal: + return [start] + + # Check if start and goal are in the graph + if start not in graph or goal not in graph: + return None + + # Initialize forward and backward search dictionaries + # Each maps a node to its parent in the search + forward_parents: dict[int, int | None] = {start: None} + backward_parents: dict[int, int | None] = {goal: None} + + # Initialize forward and backward search queues + forward_queue = deque([start]) + backward_queue = deque([goal]) + + # Intersection node (where the two searches meet) + intersection = None + + # Continue until both queues are empty or an intersection is found + while forward_queue and backward_queue and intersection is None: + # Expand forward search + intersection = expand_search( + graph=graph, + queue=forward_queue, + parents=forward_parents, + opposite_direction_parents=backward_parents, + ) + + # If no intersection found, expand backward search + if intersection is not None: + break + + intersection = expand_search( + graph=graph, + queue=backward_queue, + parents=backward_parents, + opposite_direction_parents=forward_parents, + ) + + # If no intersection found, there's no path + if intersection is None: + return None + + # Construct path from start to intersection + forward_path: list[int] = construct_path( + current=intersection, parents=forward_parents + ) + forward_path.reverse() + + # Construct path from intersection to goal + backward_path: list[int] = construct_path( + current=backward_parents[intersection], parents=backward_parents + ) + + # Return the complete path + return forward_path + backward_path + + +def main() -> None: + """ + Run example of bidirectional search algorithm. + + Examples: + >>> main() # doctest: +NORMALIZE_WHITESPACE + Path from 0 to 11: [0, 1, 3, 7, 11] + Path from 5 to 5: [5] + Path from 0 to 3: None + """ + # Example graph represented as an adjacency list + example_graph = { + 0: [1, 2], + 1: [0, 3, 4], + 2: [0, 5, 6], + 3: [1, 7], + 4: [1, 8], + 5: [2, 9], + 6: [2, 10], + 7: [3, 11], + 8: [4, 11], + 9: [5, 11], + 10: [6, 11], + 11: [7, 8, 9, 10], + } + + # Test case 1: Path exists + start, goal = 0, 11 + path = bidirectional_search(graph=example_graph, start=start, goal=goal) + print(f"Path from {start} to {goal}: {path}") + + # Test case 2: Start and goal are the same + start, goal = 5, 5 + path = bidirectional_search(graph=example_graph, start=start, goal=goal) + print(f"Path from {start} to {goal}: {path}") + + # Test case 3: No path exists (disconnected graph) + disconnected_graph = { + 0: [1, 2], + 1: [0], + 2: [0], + 3: [4], + 4: [3], + } + start, goal = 0, 3 + path = bidirectional_search(graph=disconnected_graph, start=start, goal=goal) + print(f"Path from {start} to {goal}: {path}") + + +if __name__ == "__main__": + main() diff --git a/python/Graphs/boruvka.py b/python/Graphs/boruvka.py new file mode 100644 index 00000000..3dc059ff --- /dev/null +++ b/python/Graphs/boruvka.py @@ -0,0 +1,176 @@ +"""Borůvka's algorithm. + +Determines the minimum spanning tree (MST) of a graph using the Borůvka's algorithm. +Borůvka's algorithm is a greedy algorithm for finding a minimum spanning tree in a +connected graph, or a minimum spanning forest if a graph that is not connected. + +The time complexity of this algorithm is O(ELogV), where E represents the number +of edges, while V represents the number of nodes. +O(number_of_edges Log number_of_nodes) + +The space complexity of this algorithm is O(V + E), since we have to keep a couple +of lists whose sizes are equal to the number of nodes, as well as keep all the +edges of a graph inside of the data structure itself. + +Borůvka's algorithm gives us pretty much the same result as other MST Algorithms - +they all find the minimum spanning tree, and the time complexity is approximately +the same. + +One advantage that Borůvka's algorithm has compared to the alternatives is that it +doesn't need to presort the edges or maintain a priority queue in order to find the +minimum spanning tree. +Even though that doesn't help its complexity, since it still passes the edges logE +times, it is a bit simpler to code. + +Details: https://en.wikipedia.org/wiki/Bor%C5%AFvka%27s_algorithm +""" + +from __future__ import annotations + +from typing import Any + + +class Graph: + def __init__(self, num_of_nodes: int) -> None: + """ + Arguments: + num_of_nodes - the number of nodes in the graph + Attributes: + m_num_of_nodes - the number of nodes in the graph. + m_edges - the list of edges. + m_component - the dictionary which stores the index of the component which + a node belongs to. + """ + + self.m_num_of_nodes = num_of_nodes + self.m_edges: list[list[int]] = [] + self.m_component: dict[int, int] = {} + + def add_edge(self, u_node: int, v_node: int, weight: int) -> None: + """Adds an edge in the format [first, second, edge weight] to graph.""" + + self.m_edges.append([u_node, v_node, weight]) + + def find_component(self, u_node: int) -> int: + """Propagates a new component throughout a given component.""" + + if self.m_component[u_node] == u_node: + return u_node + return self.find_component(self.m_component[u_node]) + + def set_component(self, u_node: int) -> None: + """Finds the component index of a given node""" + + if self.m_component[u_node] != u_node: + for k in self.m_component: + self.m_component[k] = self.find_component(k) + + def union(self, component_size: list[int], u_node: int, v_node: int) -> None: + """Union finds the roots of components for two nodes, compares the components + in terms of size, and attaches the smaller one to the larger one to form + single component""" + + if component_size[u_node] <= component_size[v_node]: + self.m_component[u_node] = v_node + component_size[v_node] += component_size[u_node] + self.set_component(u_node) + + elif component_size[u_node] >= component_size[v_node]: + self.m_component[v_node] = self.find_component(u_node) + component_size[u_node] += component_size[v_node] + self.set_component(v_node) + + def boruvka(self) -> None: + """Performs Borůvka's algorithm to find MST.""" + + # Initialize additional lists required to algorithm. + component_size = [] + mst_weight = 0 + + minimum_weight_edge: list[Any] = [-1] * self.m_num_of_nodes + + # A list of components (initialized to all of the nodes) + for node in range(self.m_num_of_nodes): + self.m_component.update({node: node}) + component_size.append(1) + + num_of_components = self.m_num_of_nodes + + while num_of_components > 1: + for edge in self.m_edges: + u, v, w = edge + + u_component = self.m_component[u] + v_component = self.m_component[v] + + if u_component != v_component: + """If the current minimum weight edge of component u doesn't + exist (is -1), or if it's greater than the edge we're + observing right now, we will assign the value of the edge + we're observing to it. + + If the current minimum weight edge of component v doesn't + exist (is -1), or if it's greater than the edge we're + observing right now, we will assign the value of the edge + we're observing to it""" + + for component in (u_component, v_component): + if ( + minimum_weight_edge[component] == -1 + or minimum_weight_edge[component][2] > w + ): + minimum_weight_edge[component] = [u, v, w] + + for edge in minimum_weight_edge: + if isinstance(edge, list): + u, v, w = edge + + u_component = self.m_component[u] + v_component = self.m_component[v] + + if u_component != v_component: + mst_weight += w + self.union(component_size, u_component, v_component) + print(f"Added edge [{u} - {v}]\nAdded weight: {w}\n") + num_of_components -= 1 + + minimum_weight_edge = [-1] * self.m_num_of_nodes + print(f"The total weight of the minimal spanning tree is: {mst_weight}") + + +def test_vector() -> None: + """ + >>> g = Graph(8) + >>> for u_v_w in ((0, 1, 10), (0, 2, 6), (0, 3, 5), (1, 3, 15), (2, 3, 4), + ... (3, 4, 8), (4, 5, 10), (4, 6, 6), (4, 7, 5), (5, 7, 15), (6, 7, 4)): + ... g.add_edge(*u_v_w) + >>> g.boruvka() + Added edge [0 - 3] + Added weight: 5 + + Added edge [0 - 1] + Added weight: 10 + + Added edge [2 - 3] + Added weight: 4 + + Added edge [4 - 7] + Added weight: 5 + + Added edge [4 - 5] + Added weight: 10 + + Added edge [6 - 7] + Added weight: 4 + + Added edge [3 - 4] + Added weight: 8 + + The total weight of the minimal spanning tree is: 46 + """ + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/breadth_first_search.py b/python/Graphs/breadth_first_search.py new file mode 100644 index 00000000..cab79be3 --- /dev/null +++ b/python/Graphs/breadth_first_search.py @@ -0,0 +1,93 @@ +#!/usr/bin/python + +"""Author: OMKAR PATHAK""" + +from __future__ import annotations + +from queue import Queue + + +class Graph: + def __init__(self) -> None: + self.vertices: dict[int, list[int]] = {} + + def print_graph(self) -> None: + """ + prints adjacency list representation of graaph + >>> g = Graph() + >>> g.print_graph() + >>> g.add_edge(0, 1) + >>> g.print_graph() + 0 : 1 + """ + for i in self.vertices: + print(i, " : ", " -> ".join([str(j) for j in self.vertices[i]])) + + def add_edge(self, from_vertex: int, to_vertex: int) -> None: + """ + adding the edge between two vertices + >>> g = Graph() + >>> g.print_graph() + >>> g.add_edge(0, 1) + >>> g.print_graph() + 0 : 1 + """ + if from_vertex in self.vertices: + self.vertices[from_vertex].append(to_vertex) + else: + self.vertices[from_vertex] = [to_vertex] + + def bfs(self, start_vertex: int) -> set[int]: + """ + >>> g = Graph() + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 2) + >>> g.add_edge(1, 2) + >>> g.add_edge(2, 0) + >>> g.add_edge(2, 3) + >>> g.add_edge(3, 3) + >>> sorted(g.bfs(2)) + [0, 1, 2, 3] + """ + # initialize set for storing already visited vertices + visited = set() + + # create a first in first out queue to store all the vertices for BFS + queue: Queue = Queue() + + # mark the source node as visited and enqueue it + visited.add(start_vertex) + queue.put(start_vertex) + + while not queue.empty(): + vertex = queue.get() + + # loop through all adjacent vertex and enqueue it if not yet visited + for adjacent_vertex in self.vertices[vertex]: + if adjacent_vertex not in visited: + queue.put(adjacent_vertex) + visited.add(adjacent_vertex) + return visited + + +if __name__ == "__main__": + from doctest import testmod + + testmod(verbose=True) + + g = Graph() + g.add_edge(0, 1) + g.add_edge(0, 2) + g.add_edge(1, 2) + g.add_edge(2, 0) + g.add_edge(2, 3) + g.add_edge(3, 3) + + g.print_graph() + # 0 : 1 -> 2 + # 1 : 2 + # 2 : 0 -> 3 + # 3 : 3 + + assert sorted(g.bfs(2)) == [0, 1, 2, 3] diff --git a/python/Graphs/breadth_first_search_2.py b/python/Graphs/breadth_first_search_2.py new file mode 100644 index 00000000..ccadfa34 --- /dev/null +++ b/python/Graphs/breadth_first_search_2.py @@ -0,0 +1,88 @@ +""" +https://en.wikipedia.org/wiki/Breadth-first_search +pseudo-code: +breadth_first_search(graph G, start vertex s): +// all nodes initially unexplored +mark s as explored +let Q = queue data structure, initialized with s +while Q is non-empty: + remove the first node of Q, call it v + for each edge(v, w): // for w in graph[v] + if w unexplored: + mark w as explored + add w to Q (at the end) +""" + +from __future__ import annotations + +from collections import deque +from queue import Queue +from timeit import timeit + +G = { + "A": ["B", "C"], + "B": ["A", "D", "E"], + "C": ["A", "F"], + "D": ["B"], + "E": ["B", "F"], + "F": ["C", "E"], +} + + +def breadth_first_search(graph: dict, start: str) -> list[str]: + """ + Implementation of breadth first search using queue.Queue. + + >>> ''.join(breadth_first_search(G, 'A')) + 'ABCDEF' + """ + explored = {start} + result = [start] + queue: Queue = Queue() + queue.put(start) + while not queue.empty(): + v = queue.get() + for w in graph[v]: + if w not in explored: + explored.add(w) + result.append(w) + queue.put(w) + return result + + +def breadth_first_search_with_deque(graph: dict, start: str) -> list[str]: + """ + Implementation of breadth first search using collection.queue. + + >>> ''.join(breadth_first_search_with_deque(G, 'A')) + 'ABCDEF' + """ + visited = {start} + result = [start] + queue = deque([start]) + while queue: + v = queue.popleft() + for child in graph[v]: + if child not in visited: + visited.add(child) + result.append(child) + queue.append(child) + return result + + +def benchmark_function(name: str) -> None: + setup = f"from __main__ import G, {name}" + number = 10000 + res = timeit(f"{name}(G, 'A')", setup=setup, number=number) + print(f"{name:<35} finished {number} runs in {res:.5f} seconds") + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + benchmark_function("breadth_first_search") + benchmark_function("breadth_first_search_with_deque") + # breadth_first_search finished 10000 runs in 0.20999 seconds + # breadth_first_search_with_deque finished 10000 runs in 0.01421 seconds diff --git a/python/Graphs/breadth_first_search_shortest_path.py b/python/Graphs/breadth_first_search_shortest_path.py new file mode 100644 index 00000000..c06440bc --- /dev/null +++ b/python/Graphs/breadth_first_search_shortest_path.py @@ -0,0 +1,90 @@ +"""Breath First Search (BFS) can be used when finding the shortest path +from a given source node to a target node in an unweighted graph. +""" + +from __future__ import annotations + +graph = { + "A": ["B", "C", "E"], + "B": ["A", "D", "E"], + "C": ["A", "F", "G"], + "D": ["B"], + "E": ["A", "B", "D"], + "F": ["C"], + "G": ["C"], +} + + +class Graph: + def __init__(self, graph: dict[str, list[str]], source_vertex: str) -> None: + """ + Graph is implemented as dictionary of adjacency lists. Also, + Source vertex have to be defined upon initialization. + """ + self.graph = graph + # mapping node to its parent in resulting breadth first tree + self.parent: dict[str, str | None] = {} + self.source_vertex = source_vertex + + def breath_first_search(self) -> None: + """ + This function is a helper for running breath first search on this graph. + >>> g = Graph(graph, "G") + >>> g.breath_first_search() + >>> g.parent + {'G': None, 'C': 'G', 'A': 'C', 'F': 'C', 'B': 'A', 'E': 'A', 'D': 'B'} + """ + visited = {self.source_vertex} + self.parent[self.source_vertex] = None + queue = [self.source_vertex] # first in first out queue + + while queue: + vertex = queue.pop(0) + for adjacent_vertex in self.graph[vertex]: + if adjacent_vertex not in visited: + visited.add(adjacent_vertex) + self.parent[adjacent_vertex] = vertex + queue.append(adjacent_vertex) + + def shortest_path(self, target_vertex: str) -> str: + """ + This shortest path function returns a string, describing the result: + 1.) No path is found. The string is a human readable message to indicate this. + 2.) The shortest path is found. The string is in the form + `v1(->v2->v3->...->vn)`, where v1 is the source vertex and vn is the target + vertex, if it exists separately. + + >>> g = Graph(graph, "G") + >>> g.breath_first_search() + + Case 1 - No path is found. + >>> g.shortest_path("Foo") + Traceback (most recent call last): + ... + ValueError: No path from vertex: G to vertex: Foo + + Case 2 - The path is found. + >>> g.shortest_path("D") + 'G->C->A->B->D' + >>> g.shortest_path("G") + 'G' + """ + if target_vertex == self.source_vertex: + return self.source_vertex + + target_vertex_parent = self.parent.get(target_vertex) + if target_vertex_parent is None: + msg = ( + f"No path from vertex: {self.source_vertex} to vertex: {target_vertex}" + ) + raise ValueError(msg) + + return self.shortest_path(target_vertex_parent) + f"->{target_vertex}" + + +if __name__ == "__main__": + g = Graph(graph, "G") + g.breath_first_search() + print(g.shortest_path("D")) + print(g.shortest_path("G")) + print(g.shortest_path("Foo")) diff --git a/python/Graphs/breadth_first_search_shortest_path_2.py b/python/Graphs/breadth_first_search_shortest_path_2.py new file mode 100644 index 00000000..efba9b7b --- /dev/null +++ b/python/Graphs/breadth_first_search_shortest_path_2.py @@ -0,0 +1,113 @@ +"""Breadth-first search the shortest path implementations. +doctest: +python -m doctest -v breadth_first_search_shortest_path_2.py +Manual test: +python breadth_first_search_shortest_path_2.py +""" + +from collections import deque + +demo_graph = { + "A": ["B", "C", "E"], + "B": ["A", "D", "E"], + "C": ["A", "F", "G"], + "D": ["B"], + "E": ["A", "B", "D"], + "F": ["C"], + "G": ["C"], +} + + +def bfs_shortest_path(graph: dict, start, goal) -> list[str]: + """Find the shortest path between `start` and `goal` nodes. + Args: + graph (dict): node/list of neighboring nodes key/value pairs. + start: start node. + goal: target node. + Returns: + Shortest path between `start` and `goal` nodes as a string of nodes. + 'Not found' string if no path found. + Example: + >>> bfs_shortest_path(demo_graph, "G", "D") + ['G', 'C', 'A', 'B', 'D'] + >>> bfs_shortest_path(demo_graph, "G", "G") + ['G'] + >>> bfs_shortest_path(demo_graph, "G", "Unknown") + [] + """ + # keep track of explored nodes + explored = set() + # keep track of all the paths to be checked + queue = deque([[start]]) + + # return path if start is goal + if start == goal: + return [start] + + # keeps looping until all possible paths have been checked + while queue: + # pop the first path from the queue + path = queue.popleft() + # get the last node from the path + node = path[-1] + if node not in explored: + neighbours = graph[node] + # go through all neighbour nodes, construct a new path and + # push it into the queue + for neighbour in neighbours: + new_path = list(path) + new_path.append(neighbour) + queue.append(new_path) + # return path if neighbour is goal + if neighbour == goal: + return new_path + + # mark node as explored + explored.add(node) + + # in case there's no path between the 2 nodes + return [] + + +def bfs_shortest_path_distance(graph: dict, start, target) -> int: + """Find the shortest path distance between `start` and `target` nodes. + Args: + graph: node/list of neighboring nodes key/value pairs. + start: node to start search from. + target: node to search for. + Returns: + Number of edges in the shortest path between `start` and `target` nodes. + -1 if no path exists. + Example: + >>> bfs_shortest_path_distance(demo_graph, "G", "D") + 4 + >>> bfs_shortest_path_distance(demo_graph, "A", "A") + 0 + >>> bfs_shortest_path_distance(demo_graph, "A", "Unknown") + -1 + """ + if not graph or start not in graph or target not in graph: + return -1 + if start == target: + return 0 + queue = deque([start]) + visited = set(start) + # Keep tab on distances from `start` node. + dist = {start: 0, target: -1} + while queue: + node = queue.popleft() + if node == target: + dist[target] = ( + dist[node] if dist[target] == -1 else min(dist[target], dist[node]) + ) + for adjacent in graph[node]: + if adjacent not in visited: + visited.add(adjacent) + queue.append(adjacent) + dist[adjacent] = dist[node] + 1 + return dist[target] + + +if __name__ == "__main__": + print(bfs_shortest_path(demo_graph, "G", "D")) # returns ['G', 'C', 'A', 'B', 'D'] + print(bfs_shortest_path_distance(demo_graph, "G", "D")) # returns 4 diff --git a/python/Graphs/breadth_first_search_zero_one_shortest_path.py b/python/Graphs/breadth_first_search_zero_one_shortest_path.py new file mode 100644 index 00000000..d3a255ba --- /dev/null +++ b/python/Graphs/breadth_first_search_zero_one_shortest_path.py @@ -0,0 +1,143 @@ +""" +Finding the shortest path in 0-1-graph in O(E + V) which is faster than dijkstra. +0-1-graph is the weighted graph with the weights equal to 0 or 1. +Link: https://codeforces.com/blog/entry/22276 +""" + +from __future__ import annotations + +from collections import deque +from collections.abc import Iterator +from dataclasses import dataclass + + +@dataclass +class Edge: + """Weighted directed graph edge.""" + + destination_vertex: int + weight: int + + +class AdjacencyList: + """Graph adjacency list.""" + + def __init__(self, size: int): + self._graph: list[list[Edge]] = [[] for _ in range(size)] + self._size = size + + def __getitem__(self, vertex: int) -> Iterator[Edge]: + """Get all the vertices adjacent to the given one.""" + return iter(self._graph[vertex]) + + @property + def size(self): + return self._size + + def add_edge(self, from_vertex: int, to_vertex: int, weight: int): + """ + >>> g = AdjacencyList(2) + >>> g.add_edge(0, 1, 0) + >>> g.add_edge(1, 0, 1) + >>> list(g[0]) + [Edge(destination_vertex=1, weight=0)] + >>> list(g[1]) + [Edge(destination_vertex=0, weight=1)] + >>> g.add_edge(0, 1, 2) + Traceback (most recent call last): + ... + ValueError: Edge weight must be either 0 or 1. + >>> g.add_edge(0, 2, 1) + Traceback (most recent call last): + ... + ValueError: Vertex indexes must be in [0; size). + """ + if weight not in (0, 1): + raise ValueError("Edge weight must be either 0 or 1.") + + if to_vertex < 0 or to_vertex >= self.size: + raise ValueError("Vertex indexes must be in [0; size).") + + self._graph[from_vertex].append(Edge(to_vertex, weight)) + + def get_shortest_path(self, start_vertex: int, finish_vertex: int) -> int | None: + """ + Return the shortest distance from start_vertex to finish_vertex in 0-1-graph. + 1 1 1 + 0--------->3 6--------7>------->8 + | ^ ^ ^ |1 + | | | |0 v + 0| |0 1| 9-------->10 + | | | ^ 1 + v | | |0 + 1--------->2<-------4------->5 + 0 1 1 + >>> g = AdjacencyList(11) + >>> g.add_edge(0, 1, 0) + >>> g.add_edge(0, 3, 1) + >>> g.add_edge(1, 2, 0) + >>> g.add_edge(2, 3, 0) + >>> g.add_edge(4, 2, 1) + >>> g.add_edge(4, 5, 1) + >>> g.add_edge(4, 6, 1) + >>> g.add_edge(5, 9, 0) + >>> g.add_edge(6, 7, 1) + >>> g.add_edge(7, 8, 1) + >>> g.add_edge(8, 10, 1) + >>> g.add_edge(9, 7, 0) + >>> g.add_edge(9, 10, 1) + >>> g.add_edge(1, 2, 2) + Traceback (most recent call last): + ... + ValueError: Edge weight must be either 0 or 1. + >>> g.get_shortest_path(0, 3) + 0 + >>> g.get_shortest_path(0, 4) + Traceback (most recent call last): + ... + ValueError: No path from start_vertex to finish_vertex. + >>> g.get_shortest_path(4, 10) + 2 + >>> g.get_shortest_path(4, 8) + 2 + >>> g.get_shortest_path(0, 1) + 0 + >>> g.get_shortest_path(1, 0) + Traceback (most recent call last): + ... + ValueError: No path from start_vertex to finish_vertex. + """ + queue = deque([start_vertex]) + distances: list[int | None] = [None] * self.size + distances[start_vertex] = 0 + + while queue: + current_vertex = queue.popleft() + current_distance = distances[current_vertex] + if current_distance is None: + continue + + for edge in self[current_vertex]: + new_distance = current_distance + edge.weight + dest_vertex_distance = distances[edge.destination_vertex] + if ( + isinstance(dest_vertex_distance, int) + and new_distance >= dest_vertex_distance + ): + continue + distances[edge.destination_vertex] = new_distance + if edge.weight == 0: + queue.appendleft(edge.destination_vertex) + else: + queue.append(edge.destination_vertex) + + if distances[finish_vertex] is None: + raise ValueError("No path from start_vertex to finish_vertex.") + + return distances[finish_vertex] + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/check_bipatrite.py b/python/Graphs/check_bipatrite.py new file mode 100644 index 00000000..897c7885 --- /dev/null +++ b/python/Graphs/check_bipatrite.py @@ -0,0 +1,161 @@ +from collections import defaultdict, deque + + +def is_bipartite_dfs(graph: dict[int, list[int]]) -> bool: + """ + Check if a graph is bipartite using depth-first search (DFS). + + Args: + `graph`: Adjacency list representing the graph. + + Returns: + ``True`` if bipartite, ``False`` otherwise. + + Checks if the graph can be divided into two sets of vertices, such that no two + vertices within the same set are connected by an edge. + + Examples: + + >>> is_bipartite_dfs({0: [1, 2], 1: [0, 3], 2: [0, 4]}) + True + >>> is_bipartite_dfs({0: [1, 2], 1: [0, 3], 2: [0, 1]}) + False + >>> is_bipartite_dfs({}) + True + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + >>> is_bipartite_dfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) + False + >>> is_bipartite_dfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]}) + True + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + >>> is_bipartite_dfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + + >>> # FIXME: This test should fails with KeyError: 4. + >>> is_bipartite_dfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]}) + False + >>> is_bipartite_dfs({0: [-1, 3], 1: [0, -2]}) + False + >>> is_bipartite_dfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]}) + True + >>> is_bipartite_dfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + + >>> # FIXME: This test should fails with + >>> # TypeError: list indices must be integers or... + >>> is_bipartite_dfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]}) + True + >>> is_bipartite_dfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]}) + True + >>> is_bipartite_dfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]}) + True + """ + + def depth_first_search(node: int, color: int) -> bool: + """ + Perform Depth-First Search (DFS) on the graph starting from a node. + + Args: + node: The current node being visited. + color: The color assigned to the current node. + + Returns: + True if the graph is bipartite starting from the current node, + False otherwise. + """ + if visited[node] == -1: + visited[node] = color + if node not in graph: + return True + for neighbor in graph[node]: + if not depth_first_search(neighbor, 1 - color): + return False + return visited[node] == color + + visited: defaultdict[int, int] = defaultdict(lambda: -1) + for node in graph: + if visited[node] == -1 and not depth_first_search(node, 0): + return False + return True + + +def is_bipartite_bfs(graph: dict[int, list[int]]) -> bool: + """ + Check if a graph is bipartite using a breadth-first search (BFS). + + Args: + `graph`: Adjacency list representing the graph. + + Returns: + ``True`` if bipartite, ``False`` otherwise. + + Check if the graph can be divided into two sets of vertices, such that no two + vertices within the same set are connected by an edge. + + Examples: + + >>> is_bipartite_bfs({0: [1, 2], 1: [0, 3], 2: [0, 4]}) + True + >>> is_bipartite_bfs({0: [1, 2], 1: [0, 2], 2: [0, 1]}) + False + >>> is_bipartite_bfs({}) + True + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + >>> is_bipartite_bfs({0: [1, 2, 3], 1: [0, 2], 2: [0, 1, 3], 3: [0, 2]}) + False + >>> is_bipartite_bfs({0: [4], 1: [], 2: [4], 3: [4], 4: [0, 2, 3]}) + True + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + >>> is_bipartite_bfs({7: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 4: [0]}) + False + + >>> # FIXME: This test should fails with KeyError: 4. + >>> is_bipartite_bfs({0: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2], 9: [0]}) + False + >>> is_bipartite_bfs({0: [-1, 3], 1: [0, -2]}) + False + >>> is_bipartite_bfs({-1: [0, 2], 0: [-1, 1], 1: [0, 2], 2: [-1, 1]}) + True + >>> is_bipartite_bfs({0.9: [1, 3], 1: [0, 2], 2: [1, 3], 3: [0, 2]}) + True + + >>> # FIXME: This test should fails with + >>> # TypeError: list indices must be integers or... + >>> is_bipartite_bfs({0: [1.0, 3.0], 1.0: [0, 2.0], 2.0: [1.0, 3.0], 3.0: [0, 2.0]}) + True + >>> is_bipartite_bfs({"a": [1, 3], "b": [0, 2], "c": [1, 3], "d": [0, 2]}) + True + >>> is_bipartite_bfs({0: ["b", "d"], 1: ["a", "c"], 2: ["b", "d"], 3: ["a", "c"]}) + True + """ + visited: defaultdict[int, int] = defaultdict(lambda: -1) + for node in graph: + if visited[node] == -1: + queue: deque[int] = deque() + queue.append(node) + visited[node] = 0 + while queue: + curr_node = queue.popleft() + if curr_node not in graph: + continue + for neighbor in graph[curr_node]: + if visited[neighbor] == -1: + visited[neighbor] = 1 - visited[curr_node] + queue.append(neighbor) + elif visited[neighbor] == visited[curr_node]: + return False + return True + + +if __name__ == "__main__": + import doctest + + result = doctest.testmod() + if result.failed: + print(f"{result.failed} test(s) failed.") + else: + print("All tests passed!") diff --git a/python/Graphs/check_cycle.py b/python/Graphs/check_cycle.py new file mode 100644 index 00000000..9fd1cd80 --- /dev/null +++ b/python/Graphs/check_cycle.py @@ -0,0 +1,52 @@ +""" +Program to check if a cycle is present in a given graph +""" + + +def check_cycle(graph: dict) -> bool: + """ + Returns True if graph is cyclic else False + >>> check_cycle(graph={0:[], 1:[0, 3], 2:[0, 4], 3:[5], 4:[5], 5:[]}) + False + >>> check_cycle(graph={0:[1, 2], 1:[2], 2:[0, 3], 3:[3]}) + True + """ + # Keep track of visited nodes + visited: set[int] = set() + # To detect a back edge, keep track of vertices currently in the recursion stack + rec_stk: set[int] = set() + return any( + node not in visited and depth_first_search(graph, node, visited, rec_stk) + for node in graph + ) + + +def depth_first_search(graph: dict, vertex: int, visited: set, rec_stk: set) -> bool: + """ + Recur for all neighbours. + If any neighbour is visited and in rec_stk then graph is cyclic. + >>> graph = {0:[], 1:[0, 3], 2:[0, 4], 3:[5], 4:[5], 5:[]} + >>> vertex, visited, rec_stk = 0, set(), set() + >>> depth_first_search(graph, vertex, visited, rec_stk) + False + """ + # Mark current node as visited and add to recursion stack + visited.add(vertex) + rec_stk.add(vertex) + + for node in graph[vertex]: + if node not in visited: + if depth_first_search(graph, node, visited, rec_stk): + return True + elif node in rec_stk: + return True + + # The node needs to be removed from recursion stack before function ends + rec_stk.remove(vertex) + return False + + +if __name__ == "__main__": + from doctest import testmod + + testmod() diff --git a/python/Graphs/connected_components.py b/python/Graphs/connected_components.py new file mode 100644 index 00000000..15c7633e --- /dev/null +++ b/python/Graphs/connected_components.py @@ -0,0 +1,58 @@ +""" +https://en.wikipedia.org/wiki/Component_(graph_theory) + +Finding connected components in graph + +""" + +test_graph_1 = {0: [1, 2], 1: [0, 3], 2: [0], 3: [1], 4: [5, 6], 5: [4, 6], 6: [4, 5]} + +test_graph_2 = {0: [1, 2, 3], 1: [0, 3], 2: [0], 3: [0, 1], 4: [], 5: []} + + +def dfs(graph: dict, vert: int, visited: list) -> list: + """ + Use depth first search to find all vertices + being in the same component as initial vertex + >>> dfs(test_graph_1, 0, 5 * [False]) + [0, 1, 3, 2] + >>> dfs(test_graph_2, 0, 6 * [False]) + [0, 1, 3, 2] + """ + + visited[vert] = True + connected_verts = [] + + for neighbour in graph[vert]: + if not visited[neighbour]: + connected_verts += dfs(graph, neighbour, visited) + + return [vert, *connected_verts] + + +def connected_components(graph: dict) -> list: + """ + This function takes graph as a parameter + and then returns the list of connected components + >>> connected_components(test_graph_1) + [[0, 1, 3, 2], [4, 5, 6]] + >>> connected_components(test_graph_2) + [[0, 1, 3, 2], [4], [5]] + """ + + graph_size = len(graph) + visited = graph_size * [False] + components_list = [] + + for i in range(graph_size): + if not visited[i]: + i_connected = dfs(graph, i, visited) + components_list.append(i_connected) + + return components_list + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/deep_clone_graph.py b/python/Graphs/deep_clone_graph.py new file mode 100644 index 00000000..18ea99c6 --- /dev/null +++ b/python/Graphs/deep_clone_graph.py @@ -0,0 +1,78 @@ +""" +LeetCode 133. Clone Graph +https://leetcode.com/problems/clone-graph/ + +Given a reference of a node in a connected undirected graph. + +Return a deep copy (clone) of the graph. + +Each node in the graph contains a value (int) and a list (List[Node]) of its +neighbors. +""" + +from dataclasses import dataclass + + +@dataclass +class Node: + value: int = 0 + neighbors: list["Node"] | None = None + + def __post_init__(self) -> None: + """ + >>> Node(3).neighbors + [] + """ + self.neighbors = self.neighbors or [] + + def __hash__(self) -> int: + """ + >>> hash(Node(3)) != 0 + True + """ + return id(self) + + +def clone_graph(node: Node | None) -> Node | None: + """ + This function returns a clone of a connected undirected graph. + >>> clone_graph(Node(1)) + Node(value=1, neighbors=[]) + >>> clone_graph(Node(1, [Node(2)])) + Node(value=1, neighbors=[Node(value=2, neighbors=[])]) + >>> clone_graph(None) is None + True + """ + if not node: + return None + + originals_to_clones = {} # map nodes to clones + + stack = [node] + + while stack: + original = stack.pop() + + if original in originals_to_clones: + continue + + originals_to_clones[original] = Node(original.value) + + stack.extend(original.neighbors or []) + + for original, clone in originals_to_clones.items(): + for neighbor in original.neighbors or []: + cloned_neighbor = originals_to_clones[neighbor] + + if not clone.neighbors: + clone.neighbors = [] + + clone.neighbors.append(cloned_neighbor) + + return originals_to_clones[node] + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/depth_first_search.py b/python/Graphs/depth_first_search.py new file mode 100644 index 00000000..a666e74c --- /dev/null +++ b/python/Graphs/depth_first_search.py @@ -0,0 +1,48 @@ +"""Non recursive implementation of a DFS algorithm.""" + +from __future__ import annotations + + +def depth_first_search(graph: dict, start: str) -> set[str]: + """Depth First Search on Graph + :param graph: directed graph in dictionary format + :param start: starting vertex as a string + :returns: the trace of the search + >>> input_G = { "A": ["B", "C", "D"], "B": ["A", "D", "E"], + ... "C": ["A", "F"], "D": ["B", "D"], "E": ["B", "F"], + ... "F": ["C", "E", "G"], "G": ["F"] } + >>> output_G = list({'A', 'B', 'C', 'D', 'E', 'F', 'G'}) + >>> all(x in output_G for x in list(depth_first_search(input_G, "A"))) + True + >>> all(x in output_G for x in list(depth_first_search(input_G, "G"))) + True + """ + explored, stack = set(start), [start] + + while stack: + v = stack.pop() + explored.add(v) + # Differences from BFS: + # 1) pop last element instead of first one + # 2) add adjacent elements to stack without exploring them + for adj in reversed(graph[v]): + if adj not in explored: + stack.append(adj) + return explored + + +G = { + "A": ["B", "C", "D"], + "B": ["A", "D", "E"], + "C": ["A", "F"], + "D": ["B", "D"], + "E": ["B", "F"], + "F": ["C", "E", "G"], + "G": ["F"], +} + +if __name__ == "__main__": + import doctest + + doctest.testmod() + print(depth_first_search(G, "A")) diff --git a/python/Graphs/depth_first_search_2.py b/python/Graphs/depth_first_search_2.py new file mode 100644 index 00000000..8fe48b7f --- /dev/null +++ b/python/Graphs/depth_first_search_2.py @@ -0,0 +1,127 @@ +#!/usr/bin/python + +"""Author: OMKAR PATHAK""" + + +class Graph: + def __init__(self): + self.vertex = {} + + # for printing the Graph vertices + def print_graph(self) -> None: + """ + Print the graph vertices. + + Example: + >>> g = Graph() + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 2) + >>> g.add_edge(1, 2) + >>> g.add_edge(2, 0) + >>> g.add_edge(2, 3) + >>> g.add_edge(3, 3) + >>> g.print_graph() + {0: [1, 2], 1: [2], 2: [0, 3], 3: [3]} + 0 -> 1 -> 2 + 1 -> 2 + 2 -> 0 -> 3 + 3 -> 3 + """ + print(self.vertex) + for i in self.vertex: + print(i, " -> ", " -> ".join([str(j) for j in self.vertex[i]])) + + # for adding the edge between two vertices + def add_edge(self, from_vertex: int, to_vertex: int) -> None: + """ + Add an edge between two vertices. + + :param from_vertex: The source vertex. + :param to_vertex: The destination vertex. + + Example: + >>> g = Graph() + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 2) + >>> g.print_graph() + {0: [1, 2]} + 0 -> 1 -> 2 + """ + # check if vertex is already present, + if from_vertex in self.vertex: + self.vertex[from_vertex].append(to_vertex) + else: + # else make a new vertex + self.vertex[from_vertex] = [to_vertex] + + def dfs(self) -> None: + """ + Perform depth-first search (DFS) traversal on the graph + and print the visited vertices. + + Example: + >>> g = Graph() + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 2) + >>> g.add_edge(1, 2) + >>> g.add_edge(2, 0) + >>> g.add_edge(2, 3) + >>> g.add_edge(3, 3) + >>> g.dfs() + 0 1 2 3 + """ + # visited array for storing already visited nodes + visited = [False] * len(self.vertex) + + # call the recursive helper function + for i in range(len(self.vertex)): + if not visited[i]: + self.dfs_recursive(i, visited) + + def dfs_recursive(self, start_vertex: int, visited: list) -> None: + """ + Perform a recursive depth-first search (DFS) traversal on the graph. + + :param start_vertex: The starting vertex for the traversal. + :param visited: A list to track visited vertices. + + Example: + >>> g = Graph() + >>> g.add_edge(0, 1) + >>> g.add_edge(0, 2) + >>> g.add_edge(1, 2) + >>> g.add_edge(2, 0) + >>> g.add_edge(2, 3) + >>> g.add_edge(3, 3) + >>> visited = [False] * len(g.vertex) + >>> g.dfs_recursive(0, visited) + 0 1 2 3 + """ + # mark start vertex as visited + visited[start_vertex] = True + + print(start_vertex, end="") + + # Recur for all the vertices that are adjacent to this node + for i in self.vertex: + if not visited[i]: + print(" ", end="") + self.dfs_recursive(i, visited) + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + g = Graph() + g.add_edge(0, 1) + g.add_edge(0, 2) + g.add_edge(1, 2) + g.add_edge(2, 0) + g.add_edge(2, 3) + g.add_edge(3, 3) + + g.print_graph() + print("DFS:") + g.dfs() diff --git a/python/Graphs/dijkstra.py b/python/Graphs/dijkstra.py new file mode 100644 index 00000000..87e9d223 --- /dev/null +++ b/python/Graphs/dijkstra.py @@ -0,0 +1,119 @@ +""" +pseudo-code + +DIJKSTRA(graph G, start vertex s, destination vertex d): + +//all nodes initially unexplored + +1 - let H = min heap data structure, initialized with 0 and s [here 0 indicates + the distance from start vertex s] +2 - while H is non-empty: +3 - remove the first node and cost of H, call it U and cost +4 - if U has been previously explored: +5 - go to the while loop, line 2 //Once a node is explored there is no need + to make it again +6 - mark U as explored +7 - if U is d: +8 - return cost // total cost from start to destination vertex +9 - for each edge(U, V): c=cost of edge(U,V) // for V in graph[U] +10 - if V explored: +11 - go to next V in line 9 +12 - total_cost = cost + c +13 - add (total_cost,V) to H + +You can think at cost as a distance where Dijkstra finds the shortest distance +between vertices s and v in a graph G. The use of a min heap as H guarantees +that if a vertex has already been explored there will be no other path with +shortest distance, that happens because heapq.heappop will always return the +next vertex with the shortest distance, considering that the heap stores not +only the distance between previous vertex and current vertex but the entire +distance between each vertex that makes up the path from start vertex to target +vertex. +""" + +import heapq + + +def dijkstra(graph, start, end): + """Return the cost of the shortest path between vertices start and end. + + >>> dijkstra(G, "E", "C") + 6 + >>> dijkstra(G2, "E", "F") + 3 + >>> dijkstra(G3, "E", "F") + 3 + """ + + heap = [(0, start)] # cost from start node,end node + visited = set() + while heap: + (cost, u) = heapq.heappop(heap) + if u in visited: + continue + visited.add(u) + if u == end: + return cost + for v, c in graph[u]: + if v in visited: + continue + next_item = cost + c + heapq.heappush(heap, (next_item, v)) + return -1 + + +G = { + "A": [["B", 2], ["C", 5]], + "B": [["A", 2], ["D", 3], ["E", 1], ["F", 1]], + "C": [["A", 5], ["F", 3]], + "D": [["B", 3]], + "E": [["B", 4], ["F", 3]], + "F": [["C", 3], ["E", 3]], +} + +r""" +Layout of G2: + +E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F + \ /\ + \ || + ----------------- 3 -------------------- +""" +G2 = { + "B": [["C", 1]], + "C": [["D", 1]], + "D": [["F", 1]], + "E": [["B", 1], ["F", 3]], + "F": [], +} + +r""" +Layout of G3: + +E -- 1 --> B -- 1 --> C -- 1 --> D -- 1 --> F + \ /\ + \ || + -------- 2 ---------> G ------- 1 ------ +""" +G3 = { + "B": [["C", 1]], + "C": [["D", 1]], + "D": [["F", 1]], + "E": [["B", 1], ["G", 2]], + "F": [], + "G": [["F", 1]], +} + +short_distance = dijkstra(G, "E", "C") +print(short_distance) # E -- 3 --> F -- 3 --> C == 6 + +short_distance = dijkstra(G2, "E", "F") +print(short_distance) # E -- 3 --> F == 3 + +short_distance = dijkstra(G3, "E", "F") +print(short_distance) # E -- 2 --> G -- 1 --> F == 3 + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/dijkstra_2.py b/python/Graphs/dijkstra_2.py new file mode 100644 index 00000000..f548463f --- /dev/null +++ b/python/Graphs/dijkstra_2.py @@ -0,0 +1,58 @@ +def print_dist(dist, v): + print("\nVertex Distance") + for i in range(v): + if dist[i] != float("inf"): + print(i, "\t", int(dist[i]), end="\t") + else: + print(i, "\t", "INF", end="\t") + print() + + +def min_dist(mdist, vset, v): + min_val = float("inf") + min_ind = -1 + for i in range(v): + if (not vset[i]) and mdist[i] < min_val: + min_ind = i + min_val = mdist[i] + return min_ind + + +def dijkstra(graph, v, src): + mdist = [float("inf") for _ in range(v)] + vset = [False for _ in range(v)] + mdist[src] = 0.0 + + for _ in range(v - 1): + u = min_dist(mdist, vset, v) + vset[u] = True + + for i in range(v): + if ( + (not vset[i]) + and graph[u][i] != float("inf") + and mdist[u] + graph[u][i] < mdist[i] + ): + mdist[i] = mdist[u] + graph[u][i] + + print_dist(mdist, i) + + +if __name__ == "__main__": + V = int(input("Enter number of vertices: ").strip()) + E = int(input("Enter number of edges: ").strip()) + + graph = [[float("inf") for i in range(V)] for j in range(V)] + + for i in range(V): + graph[i][i] = 0.0 + + for i in range(E): + print("\nEdge ", i + 1) + src = int(input("Enter source:").strip()) + dst = int(input("Enter destination:").strip()) + weight = float(input("Enter weight:").strip()) + graph[src][dst] = weight + + gsrc = int(input("\nEnter shortest path source:").strip()) + dijkstra(graph, V, gsrc) diff --git a/python/Graphs/dijkstra_algorithm.py b/python/Graphs/dijkstra_algorithm.py new file mode 100644 index 00000000..60646862 --- /dev/null +++ b/python/Graphs/dijkstra_algorithm.py @@ -0,0 +1,484 @@ +# Title: Dijkstra's Algorithm for finding single source shortest path from scratch +# Author: Shubham Malik +# References: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + +import math +import sys + +# For storing the vertex set to retrieve node with the lowest distance + + +class PriorityQueue: + # Based on Min Heap + def __init__(self): + """ + Priority queue class constructor method. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.cur_size + 0 + >>> priority_queue_test.array + [] + >>> priority_queue_test.pos + {} + """ + self.cur_size = 0 + self.array = [] + self.pos = {} # To store the pos of node in array + + def is_empty(self): + """ + Conditional boolean method to determine if the priority queue is empty or not. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.is_empty() + True + >>> priority_queue_test.insert((2, 'A')) + >>> priority_queue_test.is_empty() + False + """ + return self.cur_size == 0 + + def min_heapify(self, idx): + """ + Sorts the queue array so that the minimum element is root. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.cur_size = 3 + >>> priority_queue_test.pos = {'A': 0, 'B': 1, 'C': 2} + + >>> priority_queue_test.array = [(5, 'A'), (10, 'B'), (15, 'C')] + >>> priority_queue_test.min_heapify(0) + >>> priority_queue_test.array + [(5, 'A'), (10, 'B'), (15, 'C')] + + >>> priority_queue_test.array = [(10, 'A'), (5, 'B'), (15, 'C')] + >>> priority_queue_test.min_heapify(0) + >>> priority_queue_test.array + [(5, 'B'), (10, 'A'), (15, 'C')] + + >>> priority_queue_test.array = [(10, 'A'), (15, 'B'), (5, 'C')] + >>> priority_queue_test.min_heapify(0) + >>> priority_queue_test.array + [(5, 'C'), (15, 'B'), (10, 'A')] + + >>> priority_queue_test.array = [(10, 'A'), (5, 'B')] + >>> priority_queue_test.cur_size = len(priority_queue_test.array) + >>> priority_queue_test.pos = {'A': 0, 'B': 1} + >>> priority_queue_test.min_heapify(0) + >>> priority_queue_test.array + [(5, 'B'), (10, 'A')] + """ + lc = self.left(idx) + rc = self.right(idx) + if lc < self.cur_size and self.array[lc][0] < self.array[idx][0]: + smallest = lc + else: + smallest = idx + if rc < self.cur_size and self.array[rc][0] < self.array[smallest][0]: + smallest = rc + if smallest != idx: + self.swap(idx, smallest) + self.min_heapify(smallest) + + def insert(self, tup): + """ + Inserts a node into the Priority Queue. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.insert((10, 'A')) + >>> priority_queue_test.array + [(10, 'A')] + >>> priority_queue_test.insert((15, 'B')) + >>> priority_queue_test.array + [(10, 'A'), (15, 'B')] + >>> priority_queue_test.insert((5, 'C')) + >>> priority_queue_test.array + [(5, 'C'), (10, 'A'), (15, 'B')] + """ + self.pos[tup[1]] = self.cur_size + self.cur_size += 1 + self.array.append((sys.maxsize, tup[1])) + self.decrease_key((sys.maxsize, tup[1]), tup[0]) + + def extract_min(self): + """ + Removes and returns the min element at top of priority queue. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.array = [(10, 'A'), (15, 'B')] + >>> priority_queue_test.cur_size = len(priority_queue_test.array) + >>> priority_queue_test.pos = {'A': 0, 'B': 1} + >>> priority_queue_test.insert((5, 'C')) + >>> priority_queue_test.extract_min() + 'C' + >>> priority_queue_test.array[0] + (10, 'A') + """ + min_node = self.array[0][1] + self.array[0] = self.array[self.cur_size - 1] + self.cur_size -= 1 + self.min_heapify(0) + del self.pos[min_node] + return min_node + + def left(self, i): + """ + Returns the index of left child + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.left(0) + 1 + >>> priority_queue_test.left(1) + 3 + """ + return 2 * i + 1 + + def right(self, i): + """ + Returns the index of right child + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.right(0) + 2 + >>> priority_queue_test.right(1) + 4 + """ + return 2 * i + 2 + + def par(self, i): + """ + Returns the index of parent + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.par(1) + 0 + >>> priority_queue_test.par(2) + 1 + >>> priority_queue_test.par(4) + 2 + """ + return math.floor(i / 2) + + def swap(self, i, j): + """ + Swaps array elements at indices i and j, update the pos{} + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.array = [(10, 'A'), (15, 'B')] + >>> priority_queue_test.cur_size = len(priority_queue_test.array) + >>> priority_queue_test.pos = {'A': 0, 'B': 1} + >>> priority_queue_test.swap(0, 1) + >>> priority_queue_test.array + [(15, 'B'), (10, 'A')] + >>> priority_queue_test.pos + {'A': 1, 'B': 0} + """ + self.pos[self.array[i][1]] = j + self.pos[self.array[j][1]] = i + temp = self.array[i] + self.array[i] = self.array[j] + self.array[j] = temp + + def decrease_key(self, tup, new_d): + """ + Decrease the key value for a given tuple, assuming the new_d is at most old_d. + + Examples: + >>> priority_queue_test = PriorityQueue() + >>> priority_queue_test.array = [(10, 'A'), (15, 'B')] + >>> priority_queue_test.cur_size = len(priority_queue_test.array) + >>> priority_queue_test.pos = {'A': 0, 'B': 1} + >>> priority_queue_test.decrease_key((10, 'A'), 5) + >>> priority_queue_test.array + [(5, 'A'), (15, 'B')] + """ + idx = self.pos[tup[1]] + # assuming the new_d is at most old_d + self.array[idx] = (new_d, tup[1]) + while idx > 0 and self.array[self.par(idx)][0] > self.array[idx][0]: + self.swap(idx, self.par(idx)) + idx = self.par(idx) + + +class Graph: + def __init__(self, num): + """ + Graph class constructor + + Examples: + >>> graph_test = Graph(1) + >>> graph_test.num_nodes + 1 + >>> graph_test.dist + [0] + >>> graph_test.par + [-1] + >>> graph_test.adjList + {} + """ + self.adjList = {} # To store graph: u -> (v,w) + self.num_nodes = num # Number of nodes in graph + # To store the distance from source vertex + self.dist = [0] * self.num_nodes + self.par = [-1] * self.num_nodes # To store the path + + def add_edge(self, u, v, w): + """ + Add edge going from node u to v and v to u with weight w: u (w)-> v, v (w) -> u + + Examples: + >>> graph_test = Graph(1) + >>> graph_test.add_edge(1, 2, 1) + >>> graph_test.add_edge(2, 3, 2) + >>> graph_test.adjList + {1: [(2, 1)], 2: [(1, 1), (3, 2)], 3: [(2, 2)]} + """ + # Check if u already in graph + if u in self.adjList: + self.adjList[u].append((v, w)) + else: + self.adjList[u] = [(v, w)] + + # Assuming undirected graph + if v in self.adjList: + self.adjList[v].append((u, w)) + else: + self.adjList[v] = [(u, w)] + + def show_graph(self): + """ + Show the graph: u -> v(w) + + Examples: + >>> graph_test = Graph(1) + >>> graph_test.add_edge(1, 2, 1) + >>> graph_test.show_graph() + 1 -> 2(1) + 2 -> 1(1) + >>> graph_test.add_edge(2, 3, 2) + >>> graph_test.show_graph() + 1 -> 2(1) + 2 -> 1(1) -> 3(2) + 3 -> 2(2) + """ + for u in self.adjList: + print(u, "->", " -> ".join(str(f"{v}({w})") for v, w in self.adjList[u])) + + def dijkstra(self, src): + """ + Dijkstra algorithm + + Examples: + >>> graph_test = Graph(3) + >>> graph_test.add_edge(0, 1, 2) + >>> graph_test.add_edge(1, 2, 2) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 2 + Node 2 has distance: 4 + >>> graph_test.dist + [0, 2, 4] + + >>> graph_test = Graph(2) + >>> graph_test.add_edge(0, 1, 2) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 2 + >>> graph_test.dist + [0, 2] + + >>> graph_test = Graph(3) + >>> graph_test.add_edge(0, 1, 2) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 2 + Node 2 has distance: 0 + >>> graph_test.dist + [0, 2, 0] + + >>> graph_test = Graph(3) + >>> graph_test.add_edge(0, 1, 2) + >>> graph_test.add_edge(1, 2, 2) + >>> graph_test.add_edge(0, 2, 1) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 2 + Node 2 has distance: 1 + >>> graph_test.dist + [0, 2, 1] + + >>> graph_test = Graph(4) + >>> graph_test.add_edge(0, 1, 4) + >>> graph_test.add_edge(1, 2, 2) + >>> graph_test.add_edge(2, 3, 1) + >>> graph_test.add_edge(0, 2, 3) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 4 + Node 2 has distance: 3 + Node 3 has distance: 4 + >>> graph_test.dist + [0, 4, 3, 4] + + >>> graph_test = Graph(4) + >>> graph_test.add_edge(0, 1, 4) + >>> graph_test.add_edge(1, 2, 2) + >>> graph_test.add_edge(2, 3, 1) + >>> graph_test.add_edge(0, 2, 7) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 4 + Node 2 has distance: 6 + Node 3 has distance: 7 + >>> graph_test.dist + [0, 4, 6, 7] + """ + # Flush old junk values in par[] + self.par = [-1] * self.num_nodes + # src is the source node + self.dist[src] = 0 + q = PriorityQueue() + q.insert((0, src)) # (dist from src, node) + for u in self.adjList: + if u != src: + self.dist[u] = sys.maxsize # Infinity + self.par[u] = -1 + + while not q.is_empty(): + u = q.extract_min() # Returns node with the min dist from source + # Update the distance of all the neighbours of u and + # if their prev dist was INFINITY then push them in Q + for v, w in self.adjList[u]: + new_dist = self.dist[u] + w + if self.dist[v] > new_dist: + if self.dist[v] == sys.maxsize: + q.insert((new_dist, v)) + else: + q.decrease_key((self.dist[v], v), new_dist) + self.dist[v] = new_dist + self.par[v] = u + + # Show the shortest distances from src + self.show_distances(src) + + def show_distances(self, src): + """ + Show the distances from src to all other nodes in a graph + + Examples: + >>> graph_test = Graph(1) + >>> graph_test.show_distances(0) + Distance from node: 0 + Node 0 has distance: 0 + """ + print(f"Distance from node: {src}") + for u in range(self.num_nodes): + print(f"Node {u} has distance: {self.dist[u]}") + + def show_path(self, src, dest): + """ + Shows the shortest path from src to dest. + WARNING: Use it *after* calling dijkstra. + + Examples: + >>> graph_test = Graph(4) + >>> graph_test.add_edge(0, 1, 1) + >>> graph_test.add_edge(1, 2, 2) + >>> graph_test.add_edge(2, 3, 3) + >>> graph_test.dijkstra(0) + Distance from node: 0 + Node 0 has distance: 0 + Node 1 has distance: 1 + Node 2 has distance: 3 + Node 3 has distance: 6 + >>> graph_test.show_path(0, 3) # doctest: +NORMALIZE_WHITESPACE + ----Path to reach 3 from 0---- + 0 -> 1 -> 2 -> 3 + Total cost of path: 6 + """ + path = [] + cost = 0 + temp = dest + # Backtracking from dest to src + while self.par[temp] != -1: + path.append(temp) + if temp != src: + for v, w in self.adjList[temp]: + if v == self.par[temp]: + cost += w + break + temp = self.par[temp] + path.append(src) + path.reverse() + + print(f"----Path to reach {dest} from {src}----") + for u in path: + print(f"{u}", end=" ") + if u != dest: + print("-> ", end="") + + print("\nTotal cost of path: ", cost) + + +if __name__ == "__main__": + from doctest import testmod + + testmod() + graph = Graph(9) + graph.add_edge(0, 1, 4) + graph.add_edge(0, 7, 8) + graph.add_edge(1, 2, 8) + graph.add_edge(1, 7, 11) + graph.add_edge(2, 3, 7) + graph.add_edge(2, 8, 2) + graph.add_edge(2, 5, 4) + graph.add_edge(3, 4, 9) + graph.add_edge(3, 5, 14) + graph.add_edge(4, 5, 10) + graph.add_edge(5, 6, 2) + graph.add_edge(6, 7, 1) + graph.add_edge(6, 8, 6) + graph.add_edge(7, 8, 7) + graph.show_graph() + graph.dijkstra(0) + graph.show_path(0, 4) + +# OUTPUT +# 0 -> 1(4) -> 7(8) +# 1 -> 0(4) -> 2(8) -> 7(11) +# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7) +# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4) +# 3 -> 2(7) -> 4(9) -> 5(14) +# 8 -> 2(2) -> 6(6) -> 7(7) +# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2) +# 4 -> 3(9) -> 5(10) +# 6 -> 5(2) -> 7(1) -> 8(6) +# Distance from node: 0 +# Node 0 has distance: 0 +# Node 1 has distance: 4 +# Node 2 has distance: 12 +# Node 3 has distance: 19 +# Node 4 has distance: 21 +# Node 5 has distance: 11 +# Node 6 has distance: 9 +# Node 7 has distance: 8 +# Node 8 has distance: 14 +# ----Path to reach 4 from 0---- +# 0 -> 7 -> 6 -> 5 -> 4 +# Total cost of path: 21 diff --git a/python/Graphs/dijkstra_alternate.py b/python/Graphs/dijkstra_alternate.py new file mode 100644 index 00000000..7beef6b0 --- /dev/null +++ b/python/Graphs/dijkstra_alternate.py @@ -0,0 +1,98 @@ +from __future__ import annotations + + +class Graph: + def __init__(self, vertices: int) -> None: + """ + >>> graph = Graph(2) + >>> graph.vertices + 2 + >>> len(graph.graph) + 2 + >>> len(graph.graph[0]) + 2 + """ + self.vertices = vertices + self.graph = [[0] * vertices for _ in range(vertices)] + + def print_solution(self, distances_from_source: list[int]) -> None: + """ + >>> Graph(0).print_solution([]) # doctest: +NORMALIZE_WHITESPACE + Vertex Distance from Source + """ + print("Vertex \t Distance from Source") + for vertex in range(self.vertices): + print(vertex, "\t\t", distances_from_source[vertex]) + + def minimum_distance( + self, distances_from_source: list[int], visited: list[bool] + ) -> int: + """ + A utility function to find the vertex with minimum distance value, from the set + of vertices not yet included in shortest path tree. + + >>> Graph(3).minimum_distance([1, 2, 3], [False, False, True]) + 0 + """ + + # Initialize minimum distance for next node + minimum = 1e7 + min_index = 0 + + # Search not nearest vertex not in the shortest path tree + for vertex in range(self.vertices): + if distances_from_source[vertex] < minimum and visited[vertex] is False: + minimum = distances_from_source[vertex] + min_index = vertex + return min_index + + def dijkstra(self, source: int) -> None: + """ + Function that implements Dijkstra's single source shortest path algorithm for a + graph represented using adjacency matrix representation. + + >>> Graph(4).dijkstra(1) # doctest: +NORMALIZE_WHITESPACE + Vertex Distance from Source + 0 10000000 + 1 0 + 2 10000000 + 3 10000000 + """ + + distances = [int(1e7)] * self.vertices # distances from the source + distances[source] = 0 + visited = [False] * self.vertices + + for _ in range(self.vertices): + u = self.minimum_distance(distances, visited) + visited[u] = True + + # Update dist value of the adjacent vertices + # of the picked vertex only if the current + # distance is greater than new distance and + # the vertex in not in the shortest path tree + for v in range(self.vertices): + if ( + self.graph[u][v] > 0 + and visited[v] is False + and distances[v] > distances[u] + self.graph[u][v] + ): + distances[v] = distances[u] + self.graph[u][v] + + self.print_solution(distances) + + +if __name__ == "__main__": + graph = Graph(9) + graph.graph = [ + [0, 4, 0, 0, 0, 0, 0, 8, 0], + [4, 0, 8, 0, 0, 0, 0, 11, 0], + [0, 8, 0, 7, 0, 4, 0, 0, 2], + [0, 0, 7, 0, 9, 14, 0, 0, 0], + [0, 0, 0, 9, 0, 10, 0, 0, 0], + [0, 0, 4, 14, 10, 0, 2, 0, 0], + [0, 0, 0, 0, 0, 2, 0, 1, 6], + [8, 11, 0, 0, 0, 0, 1, 0, 7], + [0, 0, 2, 0, 0, 0, 6, 7, 0], + ] + graph.dijkstra(0) diff --git a/python/Graphs/dijkstra_binary_grid.py b/python/Graphs/dijkstra_binary_grid.py new file mode 100644 index 00000000..06293a87 --- /dev/null +++ b/python/Graphs/dijkstra_binary_grid.py @@ -0,0 +1,89 @@ +""" +This script implements the Dijkstra algorithm on a binary grid. +The grid consists of 0s and 1s, where 1 represents +a walkable node and 0 represents an obstacle. +The algorithm finds the shortest path from a start node to a destination node. +Diagonal movement can be allowed or disallowed. +""" + +from heapq import heappop, heappush + +import numpy as np + + +def dijkstra( + grid: np.ndarray, + source: tuple[int, int], + destination: tuple[int, int], + allow_diagonal: bool, +) -> tuple[float | int, list[tuple[int, int]]]: + """ + Implements Dijkstra's algorithm on a binary grid. + + Args: + grid (np.ndarray): A 2D numpy array representing the grid. + 1 represents a walkable node and 0 represents an obstacle. + source (Tuple[int, int]): A tuple representing the start node. + destination (Tuple[int, int]): A tuple representing the + destination node. + allow_diagonal (bool): A boolean determining whether + diagonal movements are allowed. + + Returns: + Tuple[Union[float, int], List[Tuple[int, int]]]: + The shortest distance from the start node to the destination node + and the shortest path as a list of nodes. + + >>> dijkstra(np.array([[1, 1, 1], [0, 1, 0], [0, 1, 1]]), (0, 0), (2, 2), False) + (4.0, [(0, 0), (0, 1), (1, 1), (2, 1), (2, 2)]) + + >>> dijkstra(np.array([[1, 1, 1], [0, 1, 0], [0, 1, 1]]), (0, 0), (2, 2), True) + (2.0, [(0, 0), (1, 1), (2, 2)]) + + >>> dijkstra(np.array([[1, 1, 1], [0, 0, 1], [0, 1, 1]]), (0, 0), (2, 2), False) + (4.0, [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)]) + """ + rows, cols = grid.shape + dx = [-1, 1, 0, 0] + dy = [0, 0, -1, 1] + if allow_diagonal: + dx += [-1, -1, 1, 1] + dy += [-1, 1, -1, 1] + + queue, visited = [(0, source)], set() + matrix = np.full((rows, cols), np.inf) + matrix[source] = 0 + predecessors = np.empty((rows, cols), dtype=object) + predecessors[source] = None + + while queue: + (dist, (x, y)) = heappop(queue) + if (x, y) in visited: + continue + visited.add((x, y)) + + if (x, y) == destination: + path = [] + while (x, y) != source: + path.append((x, y)) + x, y = predecessors[x, y] + path.append(source) # add the source manually + path.reverse() + return float(matrix[destination]), path + + for i in range(len(dx)): + nx, ny = x + dx[i], y + dy[i] + if 0 <= nx < rows and 0 <= ny < cols: + next_node = grid[nx][ny] + if next_node == 1 and matrix[nx, ny] > dist + 1: + heappush(queue, (dist + 1, (nx, ny))) + matrix[nx, ny] = dist + 1 + predecessors[nx, ny] = (x, y) + + return np.inf, [] + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/dinic.py b/python/Graphs/dinic.py new file mode 100644 index 00000000..7919e6bc --- /dev/null +++ b/python/Graphs/dinic.py @@ -0,0 +1,94 @@ +INF = float("inf") + + +class Dinic: + def __init__(self, n): + self.lvl = [0] * n + self.ptr = [0] * n + self.q = [0] * n + self.adj = [[] for _ in range(n)] + + """ + Here we will add our edges containing with the following parameters: + vertex closest to source, vertex closest to sink and flow capacity + through that edge ... + """ + + def add_edge(self, a, b, c, rcap=0): + self.adj[a].append([b, len(self.adj[b]), c, 0]) + self.adj[b].append([a, len(self.adj[a]) - 1, rcap, 0]) + + # This is a sample depth first search to be used at max_flow + def depth_first_search(self, vertex, sink, flow): + if vertex == sink or not flow: + return flow + + for i in range(self.ptr[vertex], len(self.adj[vertex])): + e = self.adj[vertex][i] + if self.lvl[e[0]] == self.lvl[vertex] + 1: + p = self.depth_first_search(e[0], sink, min(flow, e[2] - e[3])) + if p: + self.adj[vertex][i][3] += p + self.adj[e[0]][e[1]][3] -= p + return p + self.ptr[vertex] = self.ptr[vertex] + 1 + return 0 + + # Here we calculate the flow that reaches the sink + def max_flow(self, source, sink): + flow, self.q[0] = 0, source + for l in range(31): # l = 30 maybe faster for random data # noqa: E741 + while True: + self.lvl, self.ptr = [0] * len(self.q), [0] * len(self.q) + qi, qe, self.lvl[source] = 0, 1, 1 + while qi < qe and not self.lvl[sink]: + v = self.q[qi] + qi += 1 + for e in self.adj[v]: + if not self.lvl[e[0]] and (e[2] - e[3]) >> (30 - l): + self.q[qe] = e[0] + qe += 1 + self.lvl[e[0]] = self.lvl[v] + 1 + + p = self.depth_first_search(source, sink, INF) + while p: + flow += p + p = self.depth_first_search(source, sink, INF) + + if not self.lvl[sink]: + break + + return flow + + +# Example to use + +""" +Will be a bipartite graph, than it has the vertices near the source(4) +and the vertices near the sink(4) +""" +# Here we make a graphs with 10 vertex(source and sink includes) +graph = Dinic(10) +source = 0 +sink = 9 +""" +Now we add the vertices next to the font in the font with 1 capacity in this edge +(source -> source vertices) +""" +for vertex in range(1, 5): + graph.add_edge(source, vertex, 1) +""" +We will do the same thing for the vertices near the sink, but from vertex to sink +(sink vertices -> sink) +""" +for vertex in range(5, 9): + graph.add_edge(vertex, sink, 1) +""" +Finally we add the verices near the sink to the vertices near the source. +(source vertices -> sink vertices) +""" +for vertex in range(1, 5): + graph.add_edge(vertex, vertex + 4, 1) + +# Now we can know that is the maximum flow(source -> sink) +print(graph.max_flow(source, sink)) diff --git a/python/Graphs/directed_and_undirected_weighted_graph.py b/python/Graphs/directed_and_undirected_weighted_graph.py new file mode 100644 index 00000000..8ca645fd --- /dev/null +++ b/python/Graphs/directed_and_undirected_weighted_graph.py @@ -0,0 +1,489 @@ +from collections import deque +from math import floor +from random import random +from time import time + +# the default weight is 1 if not assigned but all the implementation is weighted + + +class DirectedGraph: + def __init__(self): + self.graph = {} + + # adding vertices and edges + # adding the weight is optional + # handles repetition + def add_pair(self, u, v, w=1): + if self.graph.get(u): + if self.graph[u].count([w, v]) == 0: + self.graph[u].append([w, v]) + else: + self.graph[u] = [[w, v]] + if not self.graph.get(v): + self.graph[v] = [] + + def all_nodes(self): + return list(self.graph) + + # handles if the input does not exist + def remove_pair(self, u, v): + if self.graph.get(u): + for _ in self.graph[u]: + if _[1] == v: + self.graph[u].remove(_) + + # if no destination is meant the default value is -1 + def dfs(self, s=-2, d=-1): + if s == d: + return [] + stack = [] + visited = [] + if s == -2: + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + ss = s + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if visited.count(node[1]) < 1: + if node[1] == d: + visited.append(d) + return visited + else: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return visited + + # c is the count of nodes you want and if you leave it or pass -1 to the function + # the count will be random from 10 to 10000 + def fill_graph_randomly(self, c=-1): + if c == -1: + c = floor(random() * 10000) + 10 + for i in range(c): + # every vertex has max 100 edges + for _ in range(floor(random() * 102) + 1): + n = floor(random() * c) + 1 + if n != i: + self.add_pair(i, n, 1) + + def bfs(self, s=-2): + d = deque() + visited = [] + if s == -2: + s = next(iter(self.graph)) + d.append(s) + visited.append(s) + while d: + s = d.popleft() + if len(self.graph[s]) != 0: + for node in self.graph[s]: + if visited.count(node[1]) < 1: + d.append(node[1]) + visited.append(node[1]) + return visited + + def in_degree(self, u): + count = 0 + for x in self.graph: + for y in self.graph[x]: + if y[1] == u: + count += 1 + return count + + def out_degree(self, u): + return len(self.graph[u]) + + def topological_sort(self, s=-2): + stack = [] + visited = [] + if s == -2: + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + ss = s + sorted_nodes = [] + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + sorted_nodes.append(stack.pop()) + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return sorted_nodes + + def cycle_nodes(self): + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + on_the_way_back = False + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + and not on_the_way_back + ): + len_stack = len(stack) - 1 + while len_stack >= 0: + if stack[len_stack] == node[1]: + anticipating_nodes.add(node[1]) + break + else: + anticipating_nodes.add(stack[len_stack]) + len_stack -= 1 + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return list(anticipating_nodes) + + def has_cycle(self): + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + on_the_way_back = False + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + and not on_the_way_back + ): + len_stack_minus_one = len(stack) - 1 + while len_stack_minus_one >= 0: + if stack[len_stack_minus_one] == node[1]: + anticipating_nodes.add(node[1]) + break + else: + return True + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return False + + def dfs_time(self, s=-2, e=-1): + begin = time() + self.dfs(s, e) + end = time() + return end - begin + + def bfs_time(self, s=-2): + begin = time() + self.bfs(s) + end = time() + return end - begin + + +class Graph: + def __init__(self): + self.graph = {} + + # adding vertices and edges + # adding the weight is optional + # handles repetition + def add_pair(self, u, v, w=1): + # check if the u exists + if self.graph.get(u): + # if there already is a edge + if self.graph[u].count([w, v]) == 0: + self.graph[u].append([w, v]) + else: + # if u does not exist + self.graph[u] = [[w, v]] + # add the other way + if self.graph.get(v): + # if there already is a edge + if self.graph[v].count([w, u]) == 0: + self.graph[v].append([w, u]) + else: + # if u does not exist + self.graph[v] = [[w, u]] + + # handles if the input does not exist + def remove_pair(self, u, v): + if self.graph.get(u): + for _ in self.graph[u]: + if _[1] == v: + self.graph[u].remove(_) + # the other way round + if self.graph.get(v): + for _ in self.graph[v]: + if _[1] == u: + self.graph[v].remove(_) + + # if no destination is meant the default value is -1 + def dfs(self, s=-2, d=-1): + if s == d: + return [] + stack = [] + visited = [] + if s == -2: + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + ss = s + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if visited.count(node[1]) < 1: + if node[1] == d: + visited.append(d) + return visited + else: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return visited + + # c is the count of nodes you want and if you leave it or pass -1 to the function + # the count will be random from 10 to 10000 + def fill_graph_randomly(self, c=-1): + if c == -1: + c = floor(random() * 10000) + 10 + for i in range(c): + # every vertex has max 100 edges + for _ in range(floor(random() * 102) + 1): + n = floor(random() * c) + 1 + if n != i: + self.add_pair(i, n, 1) + + def bfs(self, s=-2): + d = deque() + visited = [] + if s == -2: + s = next(iter(self.graph)) + d.append(s) + visited.append(s) + while d: + s = d.popleft() + if len(self.graph[s]) != 0: + for node in self.graph[s]: + if visited.count(node[1]) < 1: + d.append(node[1]) + visited.append(node[1]) + return visited + + def degree(self, u): + return len(self.graph[u]) + + def cycle_nodes(self): + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + on_the_way_back = False + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + and not on_the_way_back + ): + len_stack = len(stack) - 1 + while len_stack >= 0: + if stack[len_stack] == node[1]: + anticipating_nodes.add(node[1]) + break + else: + anticipating_nodes.add(stack[len_stack]) + len_stack -= 1 + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return list(anticipating_nodes) + + def has_cycle(self): + stack = [] + visited = [] + s = next(iter(self.graph)) + stack.append(s) + visited.append(s) + parent = -2 + indirect_parents = [] + ss = s + on_the_way_back = False + anticipating_nodes = set() + + while True: + # check if there is any non isolated nodes + if len(self.graph[s]) != 0: + ss = s + for node in self.graph[s]: + if ( + visited.count(node[1]) > 0 + and node[1] != parent + and indirect_parents.count(node[1]) > 0 + and not on_the_way_back + ): + len_stack_minus_one = len(stack) - 1 + while len_stack_minus_one >= 0: + if stack[len_stack_minus_one] == node[1]: + anticipating_nodes.add(node[1]) + break + else: + return True + if visited.count(node[1]) < 1: + stack.append(node[1]) + visited.append(node[1]) + ss = node[1] + break + + # check if all the children are visited + if s == ss: + stack.pop() + on_the_way_back = True + if len(stack) != 0: + s = stack[len(stack) - 1] + else: + on_the_way_back = False + indirect_parents.append(parent) + parent = s + s = ss + + # check if se have reached the starting point + if len(stack) == 0: + return False + + def all_nodes(self): + return list(self.graph) + + def dfs_time(self, s=-2, e=-1): + begin = time() + self.dfs(s, e) + end = time() + return end - begin + + def bfs_time(self, s=-2): + begin = time() + self.bfs(s) + end = time() + return end - begin diff --git a/python/Graphs/edmonds_karp_multiple_source_and_sink.py b/python/Graphs/edmonds_karp_multiple_source_and_sink.py new file mode 100644 index 00000000..5c774f4b --- /dev/null +++ b/python/Graphs/edmonds_karp_multiple_source_and_sink.py @@ -0,0 +1,193 @@ +class FlowNetwork: + def __init__(self, graph, sources, sinks): + self.source_index = None + self.sink_index = None + self.graph = graph + + self._normalize_graph(sources, sinks) + self.vertices_count = len(graph) + self.maximum_flow_algorithm = None + + # make only one source and one sink + def _normalize_graph(self, sources, sinks): + if sources is int: + sources = [sources] + if sinks is int: + sinks = [sinks] + + if len(sources) == 0 or len(sinks) == 0: + return + + self.source_index = sources[0] + self.sink_index = sinks[0] + + # make fake vertex if there are more + # than one source or sink + if len(sources) > 1 or len(sinks) > 1: + max_input_flow = 0 + for i in sources: + max_input_flow += sum(self.graph[i]) + + size = len(self.graph) + 1 + for room in self.graph: + room.insert(0, 0) + self.graph.insert(0, [0] * size) + for i in sources: + self.graph[0][i + 1] = max_input_flow + self.source_index = 0 + + size = len(self.graph) + 1 + for room in self.graph: + room.append(0) + self.graph.append([0] * size) + for i in sinks: + self.graph[i + 1][size - 1] = max_input_flow + self.sink_index = size - 1 + + def find_maximum_flow(self): + if self.maximum_flow_algorithm is None: + raise Exception("You need to set maximum flow algorithm before.") + if self.source_index is None or self.sink_index is None: + return 0 + + self.maximum_flow_algorithm.execute() + return self.maximum_flow_algorithm.getMaximumFlow() + + def set_maximum_flow_algorithm(self, algorithm): + self.maximum_flow_algorithm = algorithm(self) + + +class FlowNetworkAlgorithmExecutor: + def __init__(self, flow_network): + self.flow_network = flow_network + self.verticies_count = flow_network.verticesCount + self.source_index = flow_network.sourceIndex + self.sink_index = flow_network.sinkIndex + # it's just a reference, so you shouldn't change + # it in your algorithms, use deep copy before doing that + self.graph = flow_network.graph + self.executed = False + + def execute(self): + if not self.executed: + self._algorithm() + self.executed = True + + # You should override it + def _algorithm(self): + pass + + +class MaximumFlowAlgorithmExecutor(FlowNetworkAlgorithmExecutor): + def __init__(self, flow_network): + super().__init__(flow_network) + # use this to save your result + self.maximum_flow = -1 + + def get_maximum_flow(self): + if not self.executed: + raise Exception("You should execute algorithm before using its result!") + + return self.maximum_flow + + +class PushRelabelExecutor(MaximumFlowAlgorithmExecutor): + def __init__(self, flow_network): + super().__init__(flow_network) + + self.preflow = [[0] * self.verticies_count for i in range(self.verticies_count)] + + self.heights = [0] * self.verticies_count + self.excesses = [0] * self.verticies_count + + def _algorithm(self): + self.heights[self.source_index] = self.verticies_count + + # push some substance to graph + for nextvertex_index, bandwidth in enumerate(self.graph[self.source_index]): + self.preflow[self.source_index][nextvertex_index] += bandwidth + self.preflow[nextvertex_index][self.source_index] -= bandwidth + self.excesses[nextvertex_index] += bandwidth + + # Relabel-to-front selection rule + vertices_list = [ + i + for i in range(self.verticies_count) + if i not in {self.source_index, self.sink_index} + ] + + # move through list + i = 0 + while i < len(vertices_list): + vertex_index = vertices_list[i] + previous_height = self.heights[vertex_index] + self.process_vertex(vertex_index) + if self.heights[vertex_index] > previous_height: + # if it was relabeled, swap elements + # and start from 0 index + vertices_list.insert(0, vertices_list.pop(i)) + i = 0 + else: + i += 1 + + self.maximum_flow = sum(self.preflow[self.source_index]) + + def process_vertex(self, vertex_index): + while self.excesses[vertex_index] > 0: + for neighbour_index in range(self.verticies_count): + # if it's neighbour and current vertex is higher + if ( + self.graph[vertex_index][neighbour_index] + - self.preflow[vertex_index][neighbour_index] + > 0 + and self.heights[vertex_index] > self.heights[neighbour_index] + ): + self.push(vertex_index, neighbour_index) + + self.relabel(vertex_index) + + def push(self, from_index, to_index): + preflow_delta = min( + self.excesses[from_index], + self.graph[from_index][to_index] - self.preflow[from_index][to_index], + ) + self.preflow[from_index][to_index] += preflow_delta + self.preflow[to_index][from_index] -= preflow_delta + self.excesses[from_index] -= preflow_delta + self.excesses[to_index] += preflow_delta + + def relabel(self, vertex_index): + min_height = None + for to_index in range(self.verticies_count): + if ( + self.graph[vertex_index][to_index] + - self.preflow[vertex_index][to_index] + > 0 + ) and (min_height is None or self.heights[to_index] < min_height): + min_height = self.heights[to_index] + + if min_height is not None: + self.heights[vertex_index] = min_height + 1 + + +if __name__ == "__main__": + entrances = [0] + exits = [3] + # graph = [ + # [0, 0, 4, 6, 0, 0], + # [0, 0, 5, 2, 0, 0], + # [0, 0, 0, 0, 4, 4], + # [0, 0, 0, 0, 6, 6], + # [0, 0, 0, 0, 0, 0], + # [0, 0, 0, 0, 0, 0], + # ] + graph = [[0, 7, 0, 0], [0, 0, 6, 0], [0, 0, 0, 8], [9, 0, 0, 0]] + + # prepare our network + flow_network = FlowNetwork(graph, entrances, exits) + # set algorithm + flow_network.set_maximum_flow_algorithm(PushRelabelExecutor) + # and calculate + maximum_flow = flow_network.find_maximum_flow() + + print(f"maximum flow is {maximum_flow}") diff --git a/python/Graphs/eulerian_path_and_circuit_for_undirected_graph.py b/python/Graphs/eulerian_path_and_circuit_for_undirected_graph.py new file mode 100644 index 00000000..5b146eaa --- /dev/null +++ b/python/Graphs/eulerian_path_and_circuit_for_undirected_graph.py @@ -0,0 +1,71 @@ +# Eulerian Path is a path in graph that visits every edge exactly once. +# Eulerian Circuit is an Eulerian Path which starts and ends on the same +# vertex. +# time complexity is O(V+E) +# space complexity is O(VE) + + +# using dfs for finding eulerian path traversal +def dfs(u, graph, visited_edge, path=None): + path = (path or []) + [u] + for v in graph[u]: + if visited_edge[u][v] is False: + visited_edge[u][v], visited_edge[v][u] = True, True + path = dfs(v, graph, visited_edge, path) + return path + + +# for checking in graph has euler path or circuit +def check_circuit_or_path(graph, max_node): + odd_degree_nodes = 0 + odd_node = -1 + for i in range(max_node): + if i not in graph: + continue + if len(graph[i]) % 2 == 1: + odd_degree_nodes += 1 + odd_node = i + if odd_degree_nodes == 0: + return 1, odd_node + if odd_degree_nodes == 2: + return 2, odd_node + return 3, odd_node + + +def check_euler(graph, max_node): + visited_edge = [[False for _ in range(max_node + 1)] for _ in range(max_node + 1)] + check, odd_node = check_circuit_or_path(graph, max_node) + if check == 3: + print("graph is not Eulerian") + print("no path") + return + start_node = 1 + if check == 2: + start_node = odd_node + print("graph has a Euler path") + if check == 1: + print("graph has a Euler cycle") + path = dfs(start_node, graph, visited_edge) + print(path) + + +def main(): + g1 = {1: [2, 3, 4], 2: [1, 3], 3: [1, 2], 4: [1, 5], 5: [4]} + g2 = {1: [2, 3, 4, 5], 2: [1, 3], 3: [1, 2], 4: [1, 5], 5: [1, 4]} + g3 = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2], 4: [1, 2, 5], 5: [4]} + g4 = {1: [2, 3], 2: [1, 3], 3: [1, 2]} + g5 = { + 1: [], + 2: [], + # all degree is zero + } + max_node = 10 + check_euler(g1, max_node) + check_euler(g2, max_node) + check_euler(g3, max_node) + check_euler(g4, max_node) + check_euler(g5, max_node) + + +if __name__ == "__main__": + main() diff --git a/python/Graphs/even_tree.py b/python/Graphs/even_tree.py new file mode 100644 index 00000000..7d478995 --- /dev/null +++ b/python/Graphs/even_tree.py @@ -0,0 +1,60 @@ +""" +You are given a tree(a simple connected graph with no cycles). The tree has N +nodes numbered from 1 to N and is rooted at node 1. + +Find the maximum number of edges you can remove from the tree to get a forest +such that each connected component of the forest contains an even number of +nodes. + +Constraints +2 <= 2 <= 100 + +Note: The tree input will be such that it can always be decomposed into +components containing an even number of nodes. +""" + +# pylint: disable=invalid-name +from collections import defaultdict + + +def dfs(start: int) -> int: + """DFS traversal""" + # pylint: disable=redefined-outer-name + ret = 1 + visited[start] = True + for v in tree[start]: + if v not in visited: + ret += dfs(v) + if ret % 2 == 0: + cuts.append(start) + return ret + + +def even_tree(): + """ + 2 1 + 3 1 + 4 3 + 5 2 + 6 1 + 7 2 + 8 6 + 9 8 + 10 8 + On removing edges (1,3) and (1,6), we can get the desired result 2. + """ + dfs(1) + + +if __name__ == "__main__": + n, m = 10, 9 + tree = defaultdict(list) + visited: dict[int, bool] = {} + cuts: list[int] = [] + count = 0 + edges = [(2, 1), (3, 1), (4, 3), (5, 2), (6, 1), (7, 2), (8, 6), (9, 8), (10, 8)] + for u, v in edges: + tree[u].append(v) + tree[v].append(u) + even_tree() + print(len(cuts) - 1) diff --git a/python/Graphs/finding_bridges.py b/python/Graphs/finding_bridges.py new file mode 100644 index 00000000..c1760674 --- /dev/null +++ b/python/Graphs/finding_bridges.py @@ -0,0 +1,106 @@ +""" +An edge is a bridge if, after removing it count of connected components in graph will +be increased by one. Bridges represent vulnerabilities in a connected network and are +useful for designing reliable networks. For example, in a wired computer network, an +articulation point indicates the critical computers and a bridge indicates the critical +wires or connections. + +For more details, refer this article: +https://www.geeksforgeeks.org/bridge-in-a-graph/ +""" + + +def __get_demo_graph(index): + return [ + { + 0: [1, 2], + 1: [0, 2], + 2: [0, 1, 3, 5], + 3: [2, 4], + 4: [3], + 5: [2, 6, 8], + 6: [5, 7], + 7: [6, 8], + 8: [5, 7], + }, + { + 0: [6], + 1: [9], + 2: [4, 5], + 3: [4], + 4: [2, 3], + 5: [2], + 6: [0, 7], + 7: [6], + 8: [], + 9: [1], + }, + { + 0: [4], + 1: [6], + 2: [], + 3: [5, 6, 7], + 4: [0, 6], + 5: [3, 8, 9], + 6: [1, 3, 4, 7], + 7: [3, 6, 8, 9], + 8: [5, 7], + 9: [5, 7], + }, + { + 0: [1, 3], + 1: [0, 2, 4], + 2: [1, 3, 4], + 3: [0, 2, 4], + 4: [1, 2, 3], + }, + ][index] + + +def compute_bridges(graph: dict[int, list[int]]) -> list[tuple[int, int]]: + """ + Return the list of undirected graph bridges [(a1, b1), ..., (ak, bk)]; ai <= bi + >>> compute_bridges(__get_demo_graph(0)) + [(3, 4), (2, 3), (2, 5)] + >>> compute_bridges(__get_demo_graph(1)) + [(6, 7), (0, 6), (1, 9), (3, 4), (2, 4), (2, 5)] + >>> compute_bridges(__get_demo_graph(2)) + [(1, 6), (4, 6), (0, 4)] + >>> compute_bridges(__get_demo_graph(3)) + [] + >>> compute_bridges({}) + [] + """ + + id_ = 0 + n = len(graph) # No of vertices in graph + low = [0] * n + visited = [False] * n + + def dfs(at, parent, bridges, id_): + visited[at] = True + low[at] = id_ + id_ += 1 + for to in graph[at]: + if to == parent: + pass + elif not visited[to]: + dfs(to, at, bridges, id_) + low[at] = min(low[at], low[to]) + if id_ <= low[to]: + bridges.append((at, to) if at < to else (to, at)) + else: + # This edge is a back edge and cannot be a bridge + low[at] = min(low[at], low[to]) + + bridges: list[tuple[int, int]] = [] + for i in range(n): + if not visited[i]: + dfs(i, -1, bridges, id_) + return bridges + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/frequent_pattern_graph_miner.py b/python/Graphs/frequent_pattern_graph_miner.py new file mode 100644 index 00000000..f8da73f3 --- /dev/null +++ b/python/Graphs/frequent_pattern_graph_miner.py @@ -0,0 +1,233 @@ +""" +FP-GraphMiner - A Fast Frequent Pattern Mining Algorithm for Network Graphs + +A novel Frequent Pattern Graph Mining algorithm, FP-GraphMiner, that compactly +represents a set of network graphs as a Frequent Pattern Graph (or FP-Graph). +This graph can be used to efficiently mine frequent subgraphs including maximal +frequent subgraphs and maximum common subgraphs. + +URL: https://www.researchgate.net/publication/235255851 +""" + +# fmt: off +edge_array = [ + ['ab-e1', 'ac-e3', 'ad-e5', 'bc-e4', 'bd-e2', 'be-e6', 'bh-e12', 'cd-e2', 'ce-e4', + 'de-e1', 'df-e8', 'dg-e5', 'dh-e10', 'ef-e3', 'eg-e2', 'fg-e6', 'gh-e6', 'hi-e3'], + ['ab-e1', 'ac-e3', 'ad-e5', 'bc-e4', 'bd-e2', 'be-e6', 'cd-e2', 'de-e1', 'df-e8', + 'ef-e3', 'eg-e2', 'fg-e6'], + ['ab-e1', 'ac-e3', 'bc-e4', 'bd-e2', 'de-e1', 'df-e8', 'dg-e5', 'ef-e3', 'eg-e2', + 'eh-e12', 'fg-e6', 'fh-e10', 'gh-e6'], + ['ab-e1', 'ac-e3', 'bc-e4', 'bd-e2', 'bh-e12', 'cd-e2', 'df-e8', 'dh-e10'], + ['ab-e1', 'ac-e3', 'ad-e5', 'bc-e4', 'bd-e2', 'cd-e2', 'ce-e4', 'de-e1', 'df-e8', + 'dg-e5', 'ef-e3', 'eg-e2', 'fg-e6'] +] +# fmt: on + + +def get_distinct_edge(edge_array): + """ + Return Distinct edges from edge array of multiple graphs + >>> sorted(get_distinct_edge(edge_array)) + ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + """ + distinct_edge = set() + for row in edge_array: + for item in row: + distinct_edge.add(item[0]) + return list(distinct_edge) + + +def get_bitcode(edge_array, distinct_edge): + """ + Return bitcode of distinct_edge + """ + bitcode = ["0"] * len(edge_array) + for i, row in enumerate(edge_array): + for item in row: + if distinct_edge in item[0]: + bitcode[i] = "1" + break + return "".join(bitcode) + + +def get_frequency_table(edge_array): + """ + Returns Frequency Table + """ + distinct_edge = get_distinct_edge(edge_array) + frequency_table = {} + + for item in distinct_edge: + bit = get_bitcode(edge_array, item) + # print('bit',bit) + # bt=''.join(bit) + s = bit.count("1") + frequency_table[item] = [s, bit] + # Store [Distinct edge, WT(Bitcode), Bitcode] in descending order + sorted_frequency_table = [ + [k, v[0], v[1]] + for k, v in sorted(frequency_table.items(), key=lambda v: v[1][0], reverse=True) + ] + return sorted_frequency_table + + +def get_nodes(frequency_table): + """ + Returns nodes + format nodes={bitcode:edges that represent the bitcode} + >>> get_nodes([['ab', 5, '11111'], ['ac', 5, '11111'], ['df', 5, '11111'], + ... ['bd', 5, '11111'], ['bc', 5, '11111']]) + {'11111': ['ab', 'ac', 'df', 'bd', 'bc']} + """ + nodes = {} + for _, item in enumerate(frequency_table): + nodes.setdefault(item[2], []).append(item[0]) + return nodes + + +def get_cluster(nodes): + """ + Returns cluster + format cluster:{WT(bitcode):nodes with same WT} + """ + cluster = {} + for key, value in nodes.items(): + cluster.setdefault(key.count("1"), {})[key] = value + return cluster + + +def get_support(cluster): + """ + Returns support + >>> get_support({5: {'11111': ['ab', 'ac', 'df', 'bd', 'bc']}, + ... 4: {'11101': ['ef', 'eg', 'de', 'fg'], '11011': ['cd']}, + ... 3: {'11001': ['ad'], '10101': ['dg']}, + ... 2: {'10010': ['dh', 'bh'], '11000': ['be'], '10100': ['gh'], + ... '10001': ['ce']}, + ... 1: {'00100': ['fh', 'eh'], '10000': ['hi']}}) + [100.0, 80.0, 60.0, 40.0, 20.0] + """ + return [i * 100 / len(cluster) for i in cluster] + + +def print_all() -> None: + print("\nNodes\n") + for key, value in nodes.items(): + print(key, value) + print("\nSupport\n") + print(support) + print("\n Cluster \n") + for key, value in sorted(cluster.items(), reverse=True): + print(key, value) + print("\n Graph\n") + for key, value in graph.items(): + print(key, value) + print("\n Edge List of Frequent subgraphs \n") + for edge_list in freq_subgraph_edge_list: + print(edge_list) + + +def create_edge(nodes, graph, cluster, c1): + """ + create edge between the nodes + """ + for i in cluster[c1]: + count = 0 + c2 = c1 + 1 + while c2 < max(cluster.keys()): + for j in cluster[c2]: + """ + creates edge only if the condition satisfies + """ + if int(i, 2) & int(j, 2) == int(i, 2): + if tuple(nodes[i]) in graph: + graph[tuple(nodes[i])].append(nodes[j]) + else: + graph[tuple(nodes[i])] = [nodes[j]] + count += 1 + if count == 0: + c2 = c2 + 1 + else: + break + + +def construct_graph(cluster, nodes): + x = cluster[max(cluster.keys())] + cluster[max(cluster.keys()) + 1] = "Header" + graph = {} + for i in x: + if (["Header"],) in graph: + graph[(["Header"],)].append(x[i]) + else: + graph[(["Header"],)] = [x[i]] + for i in x: + graph[(x[i],)] = [["Header"]] + i = 1 + while i < max(cluster) - 1: + create_edge(nodes, graph, cluster, i) + i = i + 1 + return graph + + +def my_dfs(graph, start, end, path=None): + """ + find different DFS walk from given node to Header node + """ + path = (path or []) + [start] + if start == end: + paths.append(path) + for node in graph[start]: + if tuple(node) not in path: + my_dfs(graph, tuple(node), end, path) + + +def find_freq_subgraph_given_support(s, cluster, graph): + """ + find edges of multiple frequent subgraphs + """ + k = int(s / 100 * (len(cluster) - 1)) + for i in cluster[k]: + my_dfs(graph, tuple(cluster[k][i]), (["Header"],)) + + +def freq_subgraphs_edge_list(paths): + """ + returns Edge list for frequent subgraphs + """ + freq_sub_el = [] + for edges in paths: + el = [] + for j in range(len(edges) - 1): + temp = list(edges[j]) + for e in temp: + edge = (e[0], e[1]) + el.append(edge) + freq_sub_el.append(el) + return freq_sub_el + + +def preprocess(edge_array): + """ + Preprocess the edge array + >>> preprocess([['ab-e1', 'ac-e3', 'ad-e5', 'bc-e4', 'bd-e2', 'be-e6', 'bh-e12', + ... 'cd-e2', 'ce-e4', 'de-e1', 'df-e8', 'dg-e5', 'dh-e10', 'ef-e3', + ... 'eg-e2', 'fg-e6', 'gh-e6', 'hi-e3']]) + + """ + for i in range(len(edge_array)): + for j in range(len(edge_array[i])): + t = edge_array[i][j].split("-") + edge_array[i][j] = t + + +if __name__ == "__main__": + preprocess(edge_array) + frequency_table = get_frequency_table(edge_array) + nodes = get_nodes(frequency_table) + cluster = get_cluster(nodes) + support = get_support(cluster) + graph = construct_graph(cluster, nodes) + find_freq_subgraph_given_support(60, cluster, graph) + paths: list = [] + freq_subgraph_edge_list = freq_subgraphs_edge_list(paths) + print_all() diff --git a/python/Graphs/g_topological_sort.py b/python/Graphs/g_topological_sort.py new file mode 100644 index 00000000..77543d51 --- /dev/null +++ b/python/Graphs/g_topological_sort.py @@ -0,0 +1,47 @@ +# Author: Phyllipe Bezerra (https://github.com/pmba) + +clothes = { + 0: "underwear", + 1: "pants", + 2: "belt", + 3: "suit", + 4: "shoe", + 5: "socks", + 6: "shirt", + 7: "tie", + 8: "watch", +} + +graph = [[1, 4], [2, 4], [3], [], [], [4], [2, 7], [3], []] + +visited = [0 for x in range(len(graph))] +stack = [] + + +def print_stack(stack, clothes): + order = 1 + while stack: + current_clothing = stack.pop() + print(order, clothes[current_clothing]) + order += 1 + + +def depth_first_search(u, visited, graph): + visited[u] = 1 + for v in graph[u]: + if not visited[v]: + depth_first_search(v, visited, graph) + + stack.append(u) + + +def topological_sort(graph, visited): + for v in range(len(graph)): + if not visited[v]: + depth_first_search(v, visited, graph) + + +if __name__ == "__main__": + topological_sort(graph, visited) + print(stack) + print_stack(stack, clothes) diff --git a/python/Graphs/gale_shapley_bigraph.py b/python/Graphs/gale_shapley_bigraph.py new file mode 100644 index 00000000..f4b31538 --- /dev/null +++ b/python/Graphs/gale_shapley_bigraph.py @@ -0,0 +1,49 @@ +from __future__ import annotations + + +def stable_matching( + donor_pref: list[list[int]], recipient_pref: list[list[int]] +) -> list[int]: + """ + Finds the stable match in any bipartite graph, i.e a pairing where no 2 objects + prefer each other over their partner. The function accepts the preferences of + oegan donors and recipients (where both are assigned numbers from 0 to n-1) and + returns a list where the index position corresponds to the donor and value at the + index is the organ recipient. + + To better understand the algorithm, see also: + https://github.com/akashvshroff/Gale_Shapley_Stable_Matching (README). + https://www.youtube.com/watch?v=Qcv1IqHWAzg&t=13s (Numberphile YouTube). + + >>> donor_pref = [[0, 1, 3, 2], [0, 2, 3, 1], [1, 0, 2, 3], [0, 3, 1, 2]] + >>> recipient_pref = [[3, 1, 2, 0], [3, 1, 0, 2], [0, 3, 1, 2], [1, 0, 3, 2]] + >>> stable_matching(donor_pref, recipient_pref) + [1, 2, 3, 0] + """ + assert len(donor_pref) == len(recipient_pref) + + n = len(donor_pref) + unmatched_donors = list(range(n)) + donor_record = [-1] * n # who the donor has donated to + rec_record = [-1] * n # who the recipient has received from + num_donations = [0] * n + + while unmatched_donors: + donor = unmatched_donors[0] + donor_preference = donor_pref[donor] + recipient = donor_preference[num_donations[donor]] + num_donations[donor] += 1 + rec_preference = recipient_pref[recipient] + prev_donor = rec_record[recipient] + + if prev_donor != -1: + if rec_preference.index(prev_donor) > rec_preference.index(donor): + rec_record[recipient] = donor + donor_record[donor] = recipient + unmatched_donors.append(prev_donor) + unmatched_donors.remove(donor) + else: + rec_record[recipient] = donor + donor_record[donor] = recipient + unmatched_donors.remove(donor) + return donor_record diff --git a/python/Graphs/graph_adjacency_list.py b/python/Graphs/graph_adjacency_list.py new file mode 100644 index 00000000..34014d69 --- /dev/null +++ b/python/Graphs/graph_adjacency_list.py @@ -0,0 +1,597 @@ +#!/usr/bin/env python3 +""" +Author: Vikram Nithyanandam + +Description: +The following implementation is a robust unweighted Graph data structure +implemented using an adjacency list. This vertices and edges of this graph can be +effectively initialized and modified while storing your chosen generic +value in each vertex. + +Adjacency List: https://en.wikipedia.org/wiki/Adjacency_list + +Potential Future Ideas: +- Add a flag to set edge weights on and set edge weights +- Make edge weights and vertex values customizable to store whatever the client wants +- Support multigraph functionality if the client wants it +""" + +from __future__ import annotations + +import random +import unittest +from pprint import pformat +from typing import TypeVar + +import pytest + +T = TypeVar("T") + + +class GraphAdjacencyList[T]: + def __init__( + self, vertices: list[T], edges: list[list[T]], directed: bool = True + ) -> None: + """ + Parameters: + - vertices: (list[T]) The list of vertex names the client wants to + pass in. Default is empty. + - edges: (list[list[T]]) The list of edges the client wants to + pass in. Each edge is a 2-element list. Default is empty. + - directed: (bool) Indicates if graph is directed or undirected. + Default is True. + """ + self.adj_list: dict[T, list[T]] = {} # dictionary of lists of T + self.directed = directed + + # Falsey checks + edges = edges or [] + vertices = vertices or [] + + for vertex in vertices: + self.add_vertex(vertex) + + for edge in edges: + if len(edge) != 2: + msg = f"Invalid input: {edge} is the wrong length." + raise ValueError(msg) + self.add_edge(edge[0], edge[1]) + + def add_vertex(self, vertex: T) -> None: + """ + Adds a vertex to the graph. If the given vertex already exists, + a ValueError will be thrown. + + >>> g = GraphAdjacencyList(vertices=[], edges=[], directed=False) + >>> g.add_vertex("A") + >>> g.adj_list + {'A': []} + >>> g.add_vertex("A") + Traceback (most recent call last): + ... + ValueError: Incorrect input: A is already in the graph. + """ + if self.contains_vertex(vertex): + msg = f"Incorrect input: {vertex} is already in the graph." + raise ValueError(msg) + self.adj_list[vertex] = [] + + def add_edge(self, source_vertex: T, destination_vertex: T) -> None: + """ + Creates an edge from source vertex to destination vertex. If any + given vertex doesn't exist or the edge already exists, a ValueError + will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} or " + f"{destination_vertex} does not exist" + ) + raise ValueError(msg) + if self.contains_edge(source_vertex, destination_vertex): + msg = ( + "Incorrect input: The edge already exists between " + f"{source_vertex} and {destination_vertex}" + ) + raise ValueError(msg) + + # add the destination vertex to the list associated with the source vertex + # and vice versa if not directed + self.adj_list[source_vertex].append(destination_vertex) + if not self.directed: + self.adj_list[destination_vertex].append(source_vertex) + + def remove_vertex(self, vertex: T) -> None: + """ + Removes the given vertex from the graph and deletes all incoming and + outgoing edges from the given vertex as well. If the given vertex + does not exist, a ValueError will be thrown. + """ + if not self.contains_vertex(vertex): + msg = f"Incorrect input: {vertex} does not exist in this graph." + raise ValueError(msg) + + if not self.directed: + # If not directed, find all neighboring vertices and delete all references + # of edges connecting to the given vertex + for neighbor in self.adj_list[vertex]: + self.adj_list[neighbor].remove(vertex) + else: + # If directed, search all neighbors of all vertices and delete all + # references of edges connecting to the given vertex + for edge_list in self.adj_list.values(): + if vertex in edge_list: + edge_list.remove(vertex) + + # Finally, delete the given vertex and all of its outgoing edge references + self.adj_list.pop(vertex) + + def remove_edge(self, source_vertex: T, destination_vertex: T) -> None: + """ + Removes the edge between the two vertices. If any given vertex + doesn't exist or the edge does not exist, a ValueError will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} or " + f"{destination_vertex} does not exist" + ) + raise ValueError(msg) + if not self.contains_edge(source_vertex, destination_vertex): + msg = ( + "Incorrect input: The edge does NOT exist between " + f"{source_vertex} and {destination_vertex}" + ) + raise ValueError(msg) + + # remove the destination vertex from the list associated with the source + # vertex and vice versa if not directed + self.adj_list[source_vertex].remove(destination_vertex) + if not self.directed: + self.adj_list[destination_vertex].remove(source_vertex) + + def contains_vertex(self, vertex: T) -> bool: + """ + Returns True if the graph contains the vertex, False otherwise. + """ + return vertex in self.adj_list + + def contains_edge(self, source_vertex: T, destination_vertex: T) -> bool: + """ + Returns True if the graph contains the edge from the source_vertex to the + destination_vertex, False otherwise. If any given vertex doesn't exist, a + ValueError will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} " + f"or {destination_vertex} does not exist." + ) + raise ValueError(msg) + + return destination_vertex in self.adj_list[source_vertex] + + def clear_graph(self) -> None: + """ + Clears all vertices and edges. + """ + self.adj_list = {} + + def __repr__(self) -> str: + return pformat(self.adj_list) + + +class TestGraphAdjacencyList(unittest.TestCase): + def __assert_graph_edge_exists_check( + self, + undirected_graph: GraphAdjacencyList, + directed_graph: GraphAdjacencyList, + edge: list[int], + ) -> None: + assert undirected_graph.contains_edge(edge[0], edge[1]) + assert undirected_graph.contains_edge(edge[1], edge[0]) + assert directed_graph.contains_edge(edge[0], edge[1]) + + def __assert_graph_edge_does_not_exist_check( + self, + undirected_graph: GraphAdjacencyList, + directed_graph: GraphAdjacencyList, + edge: list[int], + ) -> None: + assert not undirected_graph.contains_edge(edge[0], edge[1]) + assert not undirected_graph.contains_edge(edge[1], edge[0]) + assert not directed_graph.contains_edge(edge[0], edge[1]) + + def __assert_graph_vertex_exists_check( + self, + undirected_graph: GraphAdjacencyList, + directed_graph: GraphAdjacencyList, + vertex: int, + ) -> None: + assert undirected_graph.contains_vertex(vertex) + assert directed_graph.contains_vertex(vertex) + + def __assert_graph_vertex_does_not_exist_check( + self, + undirected_graph: GraphAdjacencyList, + directed_graph: GraphAdjacencyList, + vertex: int, + ) -> None: + assert not undirected_graph.contains_vertex(vertex) + assert not directed_graph.contains_vertex(vertex) + + def __generate_random_edges( + self, vertices: list[int], edge_pick_count: int + ) -> list[list[int]]: + assert edge_pick_count <= len(vertices) + + random_source_vertices: list[int] = random.sample( + vertices[0 : int(len(vertices) / 2)], edge_pick_count + ) + random_destination_vertices: list[int] = random.sample( + vertices[int(len(vertices) / 2) :], edge_pick_count + ) + random_edges: list[list[int]] = [] + + for source in random_source_vertices: + for dest in random_destination_vertices: + random_edges.append([source, dest]) + + return random_edges + + def __generate_graphs( + self, vertex_count: int, min_val: int, max_val: int, edge_pick_count: int + ) -> tuple[GraphAdjacencyList, GraphAdjacencyList, list[int], list[list[int]]]: + if max_val - min_val + 1 < vertex_count: + raise ValueError( + "Will result in duplicate vertices. Either increase range " + "between min_val and max_val or decrease vertex count." + ) + + # generate graph input + random_vertices: list[int] = random.sample( + range(min_val, max_val + 1), vertex_count + ) + random_edges: list[list[int]] = self.__generate_random_edges( + random_vertices, edge_pick_count + ) + + # build graphs + undirected_graph = GraphAdjacencyList( + vertices=random_vertices, edges=random_edges, directed=False + ) + directed_graph = GraphAdjacencyList( + vertices=random_vertices, edges=random_edges, directed=True + ) + + return undirected_graph, directed_graph, random_vertices, random_edges + + def test_init_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # test graph initialization with vertices and edges + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + for edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + assert not undirected_graph.directed + assert directed_graph.directed + + def test_contains_vertex(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # Build graphs WITHOUT edges + undirected_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=True + ) + + # Test contains_vertex + for num in range(101): + assert (num in random_vertices) == undirected_graph.contains_vertex(num) + assert (num in random_vertices) == directed_graph.contains_vertex(num) + + def test_add_vertices(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # build empty graphs + undirected_graph: GraphAdjacencyList = GraphAdjacencyList( + vertices=[], edges=[], directed=False + ) + directed_graph: GraphAdjacencyList = GraphAdjacencyList( + vertices=[], edges=[], directed=True + ) + + # run add_vertex + for num in random_vertices: + undirected_graph.add_vertex(num) + + for num in random_vertices: + directed_graph.add_vertex(num) + + # test add_vertex worked + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + def test_remove_vertices(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=True + ) + + # test remove_vertex worked + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + undirected_graph.remove_vertex(num) + directed_graph.remove_vertex(num) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, num + ) + + def test_add_and_remove_vertices_repeatedly(self) -> None: + random_vertices1: list[int] = random.sample(range(51), 20) + random_vertices2: list[int] = random.sample(range(51, 101), 20) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyList( + vertices=random_vertices1, edges=[], directed=False + ) + directed_graph = GraphAdjacencyList( + vertices=random_vertices1, edges=[], directed=True + ) + + # test adding and removing vertices + for i, _ in enumerate(random_vertices1): + undirected_graph.add_vertex(random_vertices2[i]) + directed_graph.add_vertex(random_vertices2[i]) + + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, random_vertices2[i] + ) + + undirected_graph.remove_vertex(random_vertices1[i]) + directed_graph.remove_vertex(random_vertices1[i]) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, random_vertices1[i] + ) + + # remove all vertices + for i, _ in enumerate(random_vertices1): + undirected_graph.remove_vertex(random_vertices2[i]) + directed_graph.remove_vertex(random_vertices2[i]) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, random_vertices2[i] + ) + + def test_contains_edge(self) -> None: + # generate graphs and graph input + vertex_count = 20 + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(vertex_count, 0, 100, 4) + + # generate all possible edges for testing + all_possible_edges: list[list[int]] = [] + for i in range(vertex_count - 1): + for j in range(i + 1, vertex_count): + all_possible_edges.append([random_vertices[i], random_vertices[j]]) + all_possible_edges.append([random_vertices[j], random_vertices[i]]) + + # test contains_edge function + for edge in all_possible_edges: + if edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + elif [edge[1], edge[0]] in random_edges: + # since this edge exists for undirected but the reverse + # may not exist for directed + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, [edge[1], edge[0]] + ) + else: + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, edge + ) + + def test_add_edge(self) -> None: + # generate graph input + random_vertices: list[int] = random.sample(range(101), 15) + random_edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyList( + vertices=random_vertices, edges=[], directed=True + ) + + # run and test add_edge + for edge in random_edges: + undirected_graph.add_edge(edge[0], edge[1]) + directed_graph.add_edge(edge[0], edge[1]) + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + + def test_remove_edge(self) -> None: + # generate graph input and graphs + ( + undirected_graph, + directed_graph, + _random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # run and test remove_edge + for edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + undirected_graph.remove_edge(edge[0], edge[1]) + directed_graph.remove_edge(edge[0], edge[1]) + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, edge + ) + + def test_add_and_remove_edges_repeatedly(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # make some more edge options! + more_random_edges: list[list[int]] = [] + + while len(more_random_edges) != len(random_edges): + edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + for edge in edges: + if len(more_random_edges) == len(random_edges): + break + elif edge not in more_random_edges and edge not in random_edges: + more_random_edges.append(edge) + + for i, _ in enumerate(random_edges): + undirected_graph.add_edge(more_random_edges[i][0], more_random_edges[i][1]) + directed_graph.add_edge(more_random_edges[i][0], more_random_edges[i][1]) + + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, more_random_edges[i] + ) + + undirected_graph.remove_edge(random_edges[i][0], random_edges[i][1]) + directed_graph.remove_edge(random_edges[i][0], random_edges[i][1]) + + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, random_edges[i] + ) + + def test_add_vertex_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for vertex in random_vertices: + with pytest.raises(ValueError): + undirected_graph.add_vertex(vertex) + with pytest.raises(ValueError): + directed_graph.add_vertex(vertex) + + def test_remove_vertex_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for i in range(101): + if i not in random_vertices: + with pytest.raises(ValueError): + undirected_graph.remove_vertex(i) + with pytest.raises(ValueError): + directed_graph.remove_vertex(i) + + def test_add_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + _random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for edge in random_edges: + with pytest.raises(ValueError): + undirected_graph.add_edge(edge[0], edge[1]) + with pytest.raises(ValueError): + directed_graph.add_edge(edge[0], edge[1]) + + def test_remove_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + more_random_edges: list[list[int]] = [] + + while len(more_random_edges) != len(random_edges): + edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + for edge in edges: + if len(more_random_edges) == len(random_edges): + break + elif edge not in more_random_edges and edge not in random_edges: + more_random_edges.append(edge) + + for edge in more_random_edges: + with pytest.raises(ValueError): + undirected_graph.remove_edge(edge[0], edge[1]) + with pytest.raises(ValueError): + directed_graph.remove_edge(edge[0], edge[1]) + + def test_contains_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for vertex in random_vertices: + with pytest.raises(ValueError): + undirected_graph.contains_edge(vertex, 102) + with pytest.raises(ValueError): + directed_graph.contains_edge(vertex, 102) + + with pytest.raises(ValueError): + undirected_graph.contains_edge(103, 102) + with pytest.raises(ValueError): + directed_graph.contains_edge(103, 102) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/Graphs/graph_adjacency_matrix.py b/python/Graphs/graph_adjacency_matrix.py new file mode 100644 index 00000000..6dca0fbb --- /dev/null +++ b/python/Graphs/graph_adjacency_matrix.py @@ -0,0 +1,609 @@ +#!/usr/bin/env python3 +""" +Author: Vikram Nithyanandam + +Description: +The following implementation is a robust unweighted Graph data structure +implemented using an adjacency matrix. This vertices and edges of this graph can be +effectively initialized and modified while storing your chosen generic +value in each vertex. + +Adjacency Matrix: https://mathworld.wolfram.com/AdjacencyMatrix.html + +Potential Future Ideas: +- Add a flag to set edge weights on and set edge weights +- Make edge weights and vertex values customizable to store whatever the client wants +- Support multigraph functionality if the client wants it +""" + +from __future__ import annotations + +import random +import unittest +from pprint import pformat +from typing import TypeVar + +import pytest + +T = TypeVar("T") + + +class GraphAdjacencyMatrix[T]: + def __init__( + self, vertices: list[T], edges: list[list[T]], directed: bool = True + ) -> None: + """ + Parameters: + - vertices: (list[T]) The list of vertex names the client wants to + pass in. Default is empty. + - edges: (list[list[T]]) The list of edges the client wants to + pass in. Each edge is a 2-element list. Default is empty. + - directed: (bool) Indicates if graph is directed or undirected. + Default is True. + """ + self.directed = directed + self.vertex_to_index: dict[T, int] = {} + self.adj_matrix: list[list[int]] = [] + + # Falsey checks + edges = edges or [] + vertices = vertices or [] + + for vertex in vertices: + self.add_vertex(vertex) + + for edge in edges: + if len(edge) != 2: + msg = f"Invalid input: {edge} must have length 2." + raise ValueError(msg) + self.add_edge(edge[0], edge[1]) + + def add_edge(self, source_vertex: T, destination_vertex: T) -> None: + """ + Creates an edge from source vertex to destination vertex. If any + given vertex doesn't exist or the edge already exists, a ValueError + will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} or " + f"{destination_vertex} does not exist" + ) + raise ValueError(msg) + if self.contains_edge(source_vertex, destination_vertex): + msg = ( + "Incorrect input: The edge already exists between " + f"{source_vertex} and {destination_vertex}" + ) + raise ValueError(msg) + + # Get the indices of the corresponding vertices and set their edge value to 1. + u: int = self.vertex_to_index[source_vertex] + v: int = self.vertex_to_index[destination_vertex] + self.adj_matrix[u][v] = 1 + if not self.directed: + self.adj_matrix[v][u] = 1 + + def remove_edge(self, source_vertex: T, destination_vertex: T) -> None: + """ + Removes the edge between the two vertices. If any given vertex + doesn't exist or the edge does not exist, a ValueError will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} or " + f"{destination_vertex} does not exist" + ) + raise ValueError(msg) + if not self.contains_edge(source_vertex, destination_vertex): + msg = ( + "Incorrect input: The edge does NOT exist between " + f"{source_vertex} and {destination_vertex}" + ) + raise ValueError(msg) + + # Get the indices of the corresponding vertices and set their edge value to 0. + u: int = self.vertex_to_index[source_vertex] + v: int = self.vertex_to_index[destination_vertex] + self.adj_matrix[u][v] = 0 + if not self.directed: + self.adj_matrix[v][u] = 0 + + def add_vertex(self, vertex: T) -> None: + """ + Adds a vertex to the graph. If the given vertex already exists, + a ValueError will be thrown. + """ + if self.contains_vertex(vertex): + msg = f"Incorrect input: {vertex} already exists in this graph." + raise ValueError(msg) + + # build column for vertex + for row in self.adj_matrix: + row.append(0) + + # build row for vertex and update other data structures + self.adj_matrix.append([0] * (len(self.adj_matrix) + 1)) + self.vertex_to_index[vertex] = len(self.adj_matrix) - 1 + + def remove_vertex(self, vertex: T) -> None: + """ + Removes the given vertex from the graph and deletes all incoming and + outgoing edges from the given vertex as well. If the given vertex + does not exist, a ValueError will be thrown. + """ + if not self.contains_vertex(vertex): + msg = f"Incorrect input: {vertex} does not exist in this graph." + raise ValueError(msg) + + # first slide up the rows by deleting the row corresponding to + # the vertex being deleted. + start_index = self.vertex_to_index[vertex] + self.adj_matrix.pop(start_index) + + # next, slide the columns to the left by deleting the values in + # the column corresponding to the vertex being deleted + for lst in self.adj_matrix: + lst.pop(start_index) + + # final clean up + self.vertex_to_index.pop(vertex) + + # decrement indices for vertices shifted by the deleted vertex in the adj matrix + for inner_vertex in self.vertex_to_index: + if self.vertex_to_index[inner_vertex] >= start_index: + self.vertex_to_index[inner_vertex] = ( + self.vertex_to_index[inner_vertex] - 1 + ) + + def contains_vertex(self, vertex: T) -> bool: + """ + Returns True if the graph contains the vertex, False otherwise. + """ + return vertex in self.vertex_to_index + + def contains_edge(self, source_vertex: T, destination_vertex: T) -> bool: + """ + Returns True if the graph contains the edge from the source_vertex to the + destination_vertex, False otherwise. If any given vertex doesn't exist, a + ValueError will be thrown. + """ + if not ( + self.contains_vertex(source_vertex) + and self.contains_vertex(destination_vertex) + ): + msg = ( + f"Incorrect input: Either {source_vertex} " + f"or {destination_vertex} does not exist." + ) + raise ValueError(msg) + + u = self.vertex_to_index[source_vertex] + v = self.vertex_to_index[destination_vertex] + return self.adj_matrix[u][v] == 1 + + def clear_graph(self) -> None: + """ + Clears all vertices and edges. + """ + self.vertex_to_index = {} + self.adj_matrix = [] + + def __repr__(self) -> str: + first = "Adj Matrix:\n" + pformat(self.adj_matrix) + second = "\nVertex to index mapping:\n" + pformat(self.vertex_to_index) + return first + second + + +class TestGraphMatrix(unittest.TestCase): + def __assert_graph_edge_exists_check( + self, + undirected_graph: GraphAdjacencyMatrix, + directed_graph: GraphAdjacencyMatrix, + edge: list[int], + ) -> None: + assert undirected_graph.contains_edge(edge[0], edge[1]) + assert undirected_graph.contains_edge(edge[1], edge[0]) + assert directed_graph.contains_edge(edge[0], edge[1]) + + def __assert_graph_edge_does_not_exist_check( + self, + undirected_graph: GraphAdjacencyMatrix, + directed_graph: GraphAdjacencyMatrix, + edge: list[int], + ) -> None: + assert not undirected_graph.contains_edge(edge[0], edge[1]) + assert not undirected_graph.contains_edge(edge[1], edge[0]) + assert not directed_graph.contains_edge(edge[0], edge[1]) + + def __assert_graph_vertex_exists_check( + self, + undirected_graph: GraphAdjacencyMatrix, + directed_graph: GraphAdjacencyMatrix, + vertex: int, + ) -> None: + assert undirected_graph.contains_vertex(vertex) + assert directed_graph.contains_vertex(vertex) + + def __assert_graph_vertex_does_not_exist_check( + self, + undirected_graph: GraphAdjacencyMatrix, + directed_graph: GraphAdjacencyMatrix, + vertex: int, + ) -> None: + assert not undirected_graph.contains_vertex(vertex) + assert not directed_graph.contains_vertex(vertex) + + def __generate_random_edges( + self, vertices: list[int], edge_pick_count: int + ) -> list[list[int]]: + assert edge_pick_count <= len(vertices) + + random_source_vertices: list[int] = random.sample( + vertices[0 : int(len(vertices) / 2)], edge_pick_count + ) + random_destination_vertices: list[int] = random.sample( + vertices[int(len(vertices) / 2) :], edge_pick_count + ) + random_edges: list[list[int]] = [] + + for source in random_source_vertices: + for dest in random_destination_vertices: + random_edges.append([source, dest]) + + return random_edges + + def __generate_graphs( + self, vertex_count: int, min_val: int, max_val: int, edge_pick_count: int + ) -> tuple[GraphAdjacencyMatrix, GraphAdjacencyMatrix, list[int], list[list[int]]]: + if max_val - min_val + 1 < vertex_count: + raise ValueError( + "Will result in duplicate vertices. Either increase " + "range between min_val and max_val or decrease vertex count" + ) + + # generate graph input + random_vertices: list[int] = random.sample( + range(min_val, max_val + 1), vertex_count + ) + random_edges: list[list[int]] = self.__generate_random_edges( + random_vertices, edge_pick_count + ) + + # build graphs + undirected_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=random_edges, directed=False + ) + directed_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=random_edges, directed=True + ) + + return undirected_graph, directed_graph, random_vertices, random_edges + + def test_init_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # test graph initialization with vertices and edges + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + for edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + + assert not undirected_graph.directed + assert directed_graph.directed + + def test_contains_vertex(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # Build graphs WITHOUT edges + undirected_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=True + ) + + # Test contains_vertex + for num in range(101): + assert (num in random_vertices) == undirected_graph.contains_vertex(num) + assert (num in random_vertices) == directed_graph.contains_vertex(num) + + def test_add_vertices(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # build empty graphs + undirected_graph: GraphAdjacencyMatrix = GraphAdjacencyMatrix( + vertices=[], edges=[], directed=False + ) + directed_graph: GraphAdjacencyMatrix = GraphAdjacencyMatrix( + vertices=[], edges=[], directed=True + ) + + # run add_vertex + for num in random_vertices: + undirected_graph.add_vertex(num) + + for num in random_vertices: + directed_graph.add_vertex(num) + + # test add_vertex worked + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + def test_remove_vertices(self) -> None: + random_vertices: list[int] = random.sample(range(101), 20) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=True + ) + + # test remove_vertex worked + for num in random_vertices: + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, num + ) + + undirected_graph.remove_vertex(num) + directed_graph.remove_vertex(num) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, num + ) + + def test_add_and_remove_vertices_repeatedly(self) -> None: + random_vertices1: list[int] = random.sample(range(51), 20) + random_vertices2: list[int] = random.sample(range(51, 101), 20) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyMatrix( + vertices=random_vertices1, edges=[], directed=False + ) + directed_graph = GraphAdjacencyMatrix( + vertices=random_vertices1, edges=[], directed=True + ) + + # test adding and removing vertices + for i, _ in enumerate(random_vertices1): + undirected_graph.add_vertex(random_vertices2[i]) + directed_graph.add_vertex(random_vertices2[i]) + + self.__assert_graph_vertex_exists_check( + undirected_graph, directed_graph, random_vertices2[i] + ) + + undirected_graph.remove_vertex(random_vertices1[i]) + directed_graph.remove_vertex(random_vertices1[i]) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, random_vertices1[i] + ) + + # remove all vertices + for i, _ in enumerate(random_vertices1): + undirected_graph.remove_vertex(random_vertices2[i]) + directed_graph.remove_vertex(random_vertices2[i]) + + self.__assert_graph_vertex_does_not_exist_check( + undirected_graph, directed_graph, random_vertices2[i] + ) + + def test_contains_edge(self) -> None: + # generate graphs and graph input + vertex_count = 20 + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(vertex_count, 0, 100, 4) + + # generate all possible edges for testing + all_possible_edges: list[list[int]] = [] + for i in range(vertex_count - 1): + for j in range(i + 1, vertex_count): + all_possible_edges.append([random_vertices[i], random_vertices[j]]) + all_possible_edges.append([random_vertices[j], random_vertices[i]]) + + # test contains_edge function + for edge in all_possible_edges: + if edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + elif [edge[1], edge[0]] in random_edges: + # since this edge exists for undirected but the reverse may + # not exist for directed + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, [edge[1], edge[0]] + ) + else: + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, edge + ) + + def test_add_edge(self) -> None: + # generate graph input + random_vertices: list[int] = random.sample(range(101), 15) + random_edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + + # build graphs WITHOUT edges + undirected_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=False + ) + directed_graph = GraphAdjacencyMatrix( + vertices=random_vertices, edges=[], directed=True + ) + + # run and test add_edge + for edge in random_edges: + undirected_graph.add_edge(edge[0], edge[1]) + directed_graph.add_edge(edge[0], edge[1]) + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + + def test_remove_edge(self) -> None: + # generate graph input and graphs + ( + undirected_graph, + directed_graph, + _random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # run and test remove_edge + for edge in random_edges: + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, edge + ) + undirected_graph.remove_edge(edge[0], edge[1]) + directed_graph.remove_edge(edge[0], edge[1]) + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, edge + ) + + def test_add_and_remove_edges_repeatedly(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + # make some more edge options! + more_random_edges: list[list[int]] = [] + + while len(more_random_edges) != len(random_edges): + edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + for edge in edges: + if len(more_random_edges) == len(random_edges): + break + elif edge not in more_random_edges and edge not in random_edges: + more_random_edges.append(edge) + + for i, _ in enumerate(random_edges): + undirected_graph.add_edge(more_random_edges[i][0], more_random_edges[i][1]) + directed_graph.add_edge(more_random_edges[i][0], more_random_edges[i][1]) + + self.__assert_graph_edge_exists_check( + undirected_graph, directed_graph, more_random_edges[i] + ) + + undirected_graph.remove_edge(random_edges[i][0], random_edges[i][1]) + directed_graph.remove_edge(random_edges[i][0], random_edges[i][1]) + + self.__assert_graph_edge_does_not_exist_check( + undirected_graph, directed_graph, random_edges[i] + ) + + def test_add_vertex_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for vertex in random_vertices: + with pytest.raises(ValueError): + undirected_graph.add_vertex(vertex) + with pytest.raises(ValueError): + directed_graph.add_vertex(vertex) + + def test_remove_vertex_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for i in range(101): + if i not in random_vertices: + with pytest.raises(ValueError): + undirected_graph.remove_vertex(i) + with pytest.raises(ValueError): + directed_graph.remove_vertex(i) + + def test_add_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + _random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for edge in random_edges: + with pytest.raises(ValueError): + undirected_graph.add_edge(edge[0], edge[1]) + with pytest.raises(ValueError): + directed_graph.add_edge(edge[0], edge[1]) + + def test_remove_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + more_random_edges: list[list[int]] = [] + + while len(more_random_edges) != len(random_edges): + edges: list[list[int]] = self.__generate_random_edges(random_vertices, 4) + for edge in edges: + if len(more_random_edges) == len(random_edges): + break + elif edge not in more_random_edges and edge not in random_edges: + more_random_edges.append(edge) + + for edge in more_random_edges: + with pytest.raises(ValueError): + undirected_graph.remove_edge(edge[0], edge[1]) + with pytest.raises(ValueError): + directed_graph.remove_edge(edge[0], edge[1]) + + def test_contains_edge_exception_check(self) -> None: + ( + undirected_graph, + directed_graph, + random_vertices, + _random_edges, + ) = self.__generate_graphs(20, 0, 100, 4) + + for vertex in random_vertices: + with pytest.raises(ValueError): + undirected_graph.contains_edge(vertex, 102) + with pytest.raises(ValueError): + directed_graph.contains_edge(vertex, 102) + + with pytest.raises(ValueError): + undirected_graph.contains_edge(103, 102) + with pytest.raises(ValueError): + directed_graph.contains_edge(103, 102) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/Graphs/graph_list.py b/python/Graphs/graph_list.py new file mode 100644 index 00000000..6b63590b --- /dev/null +++ b/python/Graphs/graph_list.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 + +# Author: OMKAR PATHAK, Nwachukwu Chidiebere + +# Use a Python dictionary to construct the graph. +from __future__ import annotations + +from pprint import pformat +from typing import TypeVar + +T = TypeVar("T") + + +class GraphAdjacencyList[T]: + """ + Adjacency List type Graph Data Structure that accounts for directed and undirected + Graphs. Initialize graph object indicating whether it's directed or undirected. + + Directed graph example: + >>> d_graph = GraphAdjacencyList() + >>> print(d_graph) + {} + >>> d_graph.add_edge(0, 1) + {0: [1], 1: []} + >>> d_graph.add_edge(1, 2).add_edge(1, 4).add_edge(1, 5) + {0: [1], 1: [2, 4, 5], 2: [], 4: [], 5: []} + >>> d_graph.add_edge(2, 0).add_edge(2, 6).add_edge(2, 7) + {0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []} + >>> d_graph + {0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []} + >>> print(repr(d_graph)) + {0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []} + + Undirected graph example: + >>> u_graph = GraphAdjacencyList(directed=False) + >>> u_graph.add_edge(0, 1) + {0: [1], 1: [0]} + >>> u_graph.add_edge(1, 2).add_edge(1, 4).add_edge(1, 5) + {0: [1], 1: [0, 2, 4, 5], 2: [1], 4: [1], 5: [1]} + >>> u_graph.add_edge(2, 0).add_edge(2, 6).add_edge(2, 7) + {0: [1, 2], 1: [0, 2, 4, 5], 2: [1, 0, 6, 7], 4: [1], 5: [1], 6: [2], 7: [2]} + >>> u_graph.add_edge(4, 5) + {0: [1, 2], + 1: [0, 2, 4, 5], + 2: [1, 0, 6, 7], + 4: [1, 5], + 5: [1, 4], + 6: [2], + 7: [2]} + >>> print(u_graph) + {0: [1, 2], + 1: [0, 2, 4, 5], + 2: [1, 0, 6, 7], + 4: [1, 5], + 5: [1, 4], + 6: [2], + 7: [2]} + >>> print(repr(u_graph)) + {0: [1, 2], + 1: [0, 2, 4, 5], + 2: [1, 0, 6, 7], + 4: [1, 5], + 5: [1, 4], + 6: [2], + 7: [2]} + >>> char_graph = GraphAdjacencyList(directed=False) + >>> char_graph.add_edge('a', 'b') + {'a': ['b'], 'b': ['a']} + >>> char_graph.add_edge('b', 'c').add_edge('b', 'e').add_edge('b', 'f') + {'a': ['b'], 'b': ['a', 'c', 'e', 'f'], 'c': ['b'], 'e': ['b'], 'f': ['b']} + >>> char_graph + {'a': ['b'], 'b': ['a', 'c', 'e', 'f'], 'c': ['b'], 'e': ['b'], 'f': ['b']} + """ + + def __init__(self, directed: bool = True) -> None: + """ + Parameters: + directed: (bool) Indicates if graph is directed or undirected. Default is True. + """ + + self.adj_list: dict[T, list[T]] = {} # dictionary of lists + self.directed = directed + + def add_edge( + self, source_vertex: T, destination_vertex: T + ) -> GraphAdjacencyList[T]: + """ + Connects vertices together. Creates and Edge from source vertex to destination + vertex. + Vertices will be created if not found in graph + """ + + if not self.directed: # For undirected graphs + # if both source vertex and destination vertex are both present in the + # adjacency list, add destination vertex to source vertex list of adjacent + # vertices and add source vertex to destination vertex list of adjacent + # vertices. + if source_vertex in self.adj_list and destination_vertex in self.adj_list: + self.adj_list[source_vertex].append(destination_vertex) + self.adj_list[destination_vertex].append(source_vertex) + # if only source vertex is present in adjacency list, add destination vertex + # to source vertex list of adjacent vertices, then create a new vertex with + # destination vertex as key and assign a list containing the source vertex + # as it's first adjacent vertex. + elif source_vertex in self.adj_list: + self.adj_list[source_vertex].append(destination_vertex) + self.adj_list[destination_vertex] = [source_vertex] + # if only destination vertex is present in adjacency list, add source vertex + # to destination vertex list of adjacent vertices, then create a new vertex + # with source vertex as key and assign a list containing the source vertex + # as it's first adjacent vertex. + elif destination_vertex in self.adj_list: + self.adj_list[destination_vertex].append(source_vertex) + self.adj_list[source_vertex] = [destination_vertex] + # if both source vertex and destination vertex are not present in adjacency + # list, create a new vertex with source vertex as key and assign a list + # containing the destination vertex as it's first adjacent vertex also + # create a new vertex with destination vertex as key and assign a list + # containing the source vertex as it's first adjacent vertex. + else: + self.adj_list[source_vertex] = [destination_vertex] + self.adj_list[destination_vertex] = [source_vertex] + # For directed graphs + # if both source vertex and destination vertex are present in adjacency + # list, add destination vertex to source vertex list of adjacent vertices. + elif source_vertex in self.adj_list and destination_vertex in self.adj_list: + self.adj_list[source_vertex].append(destination_vertex) + # if only source vertex is present in adjacency list, add destination + # vertex to source vertex list of adjacent vertices and create a new vertex + # with destination vertex as key, which has no adjacent vertex + elif source_vertex in self.adj_list: + self.adj_list[source_vertex].append(destination_vertex) + self.adj_list[destination_vertex] = [] + # if only destination vertex is present in adjacency list, create a new + # vertex with source vertex as key and assign a list containing destination + # vertex as first adjacent vertex + elif destination_vertex in self.adj_list: + self.adj_list[source_vertex] = [destination_vertex] + # if both source vertex and destination vertex are not present in adjacency + # list, create a new vertex with source vertex as key and a list containing + # destination vertex as it's first adjacent vertex. Then create a new vertex + # with destination vertex as key, which has no adjacent vertex + else: + self.adj_list[source_vertex] = [destination_vertex] + self.adj_list[destination_vertex] = [] + + return self + + def __repr__(self) -> str: + return pformat(self.adj_list) diff --git a/python/Graphs/graphs_floyd_warshall.py b/python/Graphs/graphs_floyd_warshall.py new file mode 100644 index 00000000..aaed9ac5 --- /dev/null +++ b/python/Graphs/graphs_floyd_warshall.py @@ -0,0 +1,102 @@ +# floyd_warshall.py +""" +The problem is to find the shortest distance between all pairs of vertices in a +weighted directed graph that can have negative edge weights. +""" + + +def _print_dist(dist, v): + print("\nThe shortest path matrix using Floyd Warshall algorithm\n") + for i in range(v): + for j in range(v): + if dist[i][j] != float("inf"): + print(int(dist[i][j]), end="\t") + else: + print("INF", end="\t") + print() + + +def floyd_warshall(graph, v): + """ + :param graph: 2D array calculated from weight[edge[i, j]] + :type graph: List[List[float]] + :param v: number of vertices + :type v: int + :return: shortest distance between all vertex pairs + distance[u][v] will contain the shortest distance from vertex u to v. + + 1. For all edges from v to n, distance[i][j] = weight(edge(i, j)). + 3. The algorithm then performs distance[i][j] = min(distance[i][j], distance[i][k] + + distance[k][j]) for each possible pair i, j of vertices. + 4. The above is repeated for each vertex k in the graph. + 5. Whenever distance[i][j] is given a new minimum value, next vertex[i][j] is + updated to the next vertex[i][k]. + """ + + dist = [[float("inf") for _ in range(v)] for _ in range(v)] + + for i in range(v): + for j in range(v): + dist[i][j] = graph[i][j] + + # check vertex k against all other vertices (i, j) + for k in range(v): + # looping through rows of graph array + for i in range(v): + # looping through columns of graph array + for j in range(v): + if ( + dist[i][k] != float("inf") + and dist[k][j] != float("inf") + and dist[i][k] + dist[k][j] < dist[i][j] + ): + dist[i][j] = dist[i][k] + dist[k][j] + + _print_dist(dist, v) + return dist, v + + +if __name__ == "__main__": + v = int(input("Enter number of vertices: ")) + e = int(input("Enter number of edges: ")) + + graph = [[float("inf") for i in range(v)] for j in range(v)] + + for i in range(v): + graph[i][i] = 0.0 + + # src and dst are indices that must be within the array size graph[e][v] + # failure to follow this will result in an error + for i in range(e): + print("\nEdge ", i + 1) + src = int(input("Enter source:")) + dst = int(input("Enter destination:")) + weight = float(input("Enter weight:")) + graph[src][dst] = weight + + floyd_warshall(graph, v) + + # Example Input + # Enter number of vertices: 3 + # Enter number of edges: 2 + + # # generated graph from vertex and edge inputs + # [[inf, inf, inf], [inf, inf, inf], [inf, inf, inf]] + # [[0.0, inf, inf], [inf, 0.0, inf], [inf, inf, 0.0]] + + # specify source, destination and weight for edge #1 + # Edge 1 + # Enter source:1 + # Enter destination:2 + # Enter weight:2 + + # specify source, destination and weight for edge #2 + # Edge 2 + # Enter source:2 + # Enter destination:1 + # Enter weight:1 + + # # Expected Output from the vertice, edge and src, dst, weight inputs!! + # 0 INF INF + # INF 0 2 + # INF 1 0 diff --git a/python/Graphs/greedy_best_first.py b/python/Graphs/greedy_best_first.py new file mode 100644 index 00000000..bb316004 --- /dev/null +++ b/python/Graphs/greedy_best_first.py @@ -0,0 +1,199 @@ +""" +https://en.wikipedia.org/wiki/Best-first_search#Greedy_BFS +""" + +from __future__ import annotations + +Path = list[tuple[int, int]] + +# 0's are free path whereas 1's are obstacles +TEST_GRIDS = [ + [ + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0], + [1, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0], + ], + [ + [0, 0, 0, 1, 1, 0, 0], + [0, 0, 0, 0, 1, 0, 1], + [0, 0, 0, 1, 1, 0, 0], + [0, 1, 0, 0, 1, 0, 0], + [1, 0, 0, 1, 1, 0, 1], + [0, 0, 0, 0, 0, 0, 0], + ], + [ + [0, 0, 1, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 1], + [1, 0, 0, 1, 1], + [0, 0, 0, 0, 0], + ], +] + +delta = ([-1, 0], [0, -1], [1, 0], [0, 1]) # up, left, down, right + + +class Node: + """ + >>> k = Node(0, 0, 4, 5, 0, None) + >>> k.calculate_heuristic() + 9 + >>> n = Node(1, 4, 3, 4, 2, None) + >>> n.calculate_heuristic() + 2 + >>> l = [k, n] + >>> n == l[0] + False + >>> l.sort() + >>> n == l[0] + True + """ + + def __init__( + self, + pos_x: int, + pos_y: int, + goal_x: int, + goal_y: int, + g_cost: float, + parent: Node | None, + ): + self.pos_x = pos_x + self.pos_y = pos_y + self.pos = (pos_y, pos_x) + self.goal_x = goal_x + self.goal_y = goal_y + self.g_cost = g_cost + self.parent = parent + self.f_cost = self.calculate_heuristic() + + def calculate_heuristic(self) -> float: + """ + The heuristic here is the Manhattan Distance + Could elaborate to offer more than one choice + """ + dx = abs(self.pos_x - self.goal_x) + dy = abs(self.pos_y - self.goal_y) + return dx + dy + + def __lt__(self, other) -> bool: + return self.f_cost < other.f_cost + + def __eq__(self, other) -> bool: + return self.pos == other.pos + + +class GreedyBestFirst: + """ + >>> grid = TEST_GRIDS[2] + >>> gbf = GreedyBestFirst(grid, (0, 0), (len(grid) - 1, len(grid[0]) - 1)) + >>> [x.pos for x in gbf.get_successors(gbf.start)] + [(1, 0), (0, 1)] + >>> (gbf.start.pos_y + delta[3][0], gbf.start.pos_x + delta[3][1]) + (0, 1) + >>> (gbf.start.pos_y + delta[2][0], gbf.start.pos_x + delta[2][1]) + (1, 0) + >>> gbf.retrace_path(gbf.start) + [(0, 0)] + >>> gbf.search() # doctest: +NORMALIZE_WHITESPACE + [(0, 0), (1, 0), (2, 0), (2, 1), (3, 1), (4, 1), (4, 2), (4, 3), + (4, 4)] + """ + + def __init__( + self, grid: list[list[int]], start: tuple[int, int], goal: tuple[int, int] + ): + self.grid = grid + self.start = Node(start[1], start[0], goal[1], goal[0], 0, None) + self.target = Node(goal[1], goal[0], goal[1], goal[0], 99999, None) + + self.open_nodes = [self.start] + self.closed_nodes: list[Node] = [] + + self.reached = False + + def search(self) -> Path | None: + """ + Search for the path, + if a path is not found, only the starting position is returned + """ + while self.open_nodes: + # Open Nodes are sorted using __lt__ + self.open_nodes.sort() + current_node = self.open_nodes.pop(0) + + if current_node.pos == self.target.pos: + self.reached = True + return self.retrace_path(current_node) + + self.closed_nodes.append(current_node) + successors = self.get_successors(current_node) + + for child_node in successors: + if child_node in self.closed_nodes: + continue + + if child_node not in self.open_nodes: + self.open_nodes.append(child_node) + + if not self.reached: + return [self.start.pos] + return None + + def get_successors(self, parent: Node) -> list[Node]: + """ + Returns a list of successors (both in the grid and free spaces) + """ + return [ + Node( + pos_x, + pos_y, + self.target.pos_x, + self.target.pos_y, + parent.g_cost + 1, + parent, + ) + for action in delta + if ( + 0 <= (pos_x := parent.pos_x + action[1]) < len(self.grid[0]) + and 0 <= (pos_y := parent.pos_y + action[0]) < len(self.grid) + and self.grid[pos_y][pos_x] == 0 + ) + ] + + def retrace_path(self, node: Node | None) -> Path: + """ + Retrace the path from parents to parents until start node + """ + current_node = node + path = [] + while current_node is not None: + path.append((current_node.pos_y, current_node.pos_x)) + current_node = current_node.parent + path.reverse() + return path + + +if __name__ == "__main__": + for idx, grid in enumerate(TEST_GRIDS): + print(f"==grid-{idx + 1}==") + + init = (0, 0) + goal = (len(grid) - 1, len(grid[0]) - 1) + for elem in grid: + print(elem) + + print("------") + + greedy_bf = GreedyBestFirst(grid, init, goal) + path = greedy_bf.search() + if path: + for pos_x, pos_y in path: + grid[pos_x][pos_y] = 2 + + for elem in grid: + print(elem) diff --git a/python/Graphs/greedy_min_vertex_cover.py b/python/Graphs/greedy_min_vertex_cover.py new file mode 100644 index 00000000..cdef6914 --- /dev/null +++ b/python/Graphs/greedy_min_vertex_cover.py @@ -0,0 +1,64 @@ +""" +* Author: Manuel Di Lullo (https://github.com/manueldilullo) +* Description: Approximization algorithm for minimum vertex cover problem. + Greedy Approach. Uses graphs represented with an adjacency list +URL: https://mathworld.wolfram.com/MinimumVertexCover.html +URL: https://cs.stackexchange.com/questions/129017/greedy-algorithm-for-vertex-cover +""" + +import heapq + + +def greedy_min_vertex_cover(graph: dict) -> set[int]: + """ + Greedy APX Algorithm for min Vertex Cover + @input: graph (graph stored in an adjacency list where each vertex + is represented with an integer) + @example: + >>> graph = {0: [1, 3], 1: [0, 3], 2: [0, 3, 4], 3: [0, 1, 2], 4: [2, 3]} + >>> greedy_min_vertex_cover(graph) + {0, 1, 2, 4} + """ + # queue used to store nodes and their rank + queue: list[list] = [] + + # for each node and his adjacency list add them and the rank of the node to queue + # using heapq module the queue will be filled like a Priority Queue + # heapq works with a min priority queue, so I used -1*len(v) to build it + for key, value in graph.items(): + # O(log(n)) + heapq.heappush(queue, [-1 * len(value), (key, value)]) + + # chosen_vertices = set of chosen vertices + chosen_vertices = set() + + # while queue isn't empty and there are still edges + # (queue[0][0] is the rank of the node with max rank) + while queue and queue[0][0] != 0: + # extract vertex with max rank from queue and add it to chosen_vertices + argmax = heapq.heappop(queue)[1][0] + chosen_vertices.add(argmax) + + # Remove all arcs adjacent to argmax + for elem in queue: + # if v haven't adjacent node, skip + if elem[0] == 0: + continue + # if argmax is reachable from elem + # remove argmax from elem's adjacent list and update his rank + if argmax in elem[1][1]: + index = elem[1][1].index(argmax) + del elem[1][1][index] + elem[0] += 1 + # re-order the queue + heapq.heapify(queue) + return chosen_vertices + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + graph = {0: [1, 3], 1: [0, 3], 2: [0, 3, 4], 3: [0, 1, 2], 4: [2, 3]} + print(f"Minimum vertex cover:\n{greedy_min_vertex_cover(graph)}") diff --git a/python/Graphs/kahns_algorithm_long.py b/python/Graphs/kahns_algorithm_long.py new file mode 100644 index 00000000..1f16b90c --- /dev/null +++ b/python/Graphs/kahns_algorithm_long.py @@ -0,0 +1,30 @@ +# Finding longest distance in Directed Acyclic Graph using KahnsAlgorithm +def longest_distance(graph): + indegree = [0] * len(graph) + queue = [] + long_dist = [1] * len(graph) + + for values in graph.values(): + for i in values: + indegree[i] += 1 + + for i in range(len(indegree)): + if indegree[i] == 0: + queue.append(i) + + while queue: + vertex = queue.pop(0) + for x in graph[vertex]: + indegree[x] -= 1 + + long_dist[x] = max(long_dist[x], long_dist[vertex] + 1) + + if indegree[x] == 0: + queue.append(x) + + print(max(long_dist)) + + +# Adjacency list of Graph +graph = {0: [2, 3, 4], 1: [2, 7], 2: [5], 3: [5, 7], 4: [7], 5: [6], 6: [7], 7: []} +longest_distance(graph) diff --git a/python/Graphs/kahns_algorithm_topo.py b/python/Graphs/kahns_algorithm_topo.py new file mode 100644 index 00000000..c956cf9f --- /dev/null +++ b/python/Graphs/kahns_algorithm_topo.py @@ -0,0 +1,61 @@ +def topological_sort(graph: dict[int, list[int]]) -> list[int] | None: + """ + Perform topological sorting of a Directed Acyclic Graph (DAG) + using Kahn's Algorithm via Breadth-First Search (BFS). + + Topological sorting is a linear ordering of vertices in a graph such that for + every directed edge u → v, vertex u comes before vertex v in the ordering. + + Parameters: + graph: Adjacency list representing the directed graph where keys are + vertices, and values are lists of adjacent vertices. + + Returns: + The topologically sorted order of vertices if the graph is a DAG. + Returns None if the graph contains a cycle. + + Example: + >>> graph = {0: [1, 2], 1: [3], 2: [3], 3: [4, 5], 4: [], 5: []} + >>> topological_sort(graph) + [0, 1, 2, 3, 4, 5] + + >>> graph_with_cycle = {0: [1], 1: [2], 2: [0]} + >>> topological_sort(graph_with_cycle) + """ + + indegree = [0] * len(graph) + queue = [] + topo_order = [] + processed_vertices_count = 0 + + # Calculate the indegree of each vertex + for values in graph.values(): + for i in values: + indegree[i] += 1 + + # Add all vertices with 0 indegree to the queue + for i in range(len(indegree)): + if indegree[i] == 0: + queue.append(i) + + # Perform BFS + while queue: + vertex = queue.pop(0) + processed_vertices_count += 1 + topo_order.append(vertex) + + # Traverse neighbors + for neighbor in graph[vertex]: + indegree[neighbor] -= 1 + if indegree[neighbor] == 0: + queue.append(neighbor) + + if processed_vertices_count != len(graph): + return None # no topological ordering exists due to cycle + return topo_order # valid topological ordering + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/karger.py b/python/Graphs/karger.py new file mode 100644 index 00000000..3ef65c0d --- /dev/null +++ b/python/Graphs/karger.py @@ -0,0 +1,85 @@ +""" +An implementation of Karger's Algorithm for partitioning a graph. +""" + +from __future__ import annotations + +import random + +# Adjacency list representation of this graph: +# https://en.wikipedia.org/wiki/File:Single_run_of_Karger%E2%80%99s_Mincut_algorithm.svg +TEST_GRAPH = { + "1": ["2", "3", "4", "5"], + "2": ["1", "3", "4", "5"], + "3": ["1", "2", "4", "5", "10"], + "4": ["1", "2", "3", "5", "6"], + "5": ["1", "2", "3", "4", "7"], + "6": ["7", "8", "9", "10", "4"], + "7": ["6", "8", "9", "10", "5"], + "8": ["6", "7", "9", "10"], + "9": ["6", "7", "8", "10"], + "10": ["6", "7", "8", "9", "3"], +} + + +def partition_graph(graph: dict[str, list[str]]) -> set[tuple[str, str]]: + """ + Partitions a graph using Karger's Algorithm. Implemented from + pseudocode found here: + https://en.wikipedia.org/wiki/Karger%27s_algorithm. + This function involves random choices, meaning it will not give + consistent outputs. + + Args: + graph: A dictionary containing adacency lists for the graph. + Nodes must be strings. + + Returns: + The cutset of the cut found by Karger's Algorithm. + + >>> graph = {'0':['1'], '1':['0']} + >>> partition_graph(graph) + {('0', '1')} + """ + # Dict that maps contracted nodes to a list of all the nodes it "contains." + contracted_nodes = {node: {node} for node in graph} + + graph_copy = {node: graph[node][:] for node in graph} + + while len(graph_copy) > 2: + # Choose a random edge. + u = random.choice(list(graph_copy.keys())) + v = random.choice(graph_copy[u]) + + # Contract edge (u, v) to new node uv + uv = u + v + uv_neighbors = list(set(graph_copy[u] + graph_copy[v])) + uv_neighbors.remove(u) + uv_neighbors.remove(v) + graph_copy[uv] = uv_neighbors + for neighbor in uv_neighbors: + graph_copy[neighbor].append(uv) + + contracted_nodes[uv] = set(contracted_nodes[u].union(contracted_nodes[v])) + + # Remove nodes u and v. + del graph_copy[u] + del graph_copy[v] + for neighbor in uv_neighbors: + if u in graph_copy[neighbor]: + graph_copy[neighbor].remove(u) + if v in graph_copy[neighbor]: + graph_copy[neighbor].remove(v) + + # Find cutset. + groups = [contracted_nodes[node] for node in graph_copy] + return { + (node, neighbor) + for node in groups[0] + for neighbor in graph[node] + if neighbor in groups[1] + } + + +if __name__ == "__main__": + print(partition_graph(TEST_GRAPH)) diff --git a/python/Graphs/lanczos_eigenvectors.py b/python/Graphs/lanczos_eigenvectors.py new file mode 100644 index 00000000..581a81a1 --- /dev/null +++ b/python/Graphs/lanczos_eigenvectors.py @@ -0,0 +1,206 @@ +""" +Lanczos Method for Finding Eigenvalues and Eigenvectors of a Graph. + +This module demonstrates the Lanczos method to approximate the largest eigenvalues +and corresponding eigenvectors of a symmetric matrix represented as a graph's +adjacency list. The method efficiently handles large, sparse matrices by converting +the graph to a tridiagonal matrix, whose eigenvalues and eigenvectors are then +computed. + +Key Functions: +- `find_lanczos_eigenvectors`: Computes the k largest eigenvalues and vectors. +- `lanczos_iteration`: Constructs the tridiagonal matrix and orthonormal basis vectors. +- `multiply_matrix_vector`: Multiplies an adjacency list graph with a vector. + +Complexity: +- Time: O(k * n), where k is the number of eigenvalues and n is the matrix size. +- Space: O(n), due to sparse representation and tridiagonal matrix structure. + +Further Reading: +- Lanczos Algorithm: https://en.wikipedia.org/wiki/Lanczos_algorithm +- Eigenvector Centrality: https://en.wikipedia.org/wiki/Eigenvector_centrality + +Example Usage: +Given a graph represented by an adjacency list, the `find_lanczos_eigenvectors` +function returns the largest eigenvalues and eigenvectors. This can be used to +analyze graph centrality. +""" + +import numpy as np + + +def validate_adjacency_list(graph: list[list[int | None]]) -> None: + """Validates the adjacency list format for the graph. + + Args: + graph: A list of lists where each sublist contains the neighbors of a node. + + Raises: + ValueError: If the graph is not a list of lists, or if any node has + invalid neighbors (e.g., out-of-range or non-integer values). + + >>> validate_adjacency_list([[1, 2], [0], [0, 1]]) + >>> validate_adjacency_list([[]]) # No neighbors, valid case + >>> validate_adjacency_list([[1], [2], [-1]]) # Invalid neighbor + Traceback (most recent call last): + ... + ValueError: Invalid neighbor -1 in node 2 adjacency list. + """ + if not isinstance(graph, list): + raise ValueError("Graph should be a list of lists.") + + for node_index, neighbors in enumerate(graph): + if not isinstance(neighbors, list): + no_neighbors_message: str = ( + f"Node {node_index} should have a list of neighbors." + ) + raise ValueError(no_neighbors_message) + for neighbor_index in neighbors: + if ( + not isinstance(neighbor_index, int) + or neighbor_index < 0 + or neighbor_index >= len(graph) + ): + invalid_neighbor_message: str = ( + f"Invalid neighbor {neighbor_index} in node {node_index} " + f"adjacency list." + ) + raise ValueError(invalid_neighbor_message) + + +def lanczos_iteration( + graph: list[list[int | None]], num_eigenvectors: int +) -> tuple[np.ndarray, np.ndarray]: + """Constructs the tridiagonal matrix and orthonormal basis vectors using the + Lanczos method. + + Args: + graph: The graph represented as a list of adjacency lists. + num_eigenvectors: The number of largest eigenvalues and eigenvectors + to approximate. + + Returns: + A tuple containing: + - tridiagonal_matrix: A (num_eigenvectors x num_eigenvectors) symmetric + matrix. + - orthonormal_basis: A (num_nodes x num_eigenvectors) matrix of orthonormal + basis vectors. + + Raises: + ValueError: If num_eigenvectors is less than 1 or greater than the number of + nodes. + + >>> graph = [[1, 2], [0, 2], [0, 1]] + >>> T, Q = lanczos_iteration(graph, 2) + >>> T.shape == (2, 2) and Q.shape == (3, 2) + True + """ + num_nodes: int = len(graph) + if not (1 <= num_eigenvectors <= num_nodes): + raise ValueError( + "Number of eigenvectors must be between 1 and the number of " + "nodes in the graph." + ) + + orthonormal_basis: np.ndarray = np.zeros((num_nodes, num_eigenvectors)) + tridiagonal_matrix: np.ndarray = np.zeros((num_eigenvectors, num_eigenvectors)) + + rng = np.random.default_rng() + initial_vector: np.ndarray = rng.random(num_nodes) + initial_vector /= np.sqrt(np.dot(initial_vector, initial_vector)) + orthonormal_basis[:, 0] = initial_vector + + prev_beta: float = 0.0 + for iter_index in range(num_eigenvectors): + result_vector: np.ndarray = multiply_matrix_vector( + graph, orthonormal_basis[:, iter_index] + ) + if iter_index > 0: + result_vector -= prev_beta * orthonormal_basis[:, iter_index - 1] + alpha_value: float = np.dot(orthonormal_basis[:, iter_index], result_vector) + result_vector -= alpha_value * orthonormal_basis[:, iter_index] + + prev_beta = np.sqrt(np.dot(result_vector, result_vector)) + if iter_index < num_eigenvectors - 1 and prev_beta > 1e-10: + orthonormal_basis[:, iter_index + 1] = result_vector / prev_beta + tridiagonal_matrix[iter_index, iter_index] = alpha_value + if iter_index < num_eigenvectors - 1: + tridiagonal_matrix[iter_index, iter_index + 1] = prev_beta + tridiagonal_matrix[iter_index + 1, iter_index] = prev_beta + return tridiagonal_matrix, orthonormal_basis + + +def multiply_matrix_vector( + graph: list[list[int | None]], vector: np.ndarray +) -> np.ndarray: + """Performs multiplication of a graph's adjacency list representation with a vector. + + Args: + graph: The adjacency list of the graph. + vector: A 1D numpy array representing the vector to multiply. + + Returns: + A numpy array representing the product of the adjacency list and the vector. + + Raises: + ValueError: If the vector's length does not match the number of nodes in the + graph. + + >>> multiply_matrix_vector([[1, 2], [0, 2], [0, 1]], np.array([1, 1, 1])) + array([2., 2., 2.]) + >>> multiply_matrix_vector([[1, 2], [0, 2], [0, 1]], np.array([0, 1, 0])) + array([1., 0., 1.]) + """ + num_nodes: int = len(graph) + if vector.shape[0] != num_nodes: + raise ValueError("Vector length must match the number of nodes in the graph.") + + result: np.ndarray = np.zeros(num_nodes) + for node_index, neighbors in enumerate(graph): + for neighbor_index in neighbors: + result[node_index] += vector[neighbor_index] + return result + + +def find_lanczos_eigenvectors( + graph: list[list[int | None]], num_eigenvectors: int +) -> tuple[np.ndarray, np.ndarray]: + """Computes the largest eigenvalues and their corresponding eigenvectors using the + Lanczos method. + + Args: + graph: The graph as a list of adjacency lists. + num_eigenvectors: Number of largest eigenvalues and eigenvectors to compute. + + Returns: + A tuple containing: + - eigenvalues: 1D array of the largest eigenvalues in descending order. + - eigenvectors: 2D array where each column is an eigenvector corresponding + to an eigenvalue. + + Raises: + ValueError: If the graph format is invalid or num_eigenvectors is out of bounds. + + >>> eigenvalues, eigenvectors = find_lanczos_eigenvectors( + ... [[1, 2], [0, 2], [0, 1]], 2 + ... ) + >>> len(eigenvalues) == 2 and eigenvectors.shape[1] == 2 + True + """ + validate_adjacency_list(graph) + tridiagonal_matrix, orthonormal_basis = lanczos_iteration(graph, num_eigenvectors) + eigenvalues, eigenvectors = np.linalg.eigh(tridiagonal_matrix) + return eigenvalues[::-1], np.dot(orthonormal_basis, eigenvectors[:, ::-1]) + + +def main() -> None: + """ + Main driver function for testing the implementation with doctests. + """ + import doctest + + doctest.testmod() + + +if __name__ == "__main__": + main() diff --git a/python/Graphs/markov_chain.py b/python/Graphs/markov_chain.py new file mode 100644 index 00000000..0b665982 --- /dev/null +++ b/python/Graphs/markov_chain.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections import Counter +from random import random + + +class MarkovChainGraphUndirectedUnweighted: + """ + Undirected Unweighted Graph for running Markov Chain Algorithm + """ + + def __init__(self): + self.connections = {} + + def add_node(self, node: str) -> None: + self.connections[node] = {} + + def add_transition_probability( + self, node1: str, node2: str, probability: float + ) -> None: + if node1 not in self.connections: + self.add_node(node1) + if node2 not in self.connections: + self.add_node(node2) + self.connections[node1][node2] = probability + + def get_nodes(self) -> list[str]: + return list(self.connections) + + def transition(self, node: str) -> str: + current_probability = 0 + random_value = random() + + for dest in self.connections[node]: + current_probability += self.connections[node][dest] + if current_probability > random_value: + return dest + return "" + + +def get_transitions( + start: str, transitions: list[tuple[str, str, float]], steps: int +) -> dict[str, int]: + """ + Running Markov Chain algorithm and calculating the number of times each node is + visited + + >>> transitions = [ + ... ('a', 'a', 0.9), + ... ('a', 'b', 0.075), + ... ('a', 'c', 0.025), + ... ('b', 'a', 0.15), + ... ('b', 'b', 0.8), + ... ('b', 'c', 0.05), + ... ('c', 'a', 0.25), + ... ('c', 'b', 0.25), + ... ('c', 'c', 0.5) + ... ] + + >>> result = get_transitions('a', transitions, 5000) + + >>> result['a'] > result['b'] > result['c'] + True + """ + + graph = MarkovChainGraphUndirectedUnweighted() + + for node1, node2, probability in transitions: + graph.add_transition_probability(node1, node2, probability) + + visited = Counter(graph.get_nodes()) + node = start + + for _ in range(steps): + node = graph.transition(node) + visited[node] += 1 + + return visited + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/matching_min_vertex_cover.py b/python/Graphs/matching_min_vertex_cover.py new file mode 100644 index 00000000..5ac944ec --- /dev/null +++ b/python/Graphs/matching_min_vertex_cover.py @@ -0,0 +1,62 @@ +""" +* Author: Manuel Di Lullo (https://github.com/manueldilullo) +* Description: Approximization algorithm for minimum vertex cover problem. + Matching Approach. Uses graphs represented with an adjacency list + +URL: https://mathworld.wolfram.com/MinimumVertexCover.html +URL: https://www.princeton.edu/~aaa/Public/Teaching/ORF523/ORF523_Lec6.pdf +""" + + +def matching_min_vertex_cover(graph: dict) -> set: + """ + APX Algorithm for min Vertex Cover using Matching Approach + @input: graph (graph stored in an adjacency list where each vertex + is represented as an integer) + @example: + >>> graph = {0: [1, 3], 1: [0, 3], 2: [0, 3, 4], 3: [0, 1, 2], 4: [2, 3]} + >>> matching_min_vertex_cover(graph) + {0, 1, 2, 4} + """ + # chosen_vertices = set of chosen vertices + chosen_vertices = set() + # edges = list of graph's edges + edges = get_edges(graph) + + # While there are still elements in edges list, take an arbitrary edge + # (from_node, to_node) and add his extremity to chosen_vertices and then + # remove all arcs adjacent to the from_node and to_node + while edges: + from_node, to_node = edges.pop() + chosen_vertices.add(from_node) + chosen_vertices.add(to_node) + for edge in edges.copy(): + if from_node in edge or to_node in edge: + edges.discard(edge) + return chosen_vertices + + +def get_edges(graph: dict) -> set: + """ + Return a set of couples that represents all of the edges. + @input: graph (graph stored in an adjacency list where each vertex is + represented as an integer) + @example: + >>> graph = {0: [1, 3], 1: [0, 3], 2: [0, 3], 3: [0, 1, 2]} + >>> get_edges(graph) + {(0, 1), (3, 1), (0, 3), (2, 0), (3, 0), (2, 3), (1, 0), (3, 2), (1, 3)} + """ + edges = set() + for from_node, to_nodes in graph.items(): + for to_node in to_nodes: + edges.add((from_node, to_node)) + return edges + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + # graph = {0: [1, 3], 1: [0, 3], 2: [0, 3, 4], 3: [0, 1, 2], 4: [2, 3]} + # print(f"Matching vertex cover:\n{matching_min_vertex_cover(graph)}") diff --git a/python/Graphs/minimum_path_sum.py b/python/Graphs/minimum_path_sum.py new file mode 100644 index 00000000..df1e545d --- /dev/null +++ b/python/Graphs/minimum_path_sum.py @@ -0,0 +1,63 @@ +def min_path_sum(grid: list) -> int: + """ + Find the path from top left to bottom right of array of numbers + with the lowest possible sum and return the sum along this path. + >>> min_path_sum([ + ... [1, 3, 1], + ... [1, 5, 1], + ... [4, 2, 1], + ... ]) + 7 + + >>> min_path_sum([ + ... [1, 0, 5, 6, 7], + ... [8, 9, 0, 4, 2], + ... [4, 4, 4, 5, 1], + ... [9, 6, 3, 1, 0], + ... [8, 4, 3, 2, 7], + ... ]) + 20 + + >>> min_path_sum(None) + Traceback (most recent call last): + ... + TypeError: The grid does not contain the appropriate information + + >>> min_path_sum([[]]) + Traceback (most recent call last): + ... + TypeError: The grid does not contain the appropriate information + """ + + if not grid or not grid[0]: + raise TypeError("The grid does not contain the appropriate information") + + for cell_n in range(1, len(grid[0])): + grid[0][cell_n] += grid[0][cell_n - 1] + row_above = grid[0] + + for row_n in range(1, len(grid)): + current_row = grid[row_n] + grid[row_n] = fill_row(current_row, row_above) + row_above = grid[row_n] + + return grid[-1][-1] + + +def fill_row(current_row: list, row_above: list) -> list: + """ + >>> fill_row([2, 2, 2], [1, 2, 3]) + [3, 4, 5] + """ + + current_row[0] += row_above[0] + for cell_n in range(1, len(current_row)): + current_row[cell_n] += min(current_row[cell_n - 1], row_above[cell_n]) + + return current_row + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/minimum_spanning_tree_boruvka.py b/python/Graphs/minimum_spanning_tree_boruvka.py new file mode 100644 index 00000000..f234d65a --- /dev/null +++ b/python/Graphs/minimum_spanning_tree_boruvka.py @@ -0,0 +1,196 @@ +class Graph: + """ + Data structure to store graphs (based on adjacency lists) + """ + + def __init__(self): + self.num_vertices = 0 + self.num_edges = 0 + self.adjacency = {} + + def add_vertex(self, vertex): + """ + Adds a vertex to the graph + + """ + if vertex not in self.adjacency: + self.adjacency[vertex] = {} + self.num_vertices += 1 + + def add_edge(self, head, tail, weight): + """ + Adds an edge to the graph + + """ + + self.add_vertex(head) + self.add_vertex(tail) + + if head == tail: + return + + self.adjacency[head][tail] = weight + self.adjacency[tail][head] = weight + + def distinct_weight(self): + """ + For Boruvks's algorithm the weights should be distinct + Converts the weights to be distinct + + """ + edges = self.get_edges() + for edge in edges: + head, tail, weight = edge + edges.remove((tail, head, weight)) + for i in range(len(edges)): + edges[i] = list(edges[i]) + + edges.sort(key=lambda e: e[2]) + for i in range(len(edges) - 1): + if edges[i][2] >= edges[i + 1][2]: + edges[i + 1][2] = edges[i][2] + 1 + for edge in edges: + head, tail, weight = edge + self.adjacency[head][tail] = weight + self.adjacency[tail][head] = weight + + def __str__(self): + """ + Returns string representation of the graph + """ + string = "" + for tail in self.adjacency: + for head in self.adjacency[tail]: + weight = self.adjacency[head][tail] + string += f"{head} -> {tail} == {weight}\n" + return string.rstrip("\n") + + def get_edges(self): + """ + Returna all edges in the graph + """ + output = [] + for tail in self.adjacency: + for head in self.adjacency[tail]: + output.append((tail, head, self.adjacency[head][tail])) + return output + + def get_vertices(self): + """ + Returns all vertices in the graph + """ + return self.adjacency.keys() + + @staticmethod + def build(vertices=None, edges=None): + """ + Builds a graph from the given set of vertices and edges + + """ + g = Graph() + if vertices is None: + vertices = [] + if edges is None: + edge = [] + for vertex in vertices: + g.add_vertex(vertex) + for edge in edges: + g.add_edge(*edge) + return g + + class UnionFind: + """ + Disjoint set Union and Find for Boruvka's algorithm + """ + + def __init__(self): + self.parent = {} + self.rank = {} + + def __len__(self): + return len(self.parent) + + def make_set(self, item): + if item in self.parent: + return self.find(item) + + self.parent[item] = item + self.rank[item] = 0 + return item + + def find(self, item): + if item not in self.parent: + return self.make_set(item) + if item != self.parent[item]: + self.parent[item] = self.find(self.parent[item]) + return self.parent[item] + + def union(self, item1, item2): + root1 = self.find(item1) + root2 = self.find(item2) + + if root1 == root2: + return root1 + + if self.rank[root1] > self.rank[root2]: + self.parent[root2] = root1 + return root1 + + if self.rank[root1] < self.rank[root2]: + self.parent[root1] = root2 + return root2 + + if self.rank[root1] == self.rank[root2]: + self.rank[root1] += 1 + self.parent[root2] = root1 + return root1 + return None + + @staticmethod + def boruvka_mst(graph): + """ + Implementation of Boruvka's algorithm + >>> g = Graph() + >>> g = Graph.build([0, 1, 2, 3], [[0, 1, 1], [0, 2, 1],[2, 3, 1]]) + >>> g.distinct_weight() + >>> bg = Graph.boruvka_mst(g) + >>> print(bg) + 1 -> 0 == 1 + 2 -> 0 == 2 + 0 -> 1 == 1 + 0 -> 2 == 2 + 3 -> 2 == 3 + 2 -> 3 == 3 + """ + num_components = graph.num_vertices + + union_find = Graph.UnionFind() + mst_edges = [] + while num_components > 1: + cheap_edge = {} + for vertex in graph.get_vertices(): + cheap_edge[vertex] = -1 + + edges = graph.get_edges() + for edge in edges: + head, tail, weight = edge + edges.remove((tail, head, weight)) + for edge in edges: + head, tail, weight = edge + set1 = union_find.find(head) + set2 = union_find.find(tail) + if set1 != set2: + if cheap_edge[set1] == -1 or cheap_edge[set1][2] > weight: + cheap_edge[set1] = [head, tail, weight] + + if cheap_edge[set2] == -1 or cheap_edge[set2][2] > weight: + cheap_edge[set2] = [head, tail, weight] + for head_tail_weight in cheap_edge.values(): + if head_tail_weight != -1: + head, tail, weight = head_tail_weight + if union_find.find(head) != union_find.find(tail): + union_find.union(head, tail) + mst_edges.append(head_tail_weight) + num_components = num_components - 1 + mst = Graph.build(edges=mst_edges) + return mst diff --git a/python/Graphs/minimum_spanning_tree_kruskal.py b/python/Graphs/minimum_spanning_tree_kruskal.py new file mode 100644 index 00000000..85d93701 --- /dev/null +++ b/python/Graphs/minimum_spanning_tree_kruskal.py @@ -0,0 +1,46 @@ +def kruskal( + num_nodes: int, edges: list[tuple[int, int, int]] +) -> list[tuple[int, int, int]]: + """ + >>> kruskal(4, [(0, 1, 3), (1, 2, 5), (2, 3, 1)]) + [(2, 3, 1), (0, 1, 3), (1, 2, 5)] + + >>> kruskal(4, [(0, 1, 3), (1, 2, 5), (2, 3, 1), (0, 2, 1), (0, 3, 2)]) + [(2, 3, 1), (0, 2, 1), (0, 1, 3)] + + >>> kruskal(4, [(0, 1, 3), (1, 2, 5), (2, 3, 1), (0, 2, 1), (0, 3, 2), + ... (2, 1, 1)]) + [(2, 3, 1), (0, 2, 1), (2, 1, 1)] + """ + edges = sorted(edges, key=lambda edge: edge[2]) + + parent = list(range(num_nodes)) + + def find_parent(i): + if i != parent[i]: + parent[i] = find_parent(parent[i]) + return parent[i] + + minimum_spanning_tree_cost = 0 + minimum_spanning_tree = [] + + for edge in edges: + parent_a = find_parent(edge[0]) + parent_b = find_parent(edge[1]) + if parent_a != parent_b: + minimum_spanning_tree_cost += edge[2] + minimum_spanning_tree.append(edge) + parent[parent_a] = parent_b + + return minimum_spanning_tree + + +if __name__ == "__main__": # pragma: no cover + num_nodes, num_edges = list(map(int, input().strip().split())) + edges = [] + + for _ in range(num_edges): + node1, node2, cost = (int(x) for x in input().strip().split()) + edges.append((node1, node2, cost)) + + kruskal(num_nodes, edges) diff --git a/python/Graphs/minimum_spanning_tree_kruskal2.py b/python/Graphs/minimum_spanning_tree_kruskal2.py new file mode 100644 index 00000000..1f6d7255 --- /dev/null +++ b/python/Graphs/minimum_spanning_tree_kruskal2.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from typing import TypeVar + +T = TypeVar("T") + + +class DisjointSetTreeNode[T]: + # Disjoint Set Node to store the parent and rank + def __init__(self, data: T) -> None: + self.data = data + self.parent = self + self.rank = 0 + + +class DisjointSetTree[T]: + # Disjoint Set DataStructure + def __init__(self) -> None: + # map from node name to the node object + self.map: dict[T, DisjointSetTreeNode[T]] = {} + + def make_set(self, data: T) -> None: + # create a new set with x as its member + self.map[data] = DisjointSetTreeNode(data) + + def find_set(self, data: T) -> DisjointSetTreeNode[T]: + # find the set x belongs to (with path-compression) + elem_ref = self.map[data] + if elem_ref != elem_ref.parent: + elem_ref.parent = self.find_set(elem_ref.parent.data) + return elem_ref.parent + + def link( + self, node1: DisjointSetTreeNode[T], node2: DisjointSetTreeNode[T] + ) -> None: + # helper function for union operation + if node1.rank > node2.rank: + node2.parent = node1 + else: + node1.parent = node2 + if node1.rank == node2.rank: + node2.rank += 1 + + def union(self, data1: T, data2: T) -> None: + # merge 2 disjoint sets + self.link(self.find_set(data1), self.find_set(data2)) + + +class GraphUndirectedWeighted[T]: + def __init__(self) -> None: + # connections: map from the node to the neighbouring nodes (with weights) + self.connections: dict[T, dict[T, int]] = {} + + def add_node(self, node: T) -> None: + # add a node ONLY if its not present in the graph + if node not in self.connections: + self.connections[node] = {} + + def add_edge(self, node1: T, node2: T, weight: int) -> None: + # add an edge with the given weight + self.add_node(node1) + self.add_node(node2) + self.connections[node1][node2] = weight + self.connections[node2][node1] = weight + + def kruskal(self) -> GraphUndirectedWeighted[T]: + # Kruskal's Algorithm to generate a Minimum Spanning Tree (MST) of a graph + """ + Details: https://en.wikipedia.org/wiki/Kruskal%27s_algorithm + + Example: + >>> g1 = GraphUndirectedWeighted[int]() + >>> g1.add_edge(1, 2, 1) + >>> g1.add_edge(2, 3, 2) + >>> g1.add_edge(3, 4, 1) + >>> g1.add_edge(3, 5, 100) # Removed in MST + >>> g1.add_edge(4, 5, 5) + >>> assert 5 in g1.connections[3] + >>> mst = g1.kruskal() + >>> assert 5 not in mst.connections[3] + + >>> g2 = GraphUndirectedWeighted[str]() + >>> g2.add_edge('A', 'B', 1) + >>> g2.add_edge('B', 'C', 2) + >>> g2.add_edge('C', 'D', 1) + >>> g2.add_edge('C', 'E', 100) # Removed in MST + >>> g2.add_edge('D', 'E', 5) + >>> assert 'E' in g2.connections["C"] + >>> mst = g2.kruskal() + >>> assert 'E' not in mst.connections['C'] + """ + + # getting the edges in ascending order of weights + edges = [] + seen = set() + for start in self.connections: + for end in self.connections[start]: + if (start, end) not in seen: + seen.add((end, start)) + edges.append((start, end, self.connections[start][end])) + edges.sort(key=lambda x: x[2]) + + # creating the disjoint set + disjoint_set = DisjointSetTree[T]() + for node in self.connections: + disjoint_set.make_set(node) + + # MST generation + num_edges = 0 + index = 0 + graph = GraphUndirectedWeighted[T]() + while num_edges < len(self.connections) - 1: + u, v, w = edges[index] + index += 1 + parent_u = disjoint_set.find_set(u) + parent_v = disjoint_set.find_set(v) + if parent_u != parent_v: + num_edges += 1 + graph.add_edge(u, v, w) + disjoint_set.union(u, v) + return graph diff --git a/python/Graphs/minimum_spanning_tree_prims.py b/python/Graphs/minimum_spanning_tree_prims.py new file mode 100644 index 00000000..d0b45d7e --- /dev/null +++ b/python/Graphs/minimum_spanning_tree_prims.py @@ -0,0 +1,135 @@ +import sys +from collections import defaultdict + + +class Heap: + def __init__(self): + self.node_position = [] + + def get_position(self, vertex): + return self.node_position[vertex] + + def set_position(self, vertex, pos): + self.node_position[vertex] = pos + + def top_to_bottom(self, heap, start, size, positions): + if start > size // 2 - 1: + return + else: + if 2 * start + 2 >= size: # noqa: SIM114 + smallest_child = 2 * start + 1 + elif heap[2 * start + 1] < heap[2 * start + 2]: + smallest_child = 2 * start + 1 + else: + smallest_child = 2 * start + 2 + if heap[smallest_child] < heap[start]: + temp, temp1 = heap[smallest_child], positions[smallest_child] + heap[smallest_child], positions[smallest_child] = ( + heap[start], + positions[start], + ) + heap[start], positions[start] = temp, temp1 + + temp = self.get_position(positions[smallest_child]) + self.set_position( + positions[smallest_child], self.get_position(positions[start]) + ) + self.set_position(positions[start], temp) + + self.top_to_bottom(heap, smallest_child, size, positions) + + # Update function if value of any node in min-heap decreases + def bottom_to_top(self, val, index, heap, position): + temp = position[index] + + while index != 0: + parent = int((index - 2) / 2) if index % 2 == 0 else int((index - 1) / 2) + + if val < heap[parent]: + heap[index] = heap[parent] + position[index] = position[parent] + self.set_position(position[parent], index) + else: + heap[index] = val + position[index] = temp + self.set_position(temp, index) + break + index = parent + else: + heap[0] = val + position[0] = temp + self.set_position(temp, 0) + + def heapify(self, heap, positions): + start = len(heap) // 2 - 1 + for i in range(start, -1, -1): + self.top_to_bottom(heap, i, len(heap), positions) + + def delete_minimum(self, heap, positions): + temp = positions[0] + heap[0] = sys.maxsize + self.top_to_bottom(heap, 0, len(heap), positions) + return temp + + +def prisms_algorithm(adjacency_list): + """ + >>> adjacency_list = {0: [[1, 1], [3, 3]], + ... 1: [[0, 1], [2, 6], [3, 5], [4, 1]], + ... 2: [[1, 6], [4, 5], [5, 2]], + ... 3: [[0, 3], [1, 5], [4, 1]], + ... 4: [[1, 1], [2, 5], [3, 1], [5, 4]], + ... 5: [[2, 2], [4, 4]]} + >>> prisms_algorithm(adjacency_list) + [(0, 1), (1, 4), (4, 3), (4, 5), (5, 2)] + """ + + heap = Heap() + + visited = [0] * len(adjacency_list) + nbr_tv = [-1] * len(adjacency_list) # Neighboring Tree Vertex of selected vertex + # Minimum Distance of explored vertex with neighboring vertex of partial tree + # formed in graph + distance_tv = [] # Heap of Distance of vertices from their neighboring vertex + positions = [] + + for vertex in range(len(adjacency_list)): + distance_tv.append(sys.maxsize) + positions.append(vertex) + heap.node_position.append(vertex) + + tree_edges = [] + visited[0] = 1 + distance_tv[0] = sys.maxsize + for neighbor, distance in adjacency_list[0]: + nbr_tv[neighbor] = 0 + distance_tv[neighbor] = distance + heap.heapify(distance_tv, positions) + + for _ in range(1, len(adjacency_list)): + vertex = heap.delete_minimum(distance_tv, positions) + if visited[vertex] == 0: + tree_edges.append((nbr_tv[vertex], vertex)) + visited[vertex] = 1 + for neighbor, distance in adjacency_list[vertex]: + if ( + visited[neighbor] == 0 + and distance < distance_tv[heap.get_position(neighbor)] + ): + distance_tv[heap.get_position(neighbor)] = distance + heap.bottom_to_top( + distance, heap.get_position(neighbor), distance_tv, positions + ) + nbr_tv[neighbor] = vertex + return tree_edges + + +if __name__ == "__main__": # pragma: no cover + # < --------- Prims Algorithm --------- > + edges_number = int(input("Enter number of edges: ").strip()) + adjacency_list = defaultdict(list) + for _ in range(edges_number): + edge = [int(x) for x in input().strip().split()] + adjacency_list[edge[0]].append([edge[1], edge[2]]) + adjacency_list[edge[1]].append([edge[0], edge[2]]) + print(prisms_algorithm(adjacency_list)) diff --git a/python/Graphs/minimum_spanning_tree_prims2.py b/python/Graphs/minimum_spanning_tree_prims2.py new file mode 100644 index 00000000..d2211128 --- /dev/null +++ b/python/Graphs/minimum_spanning_tree_prims2.py @@ -0,0 +1,269 @@ +""" +Prim's (also known as Jarník's) algorithm is a greedy algorithm that finds a minimum +spanning tree for a weighted undirected graph. This means it finds a subset of the +edges that forms a tree that includes every vertex, where the total weight of all the +edges in the tree is minimized. The algorithm operates by building this tree one vertex +at a time, from an arbitrary starting vertex, at each step adding the cheapest possible +connection from the tree to another vertex. +""" + +from __future__ import annotations + +from sys import maxsize +from typing import TypeVar + +T = TypeVar("T") + + +def get_parent_position(position: int) -> int: + """ + heap helper function get the position of the parent of the current node + + >>> get_parent_position(1) + 0 + >>> get_parent_position(2) + 0 + """ + return (position - 1) // 2 + + +def get_child_left_position(position: int) -> int: + """ + heap helper function get the position of the left child of the current node + + >>> get_child_left_position(0) + 1 + """ + return (2 * position) + 1 + + +def get_child_right_position(position: int) -> int: + """ + heap helper function get the position of the right child of the current node + + >>> get_child_right_position(0) + 2 + """ + return (2 * position) + 2 + + +class MinPriorityQueue[T]: + """ + Minimum Priority Queue Class + + Functions: + is_empty: function to check if the priority queue is empty + push: function to add an element with given priority to the queue + extract_min: function to remove and return the element with lowest weight (highest + priority) + update_key: function to update the weight of the given key + _bubble_up: helper function to place a node at the proper position (upward + movement) + _bubble_down: helper function to place a node at the proper position (downward + movement) + _swap_nodes: helper function to swap the nodes at the given positions + + >>> queue = MinPriorityQueue() + + >>> queue.push(1, 1000) + >>> queue.push(2, 100) + >>> queue.push(3, 4000) + >>> queue.push(4, 3000) + + >>> queue.extract_min() + 2 + + >>> queue.update_key(4, 50) + + >>> queue.extract_min() + 4 + >>> queue.extract_min() + 1 + >>> queue.extract_min() + 3 + """ + + def __init__(self) -> None: + self.heap: list[tuple[T, int]] = [] + self.position_map: dict[T, int] = {} + self.elements: int = 0 + + def __len__(self) -> int: + return self.elements + + def __repr__(self) -> str: + return str(self.heap) + + def is_empty(self) -> bool: + # Check if the priority queue is empty + return self.elements == 0 + + def push(self, elem: T, weight: int) -> None: + # Add an element with given priority to the queue + self.heap.append((elem, weight)) + self.position_map[elem] = self.elements + self.elements += 1 + self._bubble_up(elem) + + def extract_min(self) -> T: + # Remove and return the element with lowest weight (highest priority) + if self.elements > 1: + self._swap_nodes(0, self.elements - 1) + elem, _ = self.heap.pop() + del self.position_map[elem] + self.elements -= 1 + if self.elements > 0: + bubble_down_elem, _ = self.heap[0] + self._bubble_down(bubble_down_elem) + return elem + + def update_key(self, elem: T, weight: int) -> None: + # Update the weight of the given key + position = self.position_map[elem] + self.heap[position] = (elem, weight) + if position > 0: + parent_position = get_parent_position(position) + _, parent_weight = self.heap[parent_position] + if parent_weight > weight: + self._bubble_up(elem) + else: + self._bubble_down(elem) + else: + self._bubble_down(elem) + + def _bubble_up(self, elem: T) -> None: + # Place a node at the proper position (upward movement) [to be used internally + # only] + curr_pos = self.position_map[elem] + if curr_pos == 0: + return None + parent_position = get_parent_position(curr_pos) + _, weight = self.heap[curr_pos] + _, parent_weight = self.heap[parent_position] + if parent_weight > weight: + self._swap_nodes(parent_position, curr_pos) + return self._bubble_up(elem) + return None + + def _bubble_down(self, elem: T) -> None: + # Place a node at the proper position (downward movement) [to be used + # internally only] + curr_pos = self.position_map[elem] + _, weight = self.heap[curr_pos] + child_left_position = get_child_left_position(curr_pos) + child_right_position = get_child_right_position(curr_pos) + if child_left_position < self.elements and child_right_position < self.elements: + _, child_left_weight = self.heap[child_left_position] + _, child_right_weight = self.heap[child_right_position] + if child_right_weight < child_left_weight and child_right_weight < weight: + self._swap_nodes(child_right_position, curr_pos) + return self._bubble_down(elem) + if child_left_position < self.elements: + _, child_left_weight = self.heap[child_left_position] + if child_left_weight < weight: + self._swap_nodes(child_left_position, curr_pos) + return self._bubble_down(elem) + else: + return None + if child_right_position < self.elements: + _, child_right_weight = self.heap[child_right_position] + if child_right_weight < weight: + self._swap_nodes(child_right_position, curr_pos) + return self._bubble_down(elem) + return None + + def _swap_nodes(self, node1_pos: int, node2_pos: int) -> None: + # Swap the nodes at the given positions + node1_elem = self.heap[node1_pos][0] + node2_elem = self.heap[node2_pos][0] + self.heap[node1_pos], self.heap[node2_pos] = ( + self.heap[node2_pos], + self.heap[node1_pos], + ) + self.position_map[node1_elem] = node2_pos + self.position_map[node2_elem] = node1_pos + + +class GraphUndirectedWeighted[T]: + """ + Graph Undirected Weighted Class + + Functions: + add_node: function to add a node in the graph + add_edge: function to add an edge between 2 nodes in the graph + """ + + def __init__(self) -> None: + self.connections: dict[T, dict[T, int]] = {} + self.nodes: int = 0 + + def __repr__(self) -> str: + return str(self.connections) + + def __len__(self) -> int: + return self.nodes + + def add_node(self, node: T) -> None: + # Add a node in the graph if it is not in the graph + if node not in self.connections: + self.connections[node] = {} + self.nodes += 1 + + def add_edge(self, node1: T, node2: T, weight: int) -> None: + # Add an edge between 2 nodes in the graph + self.add_node(node1) + self.add_node(node2) + self.connections[node1][node2] = weight + self.connections[node2][node1] = weight + + +def prims_algo[T]( + graph: GraphUndirectedWeighted[T], +) -> tuple[dict[T, int], dict[T, T | None]]: + """ + >>> graph = GraphUndirectedWeighted() + + >>> graph.add_edge("a", "b", 3) + >>> graph.add_edge("b", "c", 10) + >>> graph.add_edge("c", "d", 5) + >>> graph.add_edge("a", "c", 15) + >>> graph.add_edge("b", "d", 100) + + >>> dist, parent = prims_algo(graph) + + >>> abs(dist["a"] - dist["b"]) + 3 + >>> abs(dist["d"] - dist["b"]) + 15 + >>> abs(dist["a"] - dist["c"]) + 13 + """ + # prim's algorithm for minimum spanning tree + dist: dict[T, int] = dict.fromkeys(graph.connections, maxsize) + parent: dict[T, T | None] = dict.fromkeys(graph.connections) + + priority_queue: MinPriorityQueue[T] = MinPriorityQueue() + for node, weight in dist.items(): + priority_queue.push(node, weight) + + if priority_queue.is_empty(): + return dist, parent + + # initialization + node = priority_queue.extract_min() + dist[node] = 0 + for neighbour in graph.connections[node]: + if dist[neighbour] > dist[node] + graph.connections[node][neighbour]: + dist[neighbour] = dist[node] + graph.connections[node][neighbour] + priority_queue.update_key(neighbour, dist[neighbour]) + parent[neighbour] = node + + # running prim's algorithm + while not priority_queue.is_empty(): + node = priority_queue.extract_min() + for neighbour in graph.connections[node]: + if dist[neighbour] > dist[node] + graph.connections[node][neighbour]: + dist[neighbour] = dist[node] + graph.connections[node][neighbour] + priority_queue.update_key(neighbour, dist[neighbour]) + parent[neighbour] = node + return dist, parent diff --git a/python/Graphs/multi_heuristic_astar.py b/python/Graphs/multi_heuristic_astar.py new file mode 100644 index 00000000..38b07e1c --- /dev/null +++ b/python/Graphs/multi_heuristic_astar.py @@ -0,0 +1,312 @@ +import heapq +import sys + +import numpy as np + +TPos = tuple[int, int] + + +class PriorityQueue: + def __init__(self): + self.elements = [] + self.set = set() + + def minkey(self): + if not self.empty(): + return self.elements[0][0] + else: + return float("inf") + + def empty(self): + return len(self.elements) == 0 + + def put(self, item, priority): + if item not in self.set: + heapq.heappush(self.elements, (priority, item)) + self.set.add(item) + else: + # update + # print("update", item) + temp = [] + (pri, x) = heapq.heappop(self.elements) + while x != item: + temp.append((pri, x)) + (pri, x) = heapq.heappop(self.elements) + temp.append((priority, item)) + for pro, xxx in temp: + heapq.heappush(self.elements, (pro, xxx)) + + def remove_element(self, item): + if item in self.set: + self.set.remove(item) + temp = [] + (pro, x) = heapq.heappop(self.elements) + while x != item: + temp.append((pro, x)) + (pro, x) = heapq.heappop(self.elements) + for prito, yyy in temp: + heapq.heappush(self.elements, (prito, yyy)) + + def top_show(self): + return self.elements[0][1] + + def get(self): + (priority, item) = heapq.heappop(self.elements) + self.set.remove(item) + return (priority, item) + + +def consistent_heuristic(p: TPos, goal: TPos): + # euclidean distance + a = np.array(p) + b = np.array(goal) + return np.linalg.norm(a - b) + + +def heuristic_2(p: TPos, goal: TPos): + # integer division by time variable + return consistent_heuristic(p, goal) // t + + +def heuristic_1(p: TPos, goal: TPos): + # manhattan distance + return abs(p[0] - goal[0]) + abs(p[1] - goal[1]) + + +def key(start: TPos, i: int, goal: TPos, g_function: dict[TPos, float]): + ans = g_function[start] + W1 * heuristics[i](start, goal) + return ans + + +def do_something(back_pointer, goal, start): + grid = np.char.chararray((n, n)) + for i in range(n): + for j in range(n): + grid[i][j] = "*" + + for i in range(n): + for j in range(n): + if (j, (n - 1) - i) in blocks: + grid[i][j] = "#" + + grid[0][(n - 1)] = "-" + x = back_pointer[goal] + while x != start: + (x_c, y_c) = x + # print(x) + grid[(n - 1) - y_c][x_c] = "-" + x = back_pointer[x] + grid[(n - 1)][0] = "-" + + for i in range(n): + for j in range(n): + if (i, j) == (0, n - 1): + print(grid[i][j], end=" ") + print("<-- End position", end=" ") + else: + print(grid[i][j], end=" ") + print() + print("^") + print("Start position") + print() + print("# is an obstacle") + print("- is the path taken by algorithm") + print("PATH TAKEN BY THE ALGORITHM IS:-") + x = back_pointer[goal] + while x != start: + print(x, end=" ") + x = back_pointer[x] + print(x) + sys.exit() + + +def valid(p: TPos): + if p[0] < 0 or p[0] > n - 1: + return False + return not (p[1] < 0 or p[1] > n - 1) + + +def expand_state( + s, + j, + visited, + g_function, + close_list_anchor, + close_list_inad, + open_list, + back_pointer, +): + for itera in range(n_heuristic): + open_list[itera].remove_element(s) + # print("s", s) + # print("j", j) + (x, y) = s + left = (x - 1, y) + right = (x + 1, y) + up = (x, y + 1) + down = (x, y - 1) + + for neighbours in [left, right, up, down]: + if neighbours not in blocks: + if valid(neighbours) and neighbours not in visited: + # print("neighbour", neighbours) + visited.add(neighbours) + back_pointer[neighbours] = -1 + g_function[neighbours] = float("inf") + + if valid(neighbours) and g_function[neighbours] > g_function[s] + 1: + g_function[neighbours] = g_function[s] + 1 + back_pointer[neighbours] = s + if neighbours not in close_list_anchor: + open_list[0].put(neighbours, key(neighbours, 0, goal, g_function)) + if neighbours not in close_list_inad: + for var in range(1, n_heuristic): + if key(neighbours, var, goal, g_function) <= W2 * key( + neighbours, 0, goal, g_function + ): + open_list[j].put( + neighbours, key(neighbours, var, goal, g_function) + ) + + +def make_common_ground(): + some_list = [] + for x in range(1, 5): + for y in range(1, 6): + some_list.append((x, y)) + + for x in range(15, 20): + some_list.append((x, 17)) + + for x in range(10, 19): + for y in range(1, 15): + some_list.append((x, y)) + + # L block + for x in range(1, 4): + for y in range(12, 19): + some_list.append((x, y)) + for x in range(3, 13): + for y in range(16, 19): + some_list.append((x, y)) + return some_list + + +heuristics = {0: consistent_heuristic, 1: heuristic_1, 2: heuristic_2} + +blocks_blk = [ + (0, 1), + (1, 1), + (2, 1), + (3, 1), + (4, 1), + (5, 1), + (6, 1), + (7, 1), + (8, 1), + (9, 1), + (10, 1), + (11, 1), + (12, 1), + (13, 1), + (14, 1), + (15, 1), + (16, 1), + (17, 1), + (18, 1), + (19, 1), +] +blocks_all = make_common_ground() + + +blocks = blocks_blk +# hyper parameters +W1 = 1 +W2 = 1 +n = 20 +n_heuristic = 3 # one consistent and two other inconsistent + +# start and end destination +start = (0, 0) +goal = (n - 1, n - 1) + +t = 1 + + +def multi_a_star(start: TPos, goal: TPos, n_heuristic: int): + g_function = {start: 0, goal: float("inf")} + back_pointer = {start: -1, goal: -1} + open_list = [] + visited = set() + + for i in range(n_heuristic): + open_list.append(PriorityQueue()) + open_list[i].put(start, key(start, i, goal, g_function)) + + close_list_anchor: list[int] = [] + close_list_inad: list[int] = [] + while open_list[0].minkey() < float("inf"): + for i in range(1, n_heuristic): + # print(open_list[0].minkey(), open_list[i].minkey()) + if open_list[i].minkey() <= W2 * open_list[0].minkey(): + global t + t += 1 + if g_function[goal] <= open_list[i].minkey(): + if g_function[goal] < float("inf"): + do_something(back_pointer, goal, start) + else: + _, get_s = open_list[i].top_show() + visited.add(get_s) + expand_state( + get_s, + i, + visited, + g_function, + close_list_anchor, + close_list_inad, + open_list, + back_pointer, + ) + close_list_inad.append(get_s) + elif g_function[goal] <= open_list[0].minkey(): + if g_function[goal] < float("inf"): + do_something(back_pointer, goal, start) + else: + get_s = open_list[0].top_show() + visited.add(get_s) + expand_state( + get_s, + 0, + visited, + g_function, + close_list_anchor, + close_list_inad, + open_list, + back_pointer, + ) + close_list_anchor.append(get_s) + print("No path found to goal") + print() + for i in range(n - 1, -1, -1): + for j in range(n): + if (j, i) in blocks: + print("#", end=" ") + elif (j, i) in back_pointer: + if (j, i) == (n - 1, n - 1): + print("*", end=" ") + else: + print("-", end=" ") + else: + print("*", end=" ") + if (j, i) == (n - 1, n - 1): + print("<-- End position", end=" ") + print() + print("^") + print("Start position") + print() + print("# is an obstacle") + print("- is the path taken by algorithm") + + +if __name__ == "__main__": + multi_a_star(start, goal, n_heuristic) diff --git a/python/Graphs/page_rank.py b/python/Graphs/page_rank.py new file mode 100644 index 00000000..c0ce3a94 --- /dev/null +++ b/python/Graphs/page_rank.py @@ -0,0 +1,71 @@ +""" +Author: https://github.com/bhushan-borole +""" + +""" +The input graph for the algorithm is: + + A B C +A 0 1 1 +B 0 0 1 +C 1 0 0 + +""" + +graph = [[0, 1, 1], [0, 0, 1], [1, 0, 0]] + + +class Node: + def __init__(self, name): + self.name = name + self.inbound = [] + self.outbound = [] + + def add_inbound(self, node): + self.inbound.append(node) + + def add_outbound(self, node): + self.outbound.append(node) + + def __repr__(self): + return f"" + + +def page_rank(nodes, limit=3, d=0.85): + ranks = {} + for node in nodes: + ranks[node.name] = 1 + + outbounds = {} + for node in nodes: + outbounds[node.name] = len(node.outbound) + + for i in range(limit): + print(f"======= Iteration {i + 1} =======") + for _, node in enumerate(nodes): + ranks[node.name] = (1 - d) + d * sum( + ranks[ib] / outbounds[ib] for ib in node.inbound + ) + print(ranks) + + +def main(): + names = list(input("Enter Names of the Nodes: ").split()) + + nodes = [Node(name) for name in names] + + for ri, row in enumerate(graph): + for ci, col in enumerate(row): + if col == 1: + nodes[ci].add_inbound(names[ri]) + nodes[ri].add_outbound(names[ci]) + + print("======= Nodes =======") + for node in nodes: + print(node) + + page_rank(nodes) + + +if __name__ == "__main__": + main() diff --git a/python/Graphs/prim.py b/python/Graphs/prim.py new file mode 100644 index 00000000..5b3ce044 --- /dev/null +++ b/python/Graphs/prim.py @@ -0,0 +1,152 @@ +"""Prim's Algorithm. + +Determines the minimum spanning tree(MST) of a graph using the Prim's Algorithm. + +Details: https://en.wikipedia.org/wiki/Prim%27s_algorithm +""" + +import heapq as hq +import math +from collections.abc import Iterator + + +class Vertex: + """Class Vertex.""" + + def __init__(self, id_): + """ + Arguments: + id - input an id to identify the vertex + Attributes: + neighbors - a list of the vertices it is linked to + edges - a dict to store the edges's weight + """ + self.id = str(id_) + self.key = None + self.pi = None + self.neighbors = [] + self.edges = {} # {vertex:distance} + + def __lt__(self, other): + """Comparison rule to < operator.""" + return self.key < other.key + + def __repr__(self): + """Return the vertex id.""" + return self.id + + def add_neighbor(self, vertex): + """Add a pointer to a vertex at neighbor's list.""" + self.neighbors.append(vertex) + + def add_edge(self, vertex, weight): + """Destination vertex and weight.""" + self.edges[vertex.id] = weight + + +def connect(graph, a, b, edge): + # add the neighbors: + graph[a - 1].add_neighbor(graph[b - 1]) + graph[b - 1].add_neighbor(graph[a - 1]) + # add the edges: + graph[a - 1].add_edge(graph[b - 1], edge) + graph[b - 1].add_edge(graph[a - 1], edge) + + +def prim(graph: list, root: Vertex) -> list: + """Prim's Algorithm. + + Runtime: + O(mn) with `m` edges and `n` vertices + + Return: + List with the edges of a Minimum Spanning Tree + + Usage: + prim(graph, graph[0]) + """ + a = [] + for u in graph: + u.key = math.inf + u.pi = None + root.key = 0 + q = graph[:] + while q: + u = min(q) + q.remove(u) + for v in u.neighbors: + if (v in q) and (u.edges[v.id] < v.key): + v.pi = u + v.key = u.edges[v.id] + for i in range(1, len(graph)): + a.append((int(graph[i].id) + 1, int(graph[i].pi.id) + 1)) + return a + + +def prim_heap(graph: list, root: Vertex) -> Iterator[tuple]: + """Prim's Algorithm with min heap. + + Runtime: + O((m + n)log n) with `m` edges and `n` vertices + + Yield: + Edges of a Minimum Spanning Tree + + Usage: + prim(graph, graph[0]) + """ + for u in graph: + u.key = math.inf + u.pi = None + root.key = 0 + + h = list(graph) + hq.heapify(h) + + while h: + u = hq.heappop(h) + for v in u.neighbors: + if (v in h) and (u.edges[v.id] < v.key): + v.pi = u + v.key = u.edges[v.id] + hq.heapify(h) + + for i in range(1, len(graph)): + yield (int(graph[i].id) + 1, int(graph[i].pi.id) + 1) + + +def test_vector() -> None: + """ + # Creates a list to store x vertices. + >>> x = 5 + >>> G = [Vertex(n) for n in range(x)] + + >>> connect(G, 1, 2, 15) + >>> connect(G, 1, 3, 12) + >>> connect(G, 2, 4, 13) + >>> connect(G, 2, 5, 5) + >>> connect(G, 3, 2, 6) + >>> connect(G, 3, 4, 6) + >>> connect(G, 0, 0, 0) # Generate the minimum spanning tree: + >>> G_heap = G[:] + >>> MST = prim(G, G[0]) + >>> MST_heap = prim_heap(G, G[0]) + >>> for i in MST: + ... print(i) + (2, 3) + (3, 1) + (4, 3) + (5, 2) + >>> for i in MST_heap: + ... print(i) + (2, 3) + (3, 1) + (4, 3) + (5, 2) + """ + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/random_graph_generator.py b/python/Graphs/random_graph_generator.py new file mode 100644 index 00000000..0e7e18bc --- /dev/null +++ b/python/Graphs/random_graph_generator.py @@ -0,0 +1,67 @@ +""" +* Author: Manuel Di Lullo (https://github.com/manueldilullo) +* Description: Random graphs generator. + Uses graphs represented with an adjacency list. + +URL: https://en.wikipedia.org/wiki/Random_graph +""" + +import random + + +def random_graph( + vertices_number: int, probability: float, directed: bool = False +) -> dict: + """ + Generate a random graph + @input: vertices_number (number of vertices), + probability (probability that a generic edge (u,v) exists), + directed (if True: graph will be a directed graph, + otherwise it will be an undirected graph) + @examples: + >>> random.seed(1) + >>> random_graph(4, 0.5) + {0: [1], 1: [0, 2, 3], 2: [1, 3], 3: [1, 2]} + >>> random.seed(1) + >>> random_graph(4, 0.5, True) + {0: [1], 1: [2, 3], 2: [3], 3: []} + """ + graph: dict = {i: [] for i in range(vertices_number)} + + # if probability is greater or equal than 1, then generate a complete graph + if probability >= 1: + return complete_graph(vertices_number) + # if probability is lower or equal than 0, then return a graph without edges + if probability <= 0: + return graph + + # for each couple of nodes, add an edge from u to v + # if the number randomly generated is greater than probability probability + for i in range(vertices_number): + for j in range(i + 1, vertices_number): + if random.random() < probability: + graph[i].append(j) + if not directed: + # if the graph is undirected, add an edge in from j to i, either + graph[j].append(i) + return graph + + +def complete_graph(vertices_number: int) -> dict: + """ + Generate a complete graph with vertices_number vertices. + @input: vertices_number (number of vertices), + directed (False if the graph is undirected, True otherwise) + @example: + >>> complete_graph(3) + {0: [1, 2], 1: [0, 2], 2: [0, 1]} + """ + return { + i: [j for j in range(vertices_number) if i != j] for i in range(vertices_number) + } + + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/python/Graphs/scc_kosaraju.py b/python/Graphs/scc_kosaraju.py new file mode 100644 index 00000000..39211c64 --- /dev/null +++ b/python/Graphs/scc_kosaraju.py @@ -0,0 +1,54 @@ +from __future__ import annotations + + +def dfs(u): + global graph, reversed_graph, scc, component, visit, stack + if visit[u]: + return + visit[u] = True + for v in graph[u]: + dfs(v) + stack.append(u) + + +def dfs2(u): + global graph, reversed_graph, scc, component, visit, stack + if visit[u]: + return + visit[u] = True + component.append(u) + for v in reversed_graph[u]: + dfs2(v) + + +def kosaraju(): + global graph, reversed_graph, scc, component, visit, stack + for i in range(n): + dfs(i) + visit = [False] * n + for i in stack[::-1]: + if visit[i]: + continue + component = [] + dfs2(i) + scc.append(component) + return scc + + +if __name__ == "__main__": + # n - no of nodes, m - no of edges + n, m = list(map(int, input().strip().split())) + + graph: list[list[int]] = [[] for _ in range(n)] # graph + reversed_graph: list[list[int]] = [[] for i in range(n)] # reversed graph + # input graph data (edges) + for _ in range(m): + u, v = list(map(int, input().strip().split())) + graph[u].append(v) + reversed_graph[v].append(u) + + stack: list[int] = [] + visit: list[bool] = [False] * n + scc: list[int] = [] + component: list[int] = [] + print(kosaraju()) diff --git a/python/Graphs/strongly_connected_components.py b/python/Graphs/strongly_connected_components.py new file mode 100644 index 00000000..4d4cf880 --- /dev/null +++ b/python/Graphs/strongly_connected_components.py @@ -0,0 +1,90 @@ +""" +https://en.wikipedia.org/wiki/Strongly_connected_component + +Finding strongly connected components in directed graph + +""" + +test_graph_1 = {0: [2, 3], 1: [0], 2: [1], 3: [4], 4: []} + +test_graph_2 = {0: [1, 2, 3], 1: [2], 2: [0], 3: [4], 4: [5], 5: [3]} + + +def topology_sort( + graph: dict[int, list[int]], vert: int, visited: list[bool] +) -> list[int]: + """ + Use depth first search to sort graph + At this time graph is the same as input + >>> topology_sort(test_graph_1, 0, 5 * [False]) + [1, 2, 4, 3, 0] + >>> topology_sort(test_graph_2, 0, 6 * [False]) + [2, 1, 5, 4, 3, 0] + """ + + visited[vert] = True + order = [] + + for neighbour in graph[vert]: + if not visited[neighbour]: + order += topology_sort(graph, neighbour, visited) + + order.append(vert) + + return order + + +def find_components( + reversed_graph: dict[int, list[int]], vert: int, visited: list[bool] +) -> list[int]: + """ + Use depth first search to find strongly connected + vertices. Now graph is reversed + >>> find_components({0: [1], 1: [2], 2: [0]}, 0, 5 * [False]) + [0, 1, 2] + >>> find_components({0: [2], 1: [0], 2: [0, 1]}, 0, 6 * [False]) + [0, 2, 1] + """ + + visited[vert] = True + component = [vert] + + for neighbour in reversed_graph[vert]: + if not visited[neighbour]: + component += find_components(reversed_graph, neighbour, visited) + + return component + + +def strongly_connected_components(graph: dict[int, list[int]]) -> list[list[int]]: + """ + This function takes graph as a parameter + and then returns the list of strongly connected components + >>> strongly_connected_components(test_graph_1) + [[0, 1, 2], [3], [4]] + >>> strongly_connected_components(test_graph_2) + [[0, 2, 1], [3, 5, 4]] + """ + + visited = len(graph) * [False] + reversed_graph: dict[int, list[int]] = {vert: [] for vert in range(len(graph))} + + for vert, neighbours in graph.items(): + for neighbour in neighbours: + reversed_graph[neighbour].append(vert) + + order = [] + for i, was_visited in enumerate(visited): + if not was_visited: + order += topology_sort(graph, i, visited) + + components_list = [] + visited = len(graph) * [False] + + for i in range(len(graph)): + vert = order[len(graph) - i - 1] + if not visited[vert]: + component = find_components(reversed_graph, vert, visited) + components_list.append(component) + + return components_list diff --git a/python/Graphs/tarjans_scc.py b/python/Graphs/tarjans_scc.py new file mode 100644 index 00000000..b4a3bd5c --- /dev/null +++ b/python/Graphs/tarjans_scc.py @@ -0,0 +1,106 @@ +from collections import deque + + +def tarjan(g: list[list[int]]) -> list[list[int]]: + """ + Tarjan's algo for finding strongly connected components in a directed graph + + Uses two main attributes of each node to track reachability, the index of that node + within a component(index), and the lowest index reachable from that node(lowlink). + + We then perform a dfs of the each component making sure to update these parameters + for each node and saving the nodes we visit on the way. + + If ever we find that the lowest reachable node from a current node is equal to the + index of the current node then it must be the root of a strongly connected + component and so we save it and it's equireachable vertices as a strongly + connected component. + + Complexity: strong_connect() is called at most once for each node and has a + complexity of O(|E|) as it is DFS. + Therefore this has complexity O(|V| + |E|) for a graph G = (V, E) + + >>> tarjan([[2, 3, 4], [2, 3, 4], [0, 1, 3], [0, 1, 2], [1]]) + [[4, 3, 1, 2, 0]] + >>> tarjan([[], [], [], []]) + [[0], [1], [2], [3]] + >>> a = [0, 1, 2, 3, 4, 5, 4] + >>> b = [1, 0, 3, 2, 5, 4, 0] + >>> n = 7 + >>> sorted(tarjan(create_graph(n, list(zip(a, b))))) == sorted( + ... tarjan(create_graph(n, list(zip(a[::-1], b[::-1]))))) + True + >>> a = [0, 1, 2, 3, 4, 5, 6] + >>> b = [0, 1, 2, 3, 4, 5, 6] + >>> sorted(tarjan(create_graph(n, list(zip(a, b))))) + [[0], [1], [2], [3], [4], [5], [6]] + """ + + n = len(g) + stack: deque[int] = deque() + on_stack = [False for _ in range(n)] + index_of = [-1 for _ in range(n)] + lowlink_of = index_of[:] + + def strong_connect(v: int, index: int, components: list[list[int]]) -> int: + index_of[v] = index # the number when this node is seen + lowlink_of[v] = index # lowest rank node reachable from here + index += 1 + stack.append(v) + on_stack[v] = True + + for w in g[v]: + if index_of[w] == -1: + index = strong_connect(w, index, components) + lowlink_of[v] = ( + lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] + ) + elif on_stack[w]: + lowlink_of[v] = ( + lowlink_of[w] if lowlink_of[w] < lowlink_of[v] else lowlink_of[v] + ) + + if lowlink_of[v] == index_of[v]: + component = [] + w = stack.pop() + on_stack[w] = False + component.append(w) + while w != v: + w = stack.pop() + on_stack[w] = False + component.append(w) + components.append(component) + return index + + components: list[list[int]] = [] + for v in range(n): + if index_of[v] == -1: + strong_connect(v, 0, components) + + return components + + +def create_graph(n: int, edges: list[tuple[int, int]]) -> list[list[int]]: + """ + >>> n = 7 + >>> source = [0, 0, 1, 2, 3, 3, 4, 4, 6] + >>> target = [1, 3, 2, 0, 1, 4, 5, 6, 5] + >>> edges = list(zip(source, target)) + >>> create_graph(n, edges) + [[1, 3], [2], [0], [1, 4], [5, 6], [], [5]] + """ + g: list[list[int]] = [[] for _ in range(n)] + for u, v in edges: + g[u].append(v) + return g + + +if __name__ == "__main__": + # Test + n_vertices = 7 + source = [0, 0, 1, 2, 3, 3, 4, 4, 6] + target = [1, 3, 2, 0, 1, 4, 5, 6, 5] + edges = list(zip(source, target)) + g = create_graph(n_vertices, edges) + + assert tarjan(g) == [[5], [6], [4], [3, 2, 1, 0]] diff --git a/python/Graphs_BFS_Tranversal.py b/python/Graphs_BFS_Tranversal.py new file mode 100644 index 00000000..7440aeb4 --- /dev/null +++ b/python/Graphs_BFS_Tranversal.py @@ -0,0 +1,27 @@ +# Breadth First Search (BFS) Traversal in Python + +def bfs(graph, start): + visited = [] + queue = [start] + + while queue: + node = queue.pop(0) + + if node not in visited: + visited.append(node) + queue.extend(graph[node]) + + return visited + + +# Example usage: +graph = { + 'A': ['B', 'C'], + 'B': ['A', 'D', 'E'], + 'C': ['A', 'F'], + 'D': ['B'], + 'E': ['B', 'F'], + 'F': ['C', 'E'] +} + +print("BFS Traversal:", bfs(graph, 'A')) diff --git a/python/Greedy Algorithm/Serialize-and-Deserialize-Binary-Tree.py b/python/Greedy Algorithm/Serialize-and-Deserialize-Binary-Tree.py new file mode 100644 index 00000000..a3d7e6d7 --- /dev/null +++ b/python/Greedy Algorithm/Serialize-and-Deserialize-Binary-Tree.py @@ -0,0 +1,92 @@ +#Using Preorder Traversal with Null Markers + +# Definition for a binary tree node. +class TreeNode(object): + def __init__(self, x): + self.val = x + self.left = None + self.right = None + +class Codec: + def serialize(self, root): + """Encodes a tree to a single string. + + :type root: TreeNode + :rtype: str + """ + def preorder(node): + if not node: + return ["null"] + return [str(node.val)] + preorder(node.left) + preorder(node.right) + + return ",".join(preorder(root)) + + def deserialize(self, data): + """Decodes your encoded data to tree. + + :type data: str + :rtype: TreeNode + """ + nodes = data.split(",") + self.index = 0 + + def build_tree(): + if self.index >= len(nodes) or nodes[self.index] == "null": + self.index += 1 + return None + + node = TreeNode(int(nodes[self.index])) + self.index += 1 + node.left = build_tree() + node.right = build_tree() + return node + + return build_tree() + +# Alternative: Using iterative BFS approach +class CodecBFS: + def serialize(self, root): + """Encodes a tree to a single string using BFS.""" + if not root: + return "" + + queue = collections.deque([root]) + result = [] + + while queue: + node = queue.popleft() + if node: + result.append(str(node.val)) + queue.append(node.left) + queue.append(node.right) + else: + result.append("null") + + return ",".join(result) + + def deserialize(self, data): + """Decodes your encoded data to tree using BFS.""" + if not data: + return None + + nodes = data.split(",") + root = TreeNode(int(nodes[0])) + queue = collections.deque([root]) + index = 1 + + while queue and index < len(nodes): + node = queue.popleft() + + # Left child + if nodes[index] != "null": + node.left = TreeNode(int(nodes[index])) + queue.append(node.left) + index += 1 + + # Right child + if index < len(nodes) and nodes[index] != "null": + node.right = TreeNode(int(nodes[index])) + queue.append(node.right) + index += 1 + + return root \ No newline at end of file diff --git a/python/Greedy Algorithm/Spiral-Matrix-II .py b/python/Greedy Algorithm/Spiral-Matrix-II .py new file mode 100644 index 00000000..aab547a9 --- /dev/null +++ b/python/Greedy Algorithm/Spiral-Matrix-II .py @@ -0,0 +1,72 @@ +def generateMatrix(n): + """ + Generate an n x n matrix filled with elements from 1 to n² in spiral order. + + Args: + n: Size of the matrix (n x n) + + Returns: + List[List[int]]: The generated spiral matrix + """ + # Initialize matrix with zeros + matrix = [[0] * n for _ in range(n)] + + # Define boundaries + top, bottom = 0, n - 1 + left, right = 0, n - 1 + + num = 1 # Start filling from 1 + + while top <= bottom and left <= right: + # Fill top row from left to right + for i in range(left, right + 1): + matrix[top][i] = num + num += 1 + top += 1 + + # Fill right column from top to bottom + for i in range(top, bottom + 1): + matrix[i][right] = num + num += 1 + right -= 1 + + # Fill bottom row from right to left (if still within bounds) + if top <= bottom: + for i in range(right, left - 1, -1): + matrix[bottom][i] = num + num += 1 + bottom -= 1 + + # Fill left column from bottom to top (if still within bounds) + if left <= right: + for i in range(bottom, top - 1, -1): + matrix[i][left] = num + num += 1 + left += 1 + + return matrix + +# Alternative more concise solution +def generateMatrix_concise(n): + matrix = [[0] * n for _ in range(n)] + directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # right, down, left, up + row, col, direction = 0, 0, 0 + + for num in range(1, n * n + 1): + matrix[row][col] = num + + # Calculate next position + next_row = row + directions[direction][0] + next_col = col + directions[direction][1] + + # If next position is invalid or already filled, change direction + if (next_row < 0 or next_row >= n or + next_col < 0 or next_col >= n or + matrix[next_row][next_col] != 0): + direction = (direction + 1) % 4 + next_row = row + directions[direction][0] + next_col = col + directions[direction][1] + + row, col = next_row, next_col + + return matrix \ No newline at end of file diff --git a/python/Greedy Algorithm/Symmetric-Tree.py b/python/Greedy Algorithm/Symmetric-Tree.py new file mode 100644 index 00000000..908fc0c4 --- /dev/null +++ b/python/Greedy Algorithm/Symmetric-Tree.py @@ -0,0 +1,41 @@ +#Recursive Approach +#python +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +class Solution: + def isSymmetric(self, root): + """ + Check if a binary tree is symmetric (mirror of itself). + + Args: + root: TreeNode - root of the binary tree + + Returns: + bool: True if tree is symmetric, False otherwise + """ + if not root: + return True + + def isMirror(left, right): + """ + Helper function to check if two trees are mirrors of each other. + """ + # If both nodes are None, they are symmetric + if not left and not right: + return True + + # If one is None and other is not, they are not symmetric + if not left or not right: + return False + + # Check if values are equal and subtrees are mirrors + return (left.val == right.val and + isMirror(left.left, right.right) and + isMirror(left.right, right.left)) + + return isMirror(root.left, root.right) \ No newline at end of file diff --git a/python/Greedy Algorithm/assignCookies.py b/python/Greedy Algorithm/assignCookies.py new file mode 100644 index 00000000..2c978f25 --- /dev/null +++ b/python/Greedy Algorithm/assignCookies.py @@ -0,0 +1,49 @@ +""" + Assign Cookies + +Problem Statement: Assume you are an awesome parent and want to give your children some cookies. But, you should give each child at most one cookie. +Each child i has a greed factor g[i], which is the minimum size of a cookie that the child will be content with; and each cookie j has a size s[j]. If s[j] >= g[i], we can assign the cookie j to the child i, and the child i will be content. Your goal is to maximize the number of your content children and output the maximum number. + +Algorithm / Intuition: Greedy Algorithms are approached to solve problems by making the current best choice at each stage with the hope of getting the best answer overall as well. At each step of the algorithm, we choose the best possible option available without considering the consequences of the choice in future steps. +To solve this question, we sort the greed and cookies array to easily make decisions about which cookie to assign to which child. We then iterate over the sorted arrays comparing elements and assigning the smallest available cookie with the least greedy child. +This way we are able to leave larger cookies for potentially gredier children so that we are able to maximise the overall satisfaction. + +Algorithm: +Step 1:Sort both the greed and cookieSize array. By sorting, we are able to pair the smallest cookies with the least greedy children, maximising overall content. +Step 2: Use two pointers, l and r to iterate through the cookieSize and greed arrays. These pointers represent the positions of the smallest available cookie and the least greedy child. +Step 3: We iterate through the arrays, checking if the current cookie can satisfy the current child’s greed. Ie. cookieSize[l] >= greed[r]. +If the current cookie can satisfy the current child’s greed, we move to the next child. +Regardless of whether a child is satisfied or not, we move to the next cookie. +Step 4: At the end, the value of r, represents the number of children that were satisfied as we increment it each time a child’s greed is satisfied. We return this value as the total number of satisfied children. +""" + +def assignCookies(g, s): + g.sort() + s.sort() + child = 0 + cookie = 0 + while child < len(g) and cookie < len(s): + if s[cookie] >= g[child]: + child += 1 + cookie += 1 + return child + +#Sample Input For Checking +g = [1, 2, 3] +s = [1, 1, 2, 3] + +print("Maximum content:", assignCookies(g, s))#Output: 3 + +""" +Complexity + +Time Complexity: O(n log n + m log m) +Space Complexity: O(1) (in-place) +""" + +""" +g → Greed Factors of Children +s → Sizes of Cookies +n → The number of children +m→ The number of cookies +""" \ No newline at end of file diff --git a/python/Greedy Algorithm/lemonadeChange.py b/python/Greedy Algorithm/lemonadeChange.py new file mode 100644 index 00000000..7e91fd69 --- /dev/null +++ b/python/Greedy Algorithm/lemonadeChange.py @@ -0,0 +1,57 @@ +""" + Lemonade Change + +Problem Statement: At a lemonade stand, each lemonade costs $5. Customers are standing in a queue to buy from you and order one at a time (in the order specified by bills). Each customer will only buy one lemonade and pay with either a $5, $10, or $20 bill. You must provide the correct change to each customer so that the net transaction is that the customer pays $5. +Note that you do not have any change in hand at first. +Given an integer array bills where bills[i] is the bill the ith customer pays, return true if you can provide every customer with the correct change, or false otherwise. + +Algorithm / Intuition: We can approach this question by maintaining two counters to keep track of the available 5$ and 10$ bills. We iterate through the customers and provide change accordingly. +If a customer pays with a 5$ bill, we simply keep it as we will not have to provide any change. If the customer pays with a 10$ bill, we check if there is at least one 5$ bill available to provide change and decrement the counter. +If the customer uses a 20$ bill, we provide change using 5$ and 10$ bills or with three 5$ bills. If at any point, we are not able to provide the required change we return false. +Otherwise, if we successfully serve all customers with the correct change, we can return true. + +Algorithm: +Step 1:Initialise two counters, fives and tens to keep track of the number of 5$ and 10$ bills at hand. Initialise them to zero as we hold no change at the starting. +Step 2: Loop through each bill in the bills array and check the following: If the bill is 5$, increment the fives counter. +Step 3: If the bill is 10$, check if there are any 5$ bills available. +If yes, provide change by incrementing the 10$ bill counter and decrementing the 5$ bill counter. +If there are no 5$ bills available, return false as we cannot provide change. +Step 4: If the current bill is 20$, check if both 5$ and 10$ bills are available. If yes, provide change by decreasing the counter of 5$ and 10$ bills. +If there are not enough 10$ bills available, check if there are at atleast three 5$ bills available. If yes, provide change by decreasing the 5$ counter by 3. +If not able to provide change, return false. +Step 5: If all customers are served with the correct change, we exit out of the loop and return true. +""" +def lemonadeChange(bills): + five, ten = 0, 0 + for bill in bills: + if bill == 5: + five += 1 + elif bill == 10: + if five == 0: + return False + five -= 1 + ten += 1 + else: + if ten > 0 and five > 0: + ten -= 1 + five -= 1 + elif five >= 3: + five -= 3 + else: + return False + return True + +#Sample Input For Checking +bills1 = [5,5,5,10,20] +bills2 = [5,5,10,10,20] + +print(lemonadeChange(bills1)) #Output: True +print(lemonadeChange(bills2)) #Output: False + +""" +Complexity + +Time Complexity: O(n) +where n = len(bills) +Space Complexity: O(1) +""" diff --git a/python/Greedy Algorithm/rearranging_fruits.py b/python/Greedy Algorithm/rearranging_fruits.py new file mode 100644 index 00000000..fb5d1ed4 --- /dev/null +++ b/python/Greedy Algorithm/rearranging_fruits.py @@ -0,0 +1,31 @@ +# Leetcode Question Number 2561 +# Greedy Approach + +from typing import List +from collections import defaultdict + +class Solution: + def minCost(self, basket1: List[int], basket2: List[int]) -> int: + n = len(basket1) + freq = defaultdict(int) + mn = float('inf') + for i in range(n): + freq[basket1[i]] += 1 + freq[basket2[i]] -= 1 + mn = min(mn, basket1[i], basket2[i]) + + to_swap = [] + for j,k in freq.items(): + if k % 2 != 0: + return -1 + to_swap += [j] * (abs(k) // 2) + + to_swap.sort() + res = 0 + for i in range(len(to_swap) // 2): + res += min(to_swap[i], 2 * mn) + + return res + +s = Solution() +print(s.minCost([4, 2, 2, 2], [1, 4, 1, 2])) # Output: 1 diff --git a/python/Guess_the_number.py b/python/Guess_the_number.py new file mode 100644 index 00000000..def7241b --- /dev/null +++ b/python/Guess_the_number.py @@ -0,0 +1,17 @@ +import random + +# Computer chooses a number between 1 and 10 +number = random.randint(1, 10) + +print("🎯 Welcome to the Guessing Game!") +print("I'm thinking of a number between 1 and 10.") + +while True: + guess = int(input("Enter your guess: ")) + if guess > number: + print("Too high! Hint: Try a smaller number.") + elif guess < number: + print("Too low! Hint: Try a bigger number.") + else: + print("✅ Correct! You guessed the number!") + break diff --git a/python/Histogram.py b/python/Histogram.py new file mode 100644 index 00000000..9756550c --- /dev/null +++ b/python/Histogram.py @@ -0,0 +1,37 @@ +import cv2 +import matplotlib.pyplot as plt + +# Read the uploaded image in grayscale +img = cv2.imread('grayimg.jpeg', 0) + +# Apply Histogram Equalization +equalized_img = cv2.equalizeHist(img) + +# Show both images +cv2.imshow("Original Image", img) +cv2.imshow("Enhanced Image (Equalized)", equalized_img) + + +# Save histogram of original image as question1.png +plt.figure() +plt.hist(img.ravel(), bins=256, range=(0, 256)) +plt.title("Histogram of Original Image") +plt.xlabel("Pixel Intensity") +plt.ylabel("Frequency") +plt.savefig("question1.png") +plt.close() # Close the figure to free memory + +# Save histogram of equalized image as question3.png +plt.figure() +plt.hist(equalized_img.ravel(), bins=256, range=(0, 256)) +plt.title("Histogram of Equalized Image") +plt.xlabel("Pixel Intensity") +plt.ylabel("Frequency") +plt.savefig("question3.png") +plt.close() # Close the figure + +# Optionally, you can display the images using OpenCV if needed +cv2.imshow("Original Image", img) +cv2.imshow("Enhanced Image (Equalized)", equalized_img) +cv2.waitKey(0) +cv2.destroyAllWindows() diff --git a/python/House_Robber.py b/python/House_Robber.py new file mode 100644 index 00000000..77c1a6b5 --- /dev/null +++ b/python/House_Robber.py @@ -0,0 +1,20 @@ +class Solution: + def rob(self, nums): + rob1, rob2 = 0, 0 + max_val = 0 + + for n in nums: + max_val = max(n + rob1, rob2) + rob1 = rob2 + rob2 = max_val + + return max_val + + +# Main function to run the code +if __name__ == "__main__": + # Example input + nums = [2, 7, 9, 3, 1] # You can change this test case + solution = Solution() + result = solution.rob(nums) + print("Maximum amount that can be robbed:", result) diff --git a/python/LinearSearch.py b/python/LinearSearch.py new file mode 100644 index 00000000..17be542d --- /dev/null +++ b/python/LinearSearch.py @@ -0,0 +1,26 @@ +def linear_search(arr, target): + """ + Performs linear search on a list to find the target value. + + Args: + arr (list): The list to search in. + target (any): The value to search for. + + Returns: + int: The index of the target if found, else -1. + """ + for index, value in enumerate(arr): + if value == target: + return index # Target found + return -1 # Target not found + +# Example usage +numbers = [10, 20, 30, 40, 50] +target = 30 + +result = linear_search(numbers, target) + +if result != -1: + print(f"Element {target} found at index {result}.") +else: + print(f"Element {target} not found in the list.") diff --git a/python/Linked_list_insert.py b/python/Linked_list_insert.py new file mode 100644 index 00000000..32a0ae85 --- /dev/null +++ b/python/Linked_list_insert.py @@ -0,0 +1,51 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + # Insert at start + def insert_at_start(self, data): + new_node = Node(data) + new_node.next = self.head + self.head = new_node + + # Delete at end + def delete_at_end(self): + if self.head is None: + print("List is empty") + return + + if self.head.next is None: + self.head = None + return + + temp = self.head + while temp.next.next: # stop at second-last node + temp = temp.next + temp.next = None + + # Display the list + def display(self): + temp = self.head + while temp: + print(temp.data, end=" -> ") + temp = temp.next + print("NULL") + + +# Example usage +ll = LinkedList() +ll.insert_at_start(10) +ll.insert_at_start(20) +ll.insert_at_start(30) + +print("Original Linked List:") +ll.display() + +ll.delete_at_end() +print("After deleting at end:") +ll.display() diff --git a/python/Linked_list_insert_at_end.py b/python/Linked_list_insert_at_end.py new file mode 100644 index 00000000..32a0ae85 --- /dev/null +++ b/python/Linked_list_insert_at_end.py @@ -0,0 +1,51 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + # Insert at start + def insert_at_start(self, data): + new_node = Node(data) + new_node.next = self.head + self.head = new_node + + # Delete at end + def delete_at_end(self): + if self.head is None: + print("List is empty") + return + + if self.head.next is None: + self.head = None + return + + temp = self.head + while temp.next.next: # stop at second-last node + temp = temp.next + temp.next = None + + # Display the list + def display(self): + temp = self.head + while temp: + print(temp.data, end=" -> ") + temp = temp.next + print("NULL") + + +# Example usage +ll = LinkedList() +ll.insert_at_start(10) +ll.insert_at_start(20) +ll.insert_at_start(30) + +print("Original Linked List:") +ll.display() + +ll.delete_at_end() +print("After deleting at end:") +ll.display() diff --git a/python/Linked_list_insert_at_kth_index.py b/python/Linked_list_insert_at_kth_index.py new file mode 100644 index 00000000..905957d0 --- /dev/null +++ b/python/Linked_list_insert_at_kth_index.py @@ -0,0 +1,80 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + # Insert at start + def insert_at_start(self, data): + new_node = Node(data) + new_node.next = self.head + self.head = new_node + + # Insert at kth index (0-based index) + def insert_at_index(self, data, k): + new_node = Node(data) + + # If inserting at head + if k == 0: + new_node.next = self.head + self.head = new_node + return + + temp = self.head + count = 0 + while temp is not None and count < k-1: + temp = temp.next + count += 1 + + if temp is None: + print("Index out of range") + return + + new_node.next = temp.next + temp.next = new_node + + # Delete at end + def delete_at_end(self): + if self.head is None: + print("List is empty") + return + + if self.head.next is None: + self.head = None + return + + temp = self.head + while temp.next.next: + temp = temp.next + temp.next = None + + # Display the list + def display(self): + temp = self.head + while temp: + print(temp.data, end=" -> ") + temp = temp.next + print("NULL") + + +# Example usage +ll = LinkedList() +ll.insert_at_start(10) +ll.insert_at_start(20) +ll.insert_at_start(30) + +print("Original Linked List:") +ll.display() + +ll.insert_at_index(25, 1) # Insert 25 at index 1 +print("After inserting 25 at index 1:") +ll.display() + +ll.insert_at_index(5, 0) # Insert 5 at index 0 (start) +print("After inserting 5 at index 0:") +ll.display() + +ll.insert_at_index(50, 10) # Out of range diff --git a/python/Linked_list_insert_at_start.py b/python/Linked_list_insert_at_start.py new file mode 100644 index 00000000..724263b7 --- /dev/null +++ b/python/Linked_list_insert_at_start.py @@ -0,0 +1,31 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + # Insert at start + def insert_at_start(self, data): + new_node = Node(data) + new_node.next = self.head # Point to old head + self.head = new_node # Update head + + # Display the list + def display(self): + temp = self.head + while temp: + print(temp.data, end=" -> ") + temp = temp.next + print("NULL") + +# sample usage +ll = LinkedList() +ll.insert_at_start(10) +ll.insert_at_start(20) +ll.insert_at_start(30) + +print("Linked List:") +ll.display() diff --git a/python/Linked_list_pop_first.py b/python/Linked_list_pop_first.py new file mode 100644 index 00000000..c9c5ab8e --- /dev/null +++ b/python/Linked_list_pop_first.py @@ -0,0 +1,75 @@ +class Node: + def __init__(self, value): + self.value = value + self.next = None + +class LinkedList: + def __init__(self, value): + new_node = Node(value) + self.head = new_node + self.tail = new_node + self.length = 1 + + def print_list(self): + temp = self.head + while temp is not None: + print(temp.value) + temp = temp.next + + def append(self, value): + new_node = Node(value) + if self.length == 0: + self.head = new_node + self.tail = new_node + else: + self.tail.next = new_node + self.tail = new_node + self.length += 1 + return True + + def pop(self): + if self.length == 0: + return None + temp = self.head + pre = self.head + while(temp.next): + pre = temp + temp = temp.next + self.tail = pre + self.tail.next = None + self.length -= 1 + if self.length == 0: + self.head = None + self.tail = None + return temp + + def prepend(self, value): + new_node = Node(value) + if self.length == 0: + self.head = new_node + self.tail = new_node + else: + new_node.next = self.head + self.head = new_node + self.length += 1 + return True + + def pop_first(self): + if self.length == 0: + return None + temp = self.head + self.head = self.head.next + temp.next = None + self.length -= 1 + if self.length == 0: + self.tail = None + return temp + + +my_linked_list = LinkedList(2) +my_linked_list.append(1) + + +print(my_linked_list.pop_first().value) +print(my_linked_list.pop_first().value) +print(my_linked_list.pop_first()) \ No newline at end of file diff --git a/python/Lonely Number Finder.py b/python/Lonely Number Finder.py new file mode 100644 index 00000000..87a784ef --- /dev/null +++ b/python/Lonely Number Finder.py @@ -0,0 +1,15 @@ +def find_lonely(nums): + from collections import Counter + count = Counter(nums) + lonely = [] + + for num in nums: + if count[num] == 1 and count[num - 1] == 0 and count[num + 1] == 0: + lonely.append(num) + + return sorted(lonely) + +# Example runs +print(find_lonely([10, 6, 5, 8])) # Output: [8, 10] +print(find_lonely([1, 3, 5, 3])) # Output: [1, 5] +print(find_lonely([7, 8, 9, 10])) # Output: [] diff --git a/python/Longest_Alternating_Even_Odd_Subarray.py b/python/Longest_Alternating_Even_Odd_Subarray.py new file mode 100644 index 00000000..b2881ba0 --- /dev/null +++ b/python/Longest_Alternating_Even_Odd_Subarray.py @@ -0,0 +1,25 @@ +# Longest_Alternating_Even_Odd_Subarray.py + +def longestAlternatingEvenOdd(arr): + if not arr: + return 0 + + max_len = 1 + curr_len = 1 + + for i in range(1, len(arr)): + # Check alternating condition: + if (arr[i] % 2) != (arr[i-1] % 2): + curr_len += 1 + max_len = max(max_len, curr_len) + else: + curr_len = 1 + + return max_len + + +# Example usage: +if __name__ == "__main__": + nums = [3, 2, 5, 4, 7] + print("Input:", nums) + print("Longest Alternating Even-Odd Subarray Length:", longestAlternatingEvenOdd(nums)) diff --git a/python/Longest_Common_Subsequence.py b/python/Longest_Common_Subsequence.py index 9b0365db..e69de29b 100644 --- a/python/Longest_Common_Subsequence.py +++ b/python/Longest_Common_Subsequence.py @@ -1,21 +0,0 @@ -#Longest Common Subsequence (DP) -# Given two strings, find the length of their longest common subsequence. - -def lcs(X, Y): - m, n = len(X), len(Y) - dp = [[0] * (n + 1) for _ in range(m + 1)] - - for i in range(1, m + 1): - for j in range(1, n + 1): - if X[i - 1] == Y[j - 1]: - dp[i][j] = dp[i - 1][j - 1] + 1 - else: - dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) - - return dp[m][n] - -# Example usage -X = "AGGTAB" -Y = "GXTXAYB" -print("Length of LCS is:", lcs(X, Y)) # Output: 4 - diff --git a/python/Longest_Cons_Seq.py b/python/Longest_Cons_Seq.py new file mode 100644 index 00000000..9f849679 --- /dev/null +++ b/python/Longest_Cons_Seq.py @@ -0,0 +1,31 @@ +#Given an unsorted array of integers nums, +#return the length of the longest consecutive elements sequence. +from typing import List + +class Solution: + def longestConsecutive(self, nums: List[int]) -> int: + # Remove duplicates and sort the numbers + numbers = list(set(nums)) + numbers.sort() + + # Initialize previous number to negative infinity + prevN = float("-inf") + # Initialize counters for the longest streak and current streak + longest = curr = 0 + + # Iterate through each number in the sorted list + for n in numbers: + # If current number is consecutive to previous number + if n == prevN + 1: + curr += 1 # Increase current streak + prevN = n # Update previous number + else: + # If current streak is longer than longest, update longest + if curr > longest: + longest = curr + # Reset current streak to 1 for new sequence + curr = 1 + prevN = n # Update previous number + + # Return the maximum of longest streak and current streak + return longest if longest > curr else curr diff --git a/python/Longest_Increasing_Subsequence.py b/python/Longest_Increasing_Subsequence.py new file mode 100644 index 00000000..e69de29b diff --git a/python/Median_of_Two_Sorted_Arrays.py b/python/Median_of_Two_Sorted_Arrays.py new file mode 100644 index 00000000..867ac935 --- /dev/null +++ b/python/Median_of_Two_Sorted_Arrays.py @@ -0,0 +1,102 @@ +class Solution: + def findMedianSortedArrays(self, nums1, nums2): + if len(nums1) > len(nums2): + nums1, nums2 = nums2, nums1 + + m, n = len(nums1), len(nums2) + + left, right = 0, m + + while left <= right: + partition1 = (left + right) // 2 + + partition2 = (m + n + 1) // 2 - partition1 + + max_left1 = float('-inf') if partition1 == 0 else nums1[partition1 - 1] + max_left2 = float('-inf') if partition2 == 0 else nums2[partition2 - 1] + + min_right1 = float('inf') if partition1 == m else nums1[partition1] + min_right2 = float('inf') if partition2 == n else nums2[partition2] + + if max_left1 <= min_right2 and max_left2 <= min_right1: + if (m + n) % 2 == 0: + return (max(max_left1, max_left2) + min(min_right1, min_right2)) / 2.0 + else: + return max(max_left1, max_left2) + + elif max_left1 > min_right2: + right = partition1 - 1 + else: + left = partition1 + 1 + + raise ValueError("Input arrays are not sorted") + + def findMedianSortedArrays_bruteforce(self, nums1, nums2): + merged = [] + i = j = 0 + + while i < len(nums1) and j < len(nums2): + if nums1[i] <= nums2[j]: + merged.append(nums1[i]) + i += 1 + else: + merged.append(nums2[j]) + j += 1 + + while i < len(nums1): + merged.append(nums1[i]) + i += 1 + + while j < len(nums2): + merged.append(nums2[j]) + j += 1 + + n = len(merged) + if n % 2 == 0: + return (merged[n // 2 - 1] + merged[n // 2]) / 2.0 + else: + return merged[n // 2] + + +def test_solution(): + solution = Solution() + + test_cases = [ + ([1, 3], [2], 2.0), + ([1, 2], [3, 4], 2.5), + ([0, 0], [0, 0], 0.0), + ([], [1], 1.0), + ([2], [], 2.0), + ([1, 3, 8], [7, 9, 10, 11], 8.0), + ([1, 2, 3, 4], [5, 6, 7, 8], 4.5), + ([1], [2, 3, 4, 5, 6], 3.5) + ] + + print("Testing Median of Two Sorted Arrays:") + print("=" * 50) + + for i, (nums1, nums2, expected) in enumerate(test_cases, 1): + result = solution.findMedianSortedArrays(nums1, nums2) + status = "✓" if abs(result - expected) < 1e-5 else "✗" + + print(f"Test {i}: {status}") + print(f" Input: nums1 = {nums1}, nums2 = {nums2}") + print(f" Expected: {expected}") + print(f" Got: {result}") + print() + + print("\nVerifying with brute force approach:") + print("-" * 40) + + for i, (nums1, nums2, expected) in enumerate(test_cases[:5], 1): + optimal_result = solution.findMedianSortedArrays(nums1, nums2) + brute_result = solution.findMedianSortedArrays_bruteforce(nums1, nums2) + + match = abs(optimal_result - brute_result) < 1e-5 + status = "✓" if match else "✗" + + print(f"Test {i}: {status} Optimal: {optimal_result}, Brute: {brute_result}") + + +if __name__ == "__main__": + test_solution() \ No newline at end of file diff --git a/python/Minimum_arrows_to_burst_ballons.py b/python/Minimum_arrows_to_burst_ballons.py new file mode 100644 index 00000000..7eb6d031 --- /dev/null +++ b/python/Minimum_arrows_to_burst_ballons.py @@ -0,0 +1,29 @@ +from typing import List + +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + # Step 1: Sort balloons based on their end position + points.sort(key=lambda x: x[1]) + + # Step 2: Initialize first arrow position and counter + end = points[0][1] + arrows = 1 + + # Step 3: Traverse through all balloons + for start, finish in points: + if start > end: + # Need a new arrow if this balloon starts after last arrow's reach + arrows += 1 + end = finish + + return arrows + + +if __name__ == "__main__": + # Example test case + points = [[10, 16], [2, 8], [1, 6], [7, 12]] + + solution = Solution() + result = solution.findMinArrowShots(points) + + print("Minimum number of arrows needed:", result) diff --git a/python/Mirror Index Sum.py b/python/Mirror Index Sum.py new file mode 100644 index 00000000..4e6b0bb0 --- /dev/null +++ b/python/Mirror Index Sum.py @@ -0,0 +1,12 @@ +def mirror_index_sum(nums): + total = 0 + n = len(nums) + for i in range(n // 2 + n % 2): + if nums[i] == nums[n - 1 - i]: + total += nums[i] + return total + +# Example runs +print(mirror_index_sum([1, 3, 2, 3, 1])) # Output: 5 +print(mirror_index_sum([2, 5, 5, 2])) # Output: 4 +print(mirror_index_sum([4, 1, 7, 9])) # Output: 0 diff --git a/python/MovieRecommendation.py b/python/MovieRecommendation.py new file mode 100644 index 00000000..8e55e285 --- /dev/null +++ b/python/MovieRecommendation.py @@ -0,0 +1,62 @@ +# RandomForest is used for classification Problems and recommendation systems +import pandas as pd +from sklearn.preprocessing import LabelEncoder +from sklearn.model_selection import train_test_split +from sklearn.ensemble import RandomForestClassifier + +# Step 1: Create a sample dataset in a dictionary +# This data represents movies with their attributes. +data = { + 'ratings': [9, 2, 8, 3, 7, 4, 1, 5, 9, 2, 9, 8], + 'price': [250, 200, 150, 200, 300, 350, 250, 600, 450, 500, 300, 280], + 'watchTime': [2, 3, 2, 4, 2, 1, 2, 3, 2, 3, 2, 2.5], + 'genre': ["Action", "Comedy", "Sci-Fi", "Thriller", "Documentary", "Action", "Sci-Fi", "Romantic", "Comedy", "Suspense", "Horror", "Action"], + 'Suggested_Movie': ['The Dark Knight', 'Superbad', 'Blade Runner', 'The Silence of the Lambs', 'Planet Earth', 'John Wick', 'Arrival', 'The Notebook', 'Step Brothers', 'The Sixth Sense', 'The Conjuring', 'Mad Max: Fury Road'] +} +df = pd.DataFrame(data) + +# Step 2: Preprocess the data +# Machine learning models need numerical data, so we convert text (like genre) into numbers. + +# Encode the 'genre' feature +genre_encoder = LabelEncoder() +df['genre_encoded'] = genre_encoder.fit_transform(df['genre']) + +# Encode the 'Suggested_Movie' target variable +movie_encoder = LabelEncoder() +df['Movie_Label'] = movie_encoder.fit_transform(df['Suggested_Movie']) + +# Step 3: Define Features (X) and Target (Y) +# Features are the inputs used for prediction. +X = df[['ratings', 'price', 'watchTime', 'genre_encoded']] +# Target is the output we want to predict. +Y = df['Movie_Label'] + +# Step 4: Split data into training and testing sets +# We train the model on 80% of the data and test its performance on the remaining 20%. +X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=42) + +# Step 5: Train the RandomForest model +# The model learns the relationship between the features and the movie label. +model = RandomForestClassifier(n_estimators=100, random_state=42) +model.fit(X_train, y_train) + +# Step 6: Predict a movie for a new user +# Let's say a user wants an "Action" movie with a high rating. +# We must encode the user's genre preference ("Action") the same way we did for the training data. +try: + action_genre_code = genre_encoder.transform(["Action"])[0] + + # New user's preferences: [rating, price, watchTime, genre] + new_user_preferences = [[9, 300, 2.5, action_genre_code]] + + # Predict the movie label for the new user + predicted_label = model.predict(new_user_preferences) + + # Convert the predicted label back to the actual movie name + predicted_movie = movie_encoder.inverse_transform(predicted_label) + + print(f"Based on your preferences, we recommend: {predicted_movie[0]}") + +except ValueError: + print("The genre 'Action' was not found in the training data. Please choose from available genres.") diff --git a/python/N-Queens.py b/python/N-Queens.py new file mode 100644 index 00000000..f571ceba --- /dev/null +++ b/python/N-Queens.py @@ -0,0 +1,36 @@ +def solveNQueens(n): + col = set() + pos_diag = set() + neg_diag = set() + res = [] + board = [["."] * n for _ in range(n)] + + def backtrack(r): + if r == n: + res.append(["".join(row) for row in board]) + return + for c in range(n): + if c in col or (r + c) in pos_diag or (r - c) in neg_diag: + continue + col.add(c) + pos_diag.add(r + c) + neg_diag.add(r - c) + board[r][c] = "Q" + + backtrack(r + 1) + + col.remove(c) + pos_diag.remove(r + c) + neg_diag.remove(r - c) + board[r][c] = "." + + backtrack(0) + return res + +n = int(input("Enter the size of the board (n): ")) +solutions = solveNQueens(n) +print(len(solutions)) +for sol in solutions: + for row in sol: + print(row) + print() diff --git a/python/Palindrome_Check.py b/python/Palindrome_Check.py index b6253584..e69de29b 100644 --- a/python/Palindrome_Check.py +++ b/python/Palindrome_Check.py @@ -1,8 +0,0 @@ -#Palindrome Check - -def is_palindrome(s): - return s == s[::-1] - -# Example usage -word = "racecar" -print(word, "is palindrome?", is_palindrome(word)) # Output: True diff --git a/python/Prime Number.py b/python/Prime Number.py new file mode 100644 index 00000000..a057b3f9 --- /dev/null +++ b/python/Prime Number.py @@ -0,0 +1,10 @@ +n = 11 +if n <= 1: + print(False) +else: + is_prime = True # Flag variable + for i in range(2, int(n**0.5) + 1): + if n % i == 0: + is_prime = False + break + print(is_prime) \ No newline at end of file diff --git a/python/Range_Sum_Queries.py b/python/Range_Sum_Queries.py new file mode 100644 index 00000000..d3866bd3 --- /dev/null +++ b/python/Range_Sum_Queries.py @@ -0,0 +1,15 @@ +def range_sum_brute_force(nums, queries): + results = [] + for l, r in queries: # loop over each query + current_sum = 0 + for i in range(l, r + 1): # inner loop over the range + current_sum += nums[i] + results.append(current_sum) + return results + + +# Example usage +nums = [1, 2, 3, 4, 5] # array +queries = [(0, 2), (1, 3), (2, 4)] # (l, r) ranges + +print(range_sum_brute_force(nums, queries)) diff --git a/python/RemoveDuplicate.py b/python/RemoveDuplicate.py new file mode 100644 index 00000000..7f1a65bd --- /dev/null +++ b/python/RemoveDuplicate.py @@ -0,0 +1,8 @@ +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + l=1 + for r in range (1,len(nums)): + if nums[r] != nums[r-1]: + nums[l]=nums[r] + l += 1 + return l \ No newline at end of file diff --git a/python/Reverse_String.py b/python/Reverse_String.py new file mode 100644 index 00000000..ceb9a1f7 --- /dev/null +++ b/python/Reverse_String.py @@ -0,0 +1,3 @@ +s=input() +revs= s[::-1] +print(revs) diff --git a/python/STRING.py b/python/STRING.py new file mode 100644 index 00000000..cc8cfa33 --- /dev/null +++ b/python/STRING.py @@ -0,0 +1,7 @@ +# Problem: A phrase is a palindrome if it reads the same forward and backward after removing non-alphanumeric characters. + +def isPalindrome(s: str) -> bool: + s = ''.join(ch.lower() for ch in s if ch.isalnum()) + return s == s[::-1] + +print(isPalindrome("A man, a plan, a canal: Panama")) # True diff --git a/python/Save_People.py b/python/Save_People.py new file mode 100644 index 00000000..e69de29b diff --git a/python/SetMatrixZeros.py b/python/SetMatrixZeros.py new file mode 100644 index 00000000..85e40e71 --- /dev/null +++ b/python/SetMatrixZeros.py @@ -0,0 +1,17 @@ +class Solution: + def setZeroes(self, matrix: List[List[int]]) -> None: + r=len(matrix) + c=len(matrix[0]) + rowtrack=[0 for _ in range (r)] + coltrack=[0 for _ in range (c)] + for i in range (0,r): + for j in range (0,c): + if matrix[i][j]==0: + rowtrack[i]=-1 + coltrack[j]=-1 + for i in range (0,r): + for j in range (0,c): + if rowtrack[i]==-1 or coltrack[j]==-1: + matrix[i][j]=0 + + diff --git a/python/Shortest Distance to a Character b/python/Shortest Distance to a Character new file mode 100644 index 00000000..815f788a --- /dev/null +++ b/python/Shortest Distance to a Character @@ -0,0 +1,20 @@ +class Solution(object): + def shortestToChar(self, s, c): + list1 = [] + index = -1 + for i in range(len(s)): + if s[i] == c: + index = i + if index != -1: + value = abs(index - i) + list1.append(value) + else: + list1.append(len(s)) + index = -1 + for i in range(len(s)-1, -1, -1): + if s[i] ==c: + index = i + if index != -1: + value = abs(index - i) + list1[i] = min(list1[i], value) + return list1 diff --git a/python/SpaceBlasterX.py b/python/SpaceBlasterX.py new file mode 100644 index 00000000..2fea3457 --- /dev/null +++ b/python/SpaceBlasterX.py @@ -0,0 +1,130 @@ +import pygame, random, sys +pygame.init() + +# --- Screen setup --- +WIDTH, HEIGHT = 800, 600 +screen = pygame.display.set_mode((WIDTH, HEIGHT)) +pygame.display.set_caption("🚀 Space Blaster X") + +# --- Colors --- +WHITE = (255, 255, 255) +RED = (255, 0, 0) +YELLOW = (255, 255, 0) +BLACK = (0, 0, 0) + +# --- Assets --- +font = pygame.font.SysFont("Arial", 30, bold=True) +clock = pygame.time.Clock() + +# --- Classes --- +class Player(pygame.sprite.Sprite): + def __init__(self): + super().__init__() + self.image = pygame.Surface((50, 40)) + self.image.fill(YELLOW) + self.rect = self.image.get_rect(center=(WIDTH//2, HEIGHT - 50)) + self.speed = 7 + + def update(self, keys): + if keys[pygame.K_LEFT] and self.rect.left > 0: + self.rect.x -= self.speed + if keys[pygame.K_RIGHT] and self.rect.right < WIDTH: + self.rect.x += self.speed + + def shoot(self): + bullet = Bullet(self.rect.centerx, self.rect.top) + all_sprites.add(bullet) + bullets.add(bullet) + + +class Enemy(pygame.sprite.Sprite): + def __init__(self): + super().__init__() + self.image = pygame.Surface((40, 40)) + self.image.fill(RED) + self.rect = self.image.get_rect(center=(random.randint(20, WIDTH-20), -40)) + self.speed = random.randint(2, 6) + + def update(self, keys): + self.rect.y += self.speed + if self.rect.top > HEIGHT: + self.kill() + + +class Bullet(pygame.sprite.Sprite): + def __init__(self, x, y): + super().__init__() + self.image = pygame.Surface((6, 20)) + self.image.fill(WHITE) + self.rect = self.image.get_rect(center=(x, y)) + self.speed = -10 + + def update(self, keys): + self.rect.y += self.speed + if self.rect.bottom < 0: + self.kill() + + +# --- Groups --- +all_sprites = pygame.sprite.Group() +enemies = pygame.sprite.Group() +bullets = pygame.sprite.Group() + +player = Player() +all_sprites.add(player) + +score = 0 +enemy_spawn_timer = 0 +game_over = False + +# --- Main Loop --- +while True: + keys = pygame.key.get_pressed() + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + if not game_over and event.type == pygame.KEYDOWN: + if event.key == pygame.K_SPACE: + player.shoot() + if game_over and event.type == pygame.KEYDOWN and event.key == pygame.K_r: + # restart + all_sprites.empty() + enemies.empty() + bullets.empty() + player = Player() + all_sprites.add(player) + score = 0 + game_over = False + + if not game_over: + # Spawn enemies + enemy_spawn_timer += 1 + if enemy_spawn_timer > 30: + enemy_spawn_timer = 0 + enemy = Enemy() + all_sprites.add(enemy) + enemies.add(enemy) + + # Update sprites + all_sprites.update(keys) + + # Collision detection + hits = pygame.sprite.groupcollide(enemies, bullets, True, True) + score += len(hits) * 10 + + if pygame.sprite.spritecollideany(player, enemies): + game_over = True + + # --- Drawing --- + screen.fill(BLACK) + all_sprites.draw(screen) + score_text = font.render(f"Score: {score}", True, WHITE) + screen.blit(score_text, (10, 10)) + + if game_over: + over_text = font.render("GAME OVER! Press 'R' to Restart", True, RED) + screen.blit(over_text, (WIDTH//2 - 200, HEIGHT//2)) + + pygame.display.flip() + clock.tick(60) diff --git a/python/Stack-valid_parantheses.py b/python/Stack-valid_parantheses.py new file mode 100644 index 00000000..1a5a099a --- /dev/null +++ b/python/Stack-valid_parantheses.py @@ -0,0 +1,15 @@ +# Problem: Check if parentheses are valid. + +def isValid(s: str) -> bool: + stack = [] + mapping = {")":"(", "}":"{", "]":"["} + for char in s: + if char in mapping: + top = stack.pop() if stack else "#" + if mapping[char] != top: + return False + else: + stack.append(char) + return not stack + +print(isValid("()[]{}")) # True diff --git a/python/Stack.py b/python/Stack.py new file mode 100644 index 00000000..ba42c5a4 --- /dev/null +++ b/python/Stack.py @@ -0,0 +1,17 @@ +# Stack implementation using list + +stack = [] + +# Push elements +stack.append(10) +stack.append(20) +stack.append(30) +print("Stack after pushes:", stack) + +# Pop element +popped = stack.pop() +print("Popped element:", popped) +print("Stack after pop:", stack) + +# Peek top element +print("Top element:", stack[-1]) diff --git a/python/Sudoku Solver using Backtracking.py b/python/Sudoku Solver using Backtracking.py new file mode 100644 index 00000000..fcd73144 --- /dev/null +++ b/python/Sudoku Solver using Backtracking.py @@ -0,0 +1,83 @@ +# Sudoku Solver using Backtracking + +# Function to print the Sudoku board +def print_board(board): + for i in range(len(board)): + if i % 3 == 0 and i != 0: + print("- - - - - - - - - - - -") + for j in range(len(board[0])): + if j % 3 == 0 and j != 0: + print(" | ", end="") + if j == 8: + print(board[i][j]) + else: + print(str(board[i][j]) + " ", end="") + +# Find the next empty cell +def find_empty(board): + for i in range(len(board)): + for j in range(len(board[0])): + if board[i][j] == 0: + return (i, j) # row, col + return None + +# Check if a number can be placed at (row, col) +def valid(board, num, pos): + row, col = pos + + # Check row + for j in range(len(board[0])): + if board[row][j] == num and j != col: + return False + + # Check column + for i in range(len(board)): + if board[i][col] == num and i != row: + return False + + # Check 3x3 box + box_x = col // 3 + box_y = row // 3 + for i in range(box_y * 3, box_y * 3 + 3): + for j in range(box_x * 3, box_x * 3 + 3): + if board[i][j] == num and (i, j) != pos: + return False + + return True + +# Recursive backtracking solver +def solve(board): + empty = find_empty(board) + if not empty: + return True # Puzzle solved + else: + row, col = empty + + for num in range(1, 10): + if valid(board, num, (row, col)): + board[row][col] = num + if solve(board): + return True + board[row][col] = 0 # Backtrack + + return False + + +# Example Sudoku puzzle (0 = empty) +board = [ + [7, 8, 0, 4, 0, 0, 1, 2, 0], + [6, 0, 0, 0, 7, 5, 0, 0, 9], + [0, 0, 0, 6, 0, 1, 0, 7, 8], + [0, 0, 7, 0, 4, 0, 2, 6, 0], + [0, 0, 1, 0, 5, 0, 9, 3, 0], + [9, 0, 4, 0, 6, 0, 0, 0, 5], + [0, 7, 0, 3, 0, 0, 0, 1, 2], + [1, 2, 0, 0, 0, 7, 4, 0, 0], + [0, 4, 9, 2, 0, 6, 0, 0, 7] +] + +print("Original Sudoku:") +print_board(board) +solve(board) +print("\nSolved Sudoku:") +print_board(board) diff --git a/python/Sum_of_Even_Fibonacci_numbers.py b/python/Sum_of_Even_Fibonacci_numbers.py new file mode 100644 index 00000000..dd69dd04 --- /dev/null +++ b/python/Sum_of_Even_Fibonacci_numbers.py @@ -0,0 +1,21 @@ + +a = 0 +b = 1 +c = 0 +i = 0 +arr = [] +while True: + c = a + b + a = b + b = c + i += 1 + if c > 4000000: + break + if c % 2 == 0: + arr.append(c) +sum_1 = 0 +for i in range(len(arr)): + sum_1 += int(arr[i]) + +print(len(arr)) +print(sum_1) diff --git a/python/Sum_of_Unique_Elements.py b/python/Sum_of_Unique_Elements.py new file mode 100644 index 00000000..92875d6f --- /dev/null +++ b/python/Sum_of_Unique_Elements.py @@ -0,0 +1,19 @@ +# Sum_of_Unique_Elements.py + +def sumOfUnique(nums): + freq = {} + for n in nums: + freq[n] = freq.get(n, 0) + 1 + + total = 0 + for key, val in freq.items(): + if val == 1: + total += key + return total + + +# Example usage +if __name__ == "__main__": + arr = [1, 2, 3, 2] + print("Input:", arr) + print("Sum of Unique Elements:", sumOfUnique(arr)) diff --git a/python/Trie.py b/python/Trie.py new file mode 100644 index 00000000..34d9b169 --- /dev/null +++ b/python/Trie.py @@ -0,0 +1,113 @@ +# ------------------------------------------------------------ +# Data Structure: Trie (Prefix Tree) +# Difficulty: Medium +# Source: Standard Data Structure +# ------------------------------------------------------------ +# Statement: +# Implement a Trie (Prefix Tree) with the following methods: +# - `insert(word)`: Inserts a word into the trie. +# - `search(word)`: Returns `True` if the word is in the trie. +# - `startsWith(prefix)`: Returns `True` if there is any word in the +# trie that starts with the given prefix. +# +# A Trie is a tree-like data structure that stores a dynamic set of +# strings. It is commonly used for efficient retrieval of keys in a dataset +# of strings, such as autocomplete features or spell checkers. +# +# ------------------------------------------------------------ + +class TrieNode: + """A node in the Trie structure.""" + def __init__(self): + # `children` is a dictionary mapping a character to a TrieNode. + self.children = {} + # `is_end_of_word` is True if the node represents the end of a word. + self.is_end_of_word = False + +class Trie: + """ + Trie (Prefix Tree) implementation. + + Approach: + The Trie is built from a root node. Each node has a dictionary of children + and a boolean flag to mark the end of a word. + + - `insert`: Traverse the trie character by character. If a character's + node doesn't exist, create it. Mark the final node as the end of a word. + Time Complexity: O(L), where L is the length of the word. + Space Complexity: O(L) in the worst case (for a new word). + + - `search`: Traverse the trie. If any character is not found, the word + doesn't exist. If the traversal completes, check if the final node + is marked as the end of a word. + Time Complexity: O(L). + Space Complexity: O(1). + + - `startsWith`: Traverse the trie. If any character in the prefix is not + found, no word starts with it. If traversal completes, the prefix exists. + Time Complexity: O(P), where P is the length of the prefix. + Space Complexity: O(1). + """ + def __init__(self): + """Initializes the trie structure.""" + self.root = TrieNode() + + def insert(self, word: str) -> None: + """Inserts a word into the trie.""" + node = self.root + for char in word: + if char not in node.children: + node.children[char] = TrieNode() + node = node.children[char] + node.is_end_of_word = True + + def search(self, word: str) -> bool: + """Returns True if the word is in the trie.""" + node = self.root + for char in word: + if char not in node.children: + return False + node = node.children[char] + return node.is_end_of_word + + def startsWith(self, prefix: str) -> bool: + """Returns True if there is any word in the trie that starts with the given prefix.""" + node = self.root + for char in prefix: + if char not in node.children: + return False + node = node.children[char] + return True + +# ------------------------------------------------------------ +# Driver Code for Testing +# ------------------------------------------------------------ +if __name__ == "__main__": + trie = Trie() + + # --- Insert words --- + words_to_insert = ["apple", "app", "apricot", "banana", "bandana"] + for word in words_to_insert: + trie.insert(word) + print(f"Inserted words: {words_to_insert}\n") + + # --- Test search() method --- + print("--- Testing search() ---") + print(f"Search 'apple': {trie.search('apple')}") # Expected: True + print(f"Search 'app': {trie.search('app')}") # Expected: True + print(f"Search 'appl': {trie.search('appl')}") # Expected: False + print(f"Search 'banana': {trie.search('banana')}") # Expected: True + print(f"Search 'ban': {trie.search('ban')}") # Expected: False + print(f"Search 'bandanas': {trie.search('bandanas')}") # Expected: False + print("-" * 20) + + # --- Test startsWith() method --- + print("--- Testing startsWith() ---") + print(f"Starts with 'app': {trie.startsWith('app')}") # Expected: True + print(f"Starts with 'apri': {trie.startsWith('apri')}") # Expected: True + print(f"Starts with 'ban': {trie.startsWith('ban')}") # Expected: True + print(f"Starts with 'bana': {trie.startsWith('bana')}") # Expected: True + print(f"Starts with 'band': {trie.startsWith('band')}") # Expected: True + print(f"Starts with 'cat': {trie.startsWith('cat')}") # Expected: False + print(f"Starts with 'applepie': {trie.startsWith('applepie')}") # Expected: False + print("-" * 20) diff --git a/python/Two_Pointers_technique.py b/python/Two_Pointers_technique.py new file mode 100644 index 00000000..81ff58a6 --- /dev/null +++ b/python/Two_Pointers_technique.py @@ -0,0 +1,24 @@ +def has_pair_with_sum(arr, target): + # Ensure the array is sorted for two-pointer technique + arr.sort() + + i, j = 0, len(arr) - 1 # Initialize two pointers + + while i < j: + current_sum = arr[i] + arr[j] + + if current_sum == target: + return True + elif current_sum < target: + i += 1 # Move the left pointer forward + else: + j -= 1 # Move the right pointer backward + + return False # No pair found + + +# Example usage +arr = [10, 2, 5, 7, 3] +target = 12 + +print(has_pair_with_sum(arr, target)) # ✅ True (because 5 + 7 = 12) diff --git a/python/UniquePath_Backtracking.py b/python/UniquePath_Backtracking.py new file mode 100644 index 00000000..6f974728 --- /dev/null +++ b/python/UniquePath_Backtracking.py @@ -0,0 +1,99 @@ +import ast + +class Solution: + def uniquePathsIII(self, grid): + rows, cols = len(grid), len(grid[0]) + empty = 0 + start_x = start_y = -1 + + # Find start and count empty cells + for i in range(rows): + for j in range(cols): + if grid[i][j] == 0: + empty += 1 + elif grid[i][j] == 1: + start_x, start_y = i, j + + if start_x == -1: + raise ValueError("Start cell (1) not found in grid.") + + path_count = [0] # store total found paths by reference + + def dfs(x, y, remain, path): + # Out of bounds or obstacle + if not (0 <= x < rows and 0 <= y < cols) or grid[x][y] == -1: + return 0 + + # If reached end + if grid[x][y] == 2: + if remain == -1: + path_count[0] += 1 + print(f"✅ Path {path_count[0]} found: {path + [(x, y)]}") + return 1 + else: + print(f"❌ Reached end too early at {x,y}, remain={remain}") + return 0 + + # Mark visited + temp = grid[x][y] + grid[x][y] = -1 + path.append((x, y)) + print(f"➡️ Visiting {x,y}, remain={remain}") + + total = 0 + for dx, dy in ((1,0), (-1,0), (0,1), (0,-1)): + total += dfs(x+dx, y+dy, remain-1, path) + + # Backtrack + grid[x][y] = temp + last = path.pop() + print(f"🔙 Backtracking from {last}") + + return total + + total_paths = dfs(start_x, start_y, empty, []) + print(f"\n🌟 Total valid paths: {total_paths}") + return total_paths + + +def read_grid_choice(): + print("Choose input method:") + print("1) Paste Python list-of-lists (e.g. [[1,0,0,0],[0,0,0,0],[0,0,2,-1]])") + print("2) Enter rows and cols, then enter each row (space or comma separated numbers)") + choice = input("Choice (1 or 2): ").strip() + + if choice == '1': + print("Paste the grid now. End with an empty line and press 2 times enter:") + lines = [] + while True: + try: + line = input() + except EOFError: + break + if line.strip() == "": + break + lines.append(line) + grid = ast.literal_eval(" ".join(lines)) + return grid + + elif choice == '2': + r, c = map(int, input("Enter rows and cols: ").split()) + print(f"Enter {r} rows, each with {c} integers:") + grid = [] + for i in range(r): + row = list(map(int, input(f"Row {i+1}: ").replace(',', ' ').split())) + grid.append(row) + return grid + else: + raise ValueError("Invalid choice") + + +if __name__ == "__main__": + grid = read_grid_choice() + print("\nYour grid:") + for row in grid: + print(row) + print() + + sol = Solution() + sol.uniquePathsIII(grid) diff --git a/python/Unique_Paths.py b/python/Unique_Paths.py new file mode 100644 index 00000000..e69de29b diff --git a/python/__pycache__/palindrome_pattern.cpython-313.pyc b/python/__pycache__/palindrome_pattern.cpython-313.pyc new file mode 100644 index 00000000..163969d9 Binary files /dev/null and b/python/__pycache__/palindrome_pattern.cpython-313.pyc differ diff --git a/python/add_and_subtract_nodes_in_linked_list.py b/python/add_and_subtract_nodes_in_linked_list.py new file mode 100644 index 00000000..48ae72b9 --- /dev/null +++ b/python/add_and_subtract_nodes_in_linked_list.py @@ -0,0 +1,50 @@ +# Node class +class Node: + def __init__(self, data): + self.data = data + self.next = None + +# Linked List class +class LinkedList: + def __init__(self): + self.head = None + + # Add a new node at the end + def add(self, data): + new_node = Node(data) + if not self.head: + self.head = new_node + return + current = self.head + while current.next: + current = current.next + current.next = new_node + + # Subtract a value from each node + def subtract(self, value): + current = self.head + while current: + current.data -= value + current = current.next + + # Print the linked list + def print_list(self): + current = self.head + while current: + print(current.data, end=" -> ") + current = current.next + print("None") + + +# Example usage +ll = LinkedList() +ll.add(10) +ll.add(20) +ll.add(30) + +print("Original Linked List:") +ll.print_list() + +ll.subtract(5) +print("After subtracting 5 from each node:") +ll.print_list() diff --git a/python/addtwonumbers.py b/python/addtwonumbers.py new file mode 100644 index 00000000..8fbba127 --- /dev/null +++ b/python/addtwonumbers.py @@ -0,0 +1,10 @@ +# This program adds two numbers + +num1 = 1.5 +num2 = 6.3 + +# Add two numbers +sum = num1 + num2 + +# Display the sum +print('The sum of {0} and {1} is {2}'.format(num1, num2, sum)) diff --git a/python/advanced_binary_search_tree.py b/python/advanced_binary_search_tree.py new file mode 100644 index 00000000..50c3445b --- /dev/null +++ b/python/advanced_binary_search_tree.py @@ -0,0 +1,531 @@ +""" +Advanced Binary Search Tree Implementation + +This module provides a comprehensive BST implementation with advanced operations +including deletion, validation, balancing, and various tree analysis methods. + +Features: +- Complete CRUD operations (Create, Read, Update, Delete) +- Tree validation and balancing +- Multiple traversal methods +- Tree statistics and analysis +- Visualization support + +Time Complexities: +- Search/Insert/Delete: O(log n) average, O(n) worst case +- Traversals: O(n) +- Validation: O(n) + +Author: Hacktoberfest Contributor +Date: October 2024 +""" + +from typing import Optional, List, Any +import math +from collections import deque + + +class TreeNode: + """Binary Search Tree Node""" + + def __init__(self, val: int = 0): + self.val = val + self.left: Optional['TreeNode'] = None + self.right: Optional['TreeNode'] = None + self.count = 1 # For handling duplicates + + def __str__(self): + return f"TreeNode({self.val})" + + def __repr__(self): + return self.__str__() + + +class AdvancedBST: + """Advanced Binary Search Tree with comprehensive operations""" + + def __init__(self): + self.root: Optional[TreeNode] = None + self.size = 0 + + def insert(self, val: int) -> None: + """Insert a value into the BST""" + if not self.root: + self.root = TreeNode(val) + self.size = 1 + return + + self._insert_recursive(self.root, val) + + def _insert_recursive(self, node: TreeNode, val: int) -> TreeNode: + """Helper method for recursive insertion""" + if val < node.val: + if node.left is None: + node.left = TreeNode(val) + self.size += 1 + else: + self._insert_recursive(node.left, val) + elif val > node.val: + if node.right is None: + node.right = TreeNode(val) + self.size += 1 + else: + self._insert_recursive(node.right, val) + else: + # Handle duplicates by incrementing count + node.count += 1 + + return node + + def search(self, val: int) -> Optional[TreeNode]: + """Search for a value in the BST""" + return self._search_recursive(self.root, val) + + def _search_recursive(self, node: Optional[TreeNode], val: int) -> Optional[TreeNode]: + """Helper method for recursive search""" + if not node or node.val == val: + return node + + if val < node.val: + return self._search_recursive(node.left, val) + else: + return self._search_recursive(node.right, val) + + def delete(self, val: int) -> bool: + """Delete a value from the BST""" + self.root, deleted = self._delete_recursive(self.root, val) + if deleted: + self.size -= 1 + return deleted + + def _delete_recursive(self, node: Optional[TreeNode], val: int) -> tuple[Optional[TreeNode], bool]: + """Helper method for recursive deletion""" + if not node: + return None, False + + deleted = False + + if val < node.val: + node.left, deleted = self._delete_recursive(node.left, val) + elif val > node.val: + node.right, deleted = self._delete_recursive(node.right, val) + else: + # Found the node to delete + if node.count > 1: + # Handle duplicates + node.count -= 1 + return node, True + + # Node has no children + if not node.left and not node.right: + return None, True + + # Node has one child + if not node.left: + return node.right, True + if not node.right: + return node.left, True + + # Node has two children - find inorder successor + successor = self._find_min(node.right) + node.val = successor.val + node.count = successor.count + successor.count = 1 # Avoid double decrement + node.right, _ = self._delete_recursive(node.right, successor.val) + deleted = True + + return node, deleted + + def _find_min(self, node: TreeNode) -> TreeNode: + """Find the minimum value node in a subtree""" + while node.left: + node = node.left + return node + + def _find_max(self, node: TreeNode) -> TreeNode: + """Find the maximum value node in a subtree""" + while node.right: + node = node.right + return node + + # Traversal Methods + def inorder_traversal(self) -> List[int]: + """Inorder traversal (left, root, right) - gives sorted order""" + result = [] + self._inorder_recursive(self.root, result) + return result + + def _inorder_recursive(self, node: Optional[TreeNode], result: List[int]) -> None: + """Helper for inorder traversal""" + if node: + self._inorder_recursive(node.left, result) + result.extend([node.val] * node.count) + self._inorder_recursive(node.right, result) + + def preorder_traversal(self) -> List[int]: + """Preorder traversal (root, left, right)""" + result = [] + self._preorder_recursive(self.root, result) + return result + + def _preorder_recursive(self, node: Optional[TreeNode], result: List[int]) -> None: + """Helper for preorder traversal""" + if node: + result.extend([node.val] * node.count) + self._preorder_recursive(node.left, result) + self._preorder_recursive(node.right, result) + + def postorder_traversal(self) -> List[int]: + """Postorder traversal (left, right, root)""" + result = [] + self._postorder_recursive(self.root, result) + return result + + def _postorder_recursive(self, node: Optional[TreeNode], result: List[int]) -> None: + """Helper for postorder traversal""" + if node: + self._postorder_recursive(node.left, result) + self._postorder_recursive(node.right, result) + result.extend([node.val] * node.count) + + def level_order_traversal(self) -> List[List[int]]: + """Level order traversal (breadth-first)""" + if not self.root: + return [] + + result = [] + queue = deque([self.root]) + + while queue: + level_size = len(queue) + level_values = [] + + for _ in range(level_size): + node = queue.popleft() + level_values.extend([node.val] * node.count) + + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + result.append(level_values) + + return result + + # Tree Analysis Methods + def height(self) -> int: + """Calculate the height of the tree""" + return self._height_recursive(self.root) + + def _height_recursive(self, node: Optional[TreeNode]) -> int: + """Helper for height calculation""" + if not node: + return -1 # Height of empty tree is -1 + return 1 + max(self._height_recursive(node.left), + self._height_recursive(node.right)) + + def is_valid_bst(self) -> bool: + """Validate if the tree maintains BST property""" + return self._validate_bst(self.root, float('-inf'), float('inf')) + + def _validate_bst(self, node: Optional[TreeNode], min_val: float, max_val: float) -> bool: + """Helper for BST validation""" + if not node: + return True + + if node.val <= min_val or node.val >= max_val: + return False + + return (self._validate_bst(node.left, min_val, node.val) and + self._validate_bst(node.right, node.val, max_val)) + + def is_balanced(self) -> bool: + """Check if the tree is height-balanced""" + def check_balance(node: Optional[TreeNode]) -> tuple[bool, int]: + if not node: + return True, -1 + + left_balanced, left_height = check_balance(node.left) + if not left_balanced: + return False, 0 + + right_balanced, right_height = check_balance(node.right) + if not right_balanced: + return False, 0 + + balanced = abs(left_height - right_height) <= 1 + height = 1 + max(left_height, right_height) + + return balanced, height + + balanced, _ = check_balance(self.root) + return balanced + + def get_range(self, low: int, high: int) -> List[int]: + """Get all values in the given range [low, high]""" + result = [] + self._range_search(self.root, low, high, result) + return result + + def _range_search(self, node: Optional[TreeNode], low: int, high: int, result: List[int]) -> None: + """Helper for range search""" + if not node: + return + + if low <= node.val <= high: + result.extend([node.val] * node.count) + + if node.val > low: + self._range_search(node.left, low, high, result) + + if node.val < high: + self._range_search(node.right, low, high, result) + + def kth_smallest(self, k: int) -> Optional[int]: + """Find the kth smallest element""" + count = [0] + return self._kth_smallest_helper(self.root, k, count) + + def _kth_smallest_helper(self, node: Optional[TreeNode], k: int, count: List[int]) -> Optional[int]: + """Helper for kth smallest""" + if not node: + return None + + # Search in left subtree first + left_result = self._kth_smallest_helper(node.left, k, count) + if left_result is not None: + return left_result + + # Process current node + count[0] += node.count + if count[0] >= k: + return node.val + + # Search in right subtree + return self._kth_smallest_helper(node.right, k, count) + + def path_to_node(self, val: int) -> List[int]: + """Find the path from root to a given value""" + path = [] + self._find_path(self.root, val, path) + return path if path and path[-1] == val else [] + + def _find_path(self, node: Optional[TreeNode], val: int, path: List[int]) -> bool: + """Helper for finding path""" + if not node: + return False + + path.append(node.val) + + if node.val == val: + return True + + if (node.val > val and self._find_path(node.left, val, path)) or \ + (node.val < val and self._find_path(node.right, val, path)): + return True + + path.pop() + return False + + def lowest_common_ancestor(self, val1: int, val2: int) -> Optional[int]: + """Find the lowest common ancestor of two values""" + if not self.search(val1) or not self.search(val2): + return None + + return self._lca_recursive(self.root, val1, val2).val + + def _lca_recursive(self, node: TreeNode, val1: int, val2: int) -> TreeNode: + """Helper for LCA""" + if val1 < node.val and val2 < node.val: + return self._lca_recursive(node.left, val1, val2) + elif val1 > node.val and val2 > node.val: + return self._lca_recursive(node.right, val1, val2) + else: + return node + + # Tree Statistics + def get_statistics(self) -> dict: + """Get comprehensive tree statistics""" + if not self.root: + return {"size": 0, "height": -1, "balanced": True, "valid_bst": True} + + return { + "size": self.size, + "height": self.height(), + "balanced": self.is_balanced(), + "valid_bst": self.is_valid_bst(), + "min_value": self._find_min(self.root).val, + "max_value": self._find_max(self.root).val, + "leaf_count": self._count_leaves(self.root), + "internal_nodes": self.size - self._count_leaves(self.root) + } + + def _count_leaves(self, node: Optional[TreeNode]) -> int: + """Count leaf nodes""" + if not node: + return 0 + if not node.left and not node.right: + return 1 + return self._count_leaves(node.left) + self._count_leaves(node.right) + + # Tree Visualization + def print_tree(self) -> None: + """Print a visual representation of the tree""" + if not self.root: + print("Empty tree") + return + + lines, *_ = self._display_aux(self.root) + for line in lines: + print(line) + + def _display_aux(self, node: Optional[TreeNode]) -> tuple[List[str], int, int, int]: + """Auxiliary function for tree visualization""" + if not node: + return [], 0, 0, 0 + + line1 = [] + line2 = [] + + if not node.right and not node.left: + width = len(str(node.val)) + height = 1 + middle = width // 2 + return [str(node.val)], width, height, middle + + if not node.right: + lines, n, p, x = self._display_aux(node.left) + s = str(node.val) + u = len(s) + first_line = s + x * ' ' + (n - x) * ' ' + second_line = (u + x) * ' ' + '\\' + (n - x - 1) * ' ' + shifted_lines = [u * ' ' + line for line in lines] + return [first_line, second_line] + shifted_lines, n + u, p + 2, u // 2 + + if not node.left: + lines, n, p, x = self._display_aux(node.right) + s = str(node.val) + u = len(s) + first_line = (x + 1) * ' ' + s + second_line = x * ' ' + '/' + (u + n - x - 1) * ' ' + shifted_lines = [(x + u) * ' ' + line for line in lines] + return [first_line, second_line] + shifted_lines, x + u + n, p + 2, x + u // 2 + + left, n, p, x = self._display_aux(node.left) + right, m, q, y = self._display_aux(node.right) + s = str(node.val) + u = len(s) + first_line = (x + 1) * ' ' + (n - x - 1) * '_' + s + y * '_' + (m - y) * ' ' + second_line = x * ' ' + '/' + (n - x - 1 + u + y) * ' ' + '\\' + (m - y - 1) * ' ' + + if p < q: + left += [n * ' '] * (q - p) + elif q < p: + right += [m * ' '] * (p - q) + + zipped_lines = zip(left, right) + lines = [first_line, second_line] + [a + u * ' ' + b for a, b in zipped_lines] + return lines, n + m + u, max(p, q) + 2, n + u // 2 + + +def demonstrate_advanced_bst(): + """Comprehensive demonstration of BST operations""" + print("🌳 ADVANCED BINARY SEARCH TREE DEMONSTRATION") + print("=" * 50) + + # Create BST and insert values + bst = AdvancedBST() + values = [50, 30, 70, 20, 40, 60, 80, 10, 25, 35, 45] + + print("\n1. Building BST:") + for val in values: + bst.insert(val) + print(f"Inserted {val}") + + print(f"\nTree structure:") + bst.print_tree() + + # Basic operations + print(f"\n2. Basic Operations:") + print(f"Tree size: {bst.size}") + print(f"Search 40: {bst.search(40)}") + print(f"Search 99: {bst.search(99)}") + + # Traversals + print(f"\n3. Traversals:") + print(f"Inorder (sorted): {bst.inorder_traversal()}") + print(f"Preorder: {bst.preorder_traversal()}") + print(f"Postorder: {bst.postorder_traversal()}") + print(f"Level order: {bst.level_order_traversal()}") + + # Advanced operations + print(f"\n4. Advanced Operations:") + print(f"Height: {bst.height()}") + print(f"Is valid BST: {bst.is_valid_bst()}") + print(f"Is balanced: {bst.is_balanced()}") + print(f"Range [30, 60]: {bst.get_range(30, 60)}") + print(f"3rd smallest: {bst.kth_smallest(3)}") + print(f"Path to 45: {bst.path_to_node(45)}") + print(f"LCA of 25 and 45: {bst.lowest_common_ancestor(25, 45)}") + + # Tree statistics + print(f"\n5. Tree Statistics:") + stats = bst.get_statistics() + for key, value in stats.items(): + print(f"{key}: {value}") + + # Deletion demonstration + print(f"\n6. Deletion Operations:") + print(f"Before deletion: {bst.inorder_traversal()}") + + bst.delete(20) # Delete leaf + print(f"After deleting 20 (leaf): {bst.inorder_traversal()}") + + bst.delete(30) # Delete node with two children + print(f"After deleting 30 (two children): {bst.inorder_traversal()}") + + print(f"\nFinal tree structure:") + bst.print_tree() + + +if __name__ == "__main__": + demonstrate_advanced_bst() + + # Interactive demo + print(f"\n{'='*50}") + print("🎯 Perfect for Hacktoberfest 2024!") + print("This implementation includes:") + print("✅ Complete CRUD operations") + print("✅ Advanced BST algorithms") + print("✅ Tree analysis and validation") + print("✅ Multiple traversal methods") + print("✅ Statistical analysis") + print("✅ Tree visualization") + print("Happy coding! 🚀") + + +# Example usage for testing +""" +# Create and use the BST +bst = AdvancedBST() + +# Insert values +for val in [50, 30, 70, 20, 40, 60, 80]: + bst.insert(val) + +# Basic operations +print(bst.inorder_traversal()) # [20, 30, 40, 50, 60, 70, 80] +print(bst.search(40)) # TreeNode(40) +print(bst.height()) # 2 +print(bst.is_balanced()) # True + +# Advanced operations +print(bst.kth_smallest(3)) # 40 +print(bst.get_range(35, 65)) # [40, 50, 60] +print(bst.lowest_common_ancestor(20, 40)) # 30 + +# Delete operations +bst.delete(20) +print(bst.inorder_traversal()) # [30, 40, 50, 60, 70, 80] +""" \ No newline at end of file diff --git a/python/advanced_sorting.py b/python/advanced_sorting.py new file mode 100644 index 00000000..4e2ec5ef --- /dev/null +++ b/python/advanced_sorting.py @@ -0,0 +1,306 @@ +def counting_sort(arr, exp=1): + """ + Counting sort for a specific digit position + Used as a subroutine in radix sort + """ + n = len(arr) + output = [0] * n + count = [0] * 10 # For digits 0-9 + + # Count occurrences of each digit + for i in range(n): + index = (arr[i] // exp) % 10 + count[index] += 1 + + # Change count[i] to actual position + for i in range(1, 10): + count[i] += count[i - 1] + + # Build output array + i = n - 1 + while i >= 0: + index = (arr[i] // exp) % 10 + output[count[index] - 1] = arr[i] + count[index] -= 1 + i -= 1 + + # Copy output array to arr + for i in range(n): + arr[i] = output[i] + +def radix_sort(arr): + """ + Radix sort algorithm implementation + Time Complexity: O(d * (n + k)) where d is digits, k is range + Space Complexity: O(n + k) + """ + if not arr: + return arr + + # Find maximum number to know number of digits + max_num = max(arr) + + # Do counting sort for every digit + exp = 1 + while max_num // exp > 0: + counting_sort(arr, exp) + exp *= 10 + + return arr + +def bucket_sort(arr, num_buckets=10): + """ + Bucket sort algorithm implementation + Time Complexity: O(n + k) average case, O(n²) worst case + Space Complexity: O(n + k) + """ + if len(arr) <= 1: + return arr + + # Find minimum and maximum values + min_val = min(arr) + max_val = max(arr) + + # Calculate bucket range + bucket_range = (max_val - min_val) / num_buckets + + # Create empty buckets + buckets = [[] for _ in range(num_buckets)] + + # Put array elements into buckets + for num in arr: + if num == max_val: + bucket_index = num_buckets - 1 + else: + bucket_index = int((num - min_val) / bucket_range) + buckets[bucket_index].append(num) + + # Sort individual buckets and concatenate + sorted_arr = [] + for bucket in buckets: + if bucket: + bucket.sort() # Using built-in sort for individual buckets + sorted_arr.extend(bucket) + + return sorted_arr + +def shell_sort(arr): + """ + Shell sort algorithm implementation + Time Complexity: O(n log n) to O(n²) depending on gap sequence + Space Complexity: O(1) + """ + n = len(arr) + gap = n // 2 + + while gap > 0: + # Perform insertion sort with gap + for i in range(gap, n): + temp = arr[i] + j = i + + while j >= gap and arr[j - gap] > temp: + arr[j] = arr[j - gap] + j -= gap + + arr[j] = temp + + gap //= 2 + + return arr + +def cocktail_sort(arr): + """ + Cocktail sort (bidirectional bubble sort) implementation + Time Complexity: O(n²) + Space Complexity: O(1) + """ + n = len(arr) + start = 0 + end = n - 1 + swapped = True + + while swapped: + swapped = False + + # Forward pass + for i in range(start, end): + if arr[i] > arr[i + 1]: + arr[i], arr[i + 1] = arr[i + 1], arr[i] + swapped = True + + if not swapped: + break + + end -= 1 + swapped = False + + # Backward pass + for i in range(end - 1, start - 1, -1): + if arr[i] > arr[i + 1]: + arr[i], arr[i + 1] = arr[i + 1], arr[i] + swapped = True + + start += 1 + + return arr + +def gnome_sort(arr): + """ + Gnome sort algorithm implementation + Time Complexity: O(n²) + Space Complexity: O(1) + """ + index = 0 + n = len(arr) + + while index < n: + if index == 0: + index += 1 + elif arr[index] >= arr[index - 1]: + index += 1 + else: + arr[index], arr[index - 1] = arr[index - 1], arr[index] + index -= 1 + + return arr + +def comb_sort(arr): + """ + Comb sort algorithm implementation + Time Complexity: O(n²) worst case, O(n log n) average + Space Complexity: O(1) + """ + n = len(arr) + gap = n + shrink = 1.3 + swapped = True + + while gap > 1 or swapped: + # Update gap + gap = int(gap / shrink) + if gap < 1: + gap = 1 + + swapped = False + + # Compare elements with gap + for i in range(n - gap): + if arr[i] > arr[i + gap]: + arr[i], arr[i + gap] = arr[i + gap], arr[i] + swapped = True + + return arr + +def pancake_sort(arr): + """ + Pancake sort algorithm implementation + Time Complexity: O(n²) + Space Complexity: O(1) + """ + def flip(arr, k): + """Flip elements from 0 to k""" + left = 0 + while left < k: + arr[left], arr[k] = arr[k], arr[left] + left += 1 + k -= 1 + + def find_max_index(arr, n): + """Find index of maximum element in arr[0..n-1]""" + max_idx = 0 + for i in range(1, n): + if arr[i] > arr[max_idx]: + max_idx = i + return max_idx + + n = len(arr) + + for curr_size in range(n, 1, -1): + # Find index of maximum element in arr[0..curr_size-1] + max_idx = find_max_index(arr, curr_size) + + # If maximum is not at the end, move it to the end + if max_idx != curr_size - 1: + # Move maximum to beginning if it's not already there + if max_idx != 0: + flip(arr, max_idx) + + # Move maximum to the end + flip(arr, curr_size - 1) + + return arr + +def compare_sorting_algorithms(): + """ + Compare different sorting algorithms with sample data + """ + import time + import random + + # Generate test data + test_data = [random.randint(1, 1000) for _ in range(100)] + + algorithms = [ + ("Radix Sort", radix_sort), + ("Bucket Sort", bucket_sort), + ("Shell Sort", shell_sort), + ("Cocktail Sort", cocktail_sort), + ("Gnome Sort", gnome_sort), + ("Comb Sort", comb_sort), + ("Pancake Sort", pancake_sort) + ] + + print("Comparing sorting algorithms with 100 random integers:") + print("=" * 60) + + for name, algorithm in algorithms: + data_copy = test_data.copy() + + start_time = time.time() + sorted_data = algorithm(data_copy) + end_time = time.time() + + execution_time = (end_time - start_time) * 1000 # Convert to milliseconds + is_sorted = sorted_data == sorted(test_data) + + print(f"{name:15} | Time: {execution_time:8.4f}ms | Correct: {is_sorted}") + +# Test the advanced sorting algorithms +if __name__ == "__main__": + # Test each algorithm individually + test_array = [170, 45, 75, 90, 2, 802, 24, 66] + print(f"Original array: {test_array}") + print("=" * 50) + + # Test Radix Sort + radix_result = radix_sort(test_array.copy()) + print(f"Radix Sort: {radix_result}") + + # Test Bucket Sort + bucket_result = bucket_sort(test_array.copy()) + print(f"Bucket Sort: {bucket_result}") + + # Test Shell Sort + shell_result = shell_sort(test_array.copy()) + print(f"Shell Sort: {shell_result}") + + # Test Cocktail Sort + cocktail_result = cocktail_sort(test_array.copy()) + print(f"Cocktail Sort: {cocktail_result}") + + # Test Gnome Sort + gnome_result = gnome_sort(test_array.copy()) + print(f"Gnome Sort: {gnome_result}") + + # Test Comb Sort + comb_result = comb_sort(test_array.copy()) + print(f"Comb Sort: {comb_result}") + + # Test Pancake Sort + pancake_result = pancake_sort(test_array.copy()) + print(f"Pancake Sort: {pancake_result}") + + print("\n" + "=" * 50) + # Compare performance + compare_sorting_algorithms() \ No newline at end of file diff --git a/python/areaoftraingle.py b/python/areaoftraingle.py new file mode 100644 index 00000000..cf444e54 --- /dev/null +++ b/python/areaoftraingle.py @@ -0,0 +1,17 @@ +# Python Program to find the area of triangle + +a = 5 +b = 6 +c = 7 + +# Uncomment below to take inputs from the user +# a = float(input('Enter first side: ')) +# b = float(input('Enter second side: ')) +# c = float(input('Enter third side: ')) + +# calculate the semi-perimeter +s = (a + b + c) / 2 + +# calculate the area +area = (s*(s-a)*(s-b)*(s-c)) ** 0.5 +print('The area of the triangle is %0.2f' %area) \ No newline at end of file diff --git a/python/arr_to_ll.py b/python/arr_to_ll.py new file mode 100644 index 00000000..09e97323 --- /dev/null +++ b/python/arr_to_ll.py @@ -0,0 +1,33 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class Solution: + def constructLL(self, arr): + # code here + head = Node(arr[0]) + + curr = head + + for i in range(1,len(arr)): + curr.next = Node(arr[i]) + curr = curr.next + return head + +def printList(head): + curr = head + while curr: + print(curr.data, end=" -> ") + curr = curr.next + print("None") + + +# Driver code +if __name__ == "__main__": + arr = [1, 2, 3, 4, 5] + obj = Solution() + head = obj.constructLL(arr) + + print("Linked List constructed from array:") + printList(head) \ No newline at end of file diff --git a/python/avl_tree.py b/python/avl_tree.py new file mode 100644 index 00000000..31910ee2 --- /dev/null +++ b/python/avl_tree.py @@ -0,0 +1,240 @@ +class Node: + def __init__(self, key): + self.key = key + self.left = None + self.right = None + self.height = 1 + +class AVLTree: + def __init__(self): + self.root = None + + def get_height(self, node): + if not node: + return 0 + return node.height + + def get_balance(self, node): + if not node: + return 0 + return self.get_height(node.left) - self.get_height(node.right) + + def update_height(self, node): + if not node: + return + node.height = 1 + max(self.get_height(node.left), self.get_height(node.right)) + + def rotate_right(self, z): + y = z.left + T3 = y.right + + y.right = z + z.left = T3 + + self.update_height(z) + self.update_height(y) + + return y + + def rotate_left(self, z): + y = z.right + T2 = y.left + + y.left = z + z.right = T2 + + self.update_height(z) + self.update_height(y) + + return y + + def insert(self, key): + self.root = self._insert(self.root, key) + + def _insert(self, node, key): + if not node: + return Node(key) + + if key < node.key: + node.left = self._insert(node.left, key) + elif key > node.key: + node.right = self._insert(node.right, key) + else: + return node + + self.update_height(node) + + balance = self.get_balance(node) + + if balance > 1 and key < node.left.key: + return self.rotate_right(node) + + if balance < -1 and key > node.right.key: + return self.rotate_left(node) + + if balance > 1 and key > node.left.key: + node.left = self.rotate_left(node.left) + return self.rotate_right(node) + + if balance < -1 and key < node.right.key: + node.right = self.rotate_right(node.right) + return self.rotate_left(node) + + return node + + def delete(self, key): + self.root = self._delete(self.root, key) + + def _delete(self, node, key): + if not node: + return node + + if key < node.key: + node.left = self._delete(node.left, key) + elif key > node.key: + node.right = self._delete(node.right, key) + else: + if not node.left: + return node.right + elif not node.right: + return node.left + + temp = self._get_min_value_node(node.right) + node.key = temp.key + node.right = self._delete(node.right, temp.key) + + if not node: + return node + + self.update_height(node) + + balance = self.get_balance(node) + + if balance > 1 and self.get_balance(node.left) >= 0: + return self.rotate_right(node) + + if balance > 1 and self.get_balance(node.left) < 0: + node.left = self.rotate_left(node.left) + return self.rotate_right(node) + + if balance < -1 and self.get_balance(node.right) <= 0: + return self.rotate_left(node) + + if balance < -1 and self.get_balance(node.right) > 0: + node.right = self.rotate_right(node.right) + return self.rotate_left(node) + + return node + + def _get_min_value_node(self, node): + current = node + while current.left: + current = current.left + return current + + def search(self, key): + return self._search(self.root, key) + + def _search(self, node, key): + if not node or node.key == key: + return node + + if key < node.key: + return self._search(node.left, key) + return self._search(node.right, key) + + def inorder(self): + result = [] + self._inorder(self.root, result) + return result + + def _inorder(self, node, result): + if node: + self._inorder(node.left, result) + result.append(node.key) + self._inorder(node.right, result) + + def preorder(self): + result = [] + self._preorder(self.root, result) + return result + + def _preorder(self, node, result): + if node: + result.append(node.key) + self._preorder(node.left, result) + self._preorder(node.right, result) + + def postorder(self): + result = [] + self._postorder(self.root, result) + return result + + def _postorder(self, node, result): + if node: + self._postorder(node.left, result) + self._postorder(node.right, result) + result.append(node.key) + + def level_order(self): + if not self.root: + return [] + + result = [] + queue = [self.root] + + while queue: + node = queue.pop(0) + result.append(node.key) + + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + return result + + def get_max_depth(self): + return self.get_height(self.root) + + def is_balanced(self): + return self._is_balanced(self.root) + + def _is_balanced(self, node): + if not node: + return True + + balance = self.get_balance(node) + if abs(balance) > 1: + return False + + return self._is_balanced(node.left) and self._is_balanced(node.right) + +if __name__ == "__main__": + avl = AVLTree() + + elements = [50, 25, 75, 10, 30, 60, 80, 5, 15, 27, 55, 65] + + print("Inserting elements:", elements) + for elem in elements: + avl.insert(elem) + + print("\nInorder Traversal:", avl.inorder()) + print("Preorder Traversal:", avl.preorder()) + print("Postorder Traversal:", avl.postorder()) + print("Level Order Traversal:", avl.level_order()) + + print("\nTree Height:", avl.get_max_depth()) + print("Is Balanced:", avl.is_balanced()) + + search_key = 27 + found = avl.search(search_key) + print(f"\nSearching for {search_key}:", "Found" if found else "Not Found") + + delete_elements = [10, 25, 75] + print(f"\nDeleting elements: {delete_elements}") + for elem in delete_elements: + avl.delete(elem) + + print("Inorder after deletion:", avl.inorder()) + print("Is still balanced:", avl.is_balanced()) diff --git a/python/bellman_ford.py b/python/bellman_ford.py new file mode 100644 index 00000000..8f60d903 --- /dev/null +++ b/python/bellman_ford.py @@ -0,0 +1,35 @@ +def bellman_ford_path(edges, start): + nodes = set() + for u, v, w in edges: + nodes.add(u) + nodes.add(v) + + dist = {n: float('inf') for n in nodes} + dist[start] = 0 + V = len(nodes) + + for _ in range(V - 1): + for u, v, w in edges: + if dist[u] != float('inf') and dist[u] + w < dist[v]: + dist[v] = dist[u] + w + + for u, v, w in edges: + if dist[u] != float('inf') and dist[u] + w < dist[v]: + return "Negative Cycle Detected" + + return dist + +# Example +E = [ + ('A', 'B', -1), + ('A', 'C', 4), + ('B', 'C', 3), + ('B', 'D', 2), + ('B', 'E', 2), + ('D', 'B', 1), + ('E', 'D', -3) +] + +start_node = 'A' +res = bellman_ford_path(E, start_node) +print(f"Shortest Paths from {start_node}: {res}") \ No newline at end of file diff --git a/python/bfs.py b/python/bfs.py new file mode 100644 index 00000000..484646e2 --- /dev/null +++ b/python/bfs.py @@ -0,0 +1,26 @@ +from collections import deque + +def bfs(graph, start): + visited = [False] * len(graph) + queue = deque([start]) + visited[start] = True + + while queue: + vertex = queue.popleft() + print(vertex, end=" ") + for neighbor in graph[vertex]: + if not visited[neighbor]: + visited[neighbor] = True + queue.append(neighbor) + +# Example usage +graph = [ + [1, 4], + [0, 2, 3, 4], + [1, 3], + [1, 2, 4], + [0, 1, 3] +] + +print("BFS starting from vertex 0:") +bfs(graph, 0) diff --git a/python/binary_search.py b/python/binary_search.py index 1aabc64e..d3b9c17e 100644 --- a/python/binary_search.py +++ b/python/binary_search.py @@ -1,30 +1,17 @@ def binary_search(arr, target): - """ - Binary search algorithm to find target in sorted array - Time Complexity: O(log n) - Space Complexity: O(1) - """ left, right = 0, len(arr) - 1 - while left <= right: mid = (left + right) // 2 - if arr[mid] == target: return mid elif arr[mid] < target: left = mid + 1 else: right = mid - 1 - return -1 -# Test the function -if __name__ == "__main__": - arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] - target = 7 - result = binary_search(arr, target) - - if result != -1: - print(f"Element {target} found at index {result}") - else: - print(f"Element {target} not found in array") \ No newline at end of file +# Example usage +arr = [1, 2, 4, 7, 9] +target = 7 +result = binary_search(arr, target) +print(f"Element found at index: {result}" if result != -1 else "Element not found") diff --git a/python/binary_search1.py b/python/binary_search1.py new file mode 100644 index 00000000..a1c7c1ca --- /dev/null +++ b/python/binary_search1.py @@ -0,0 +1,26 @@ +# Binary Search Implementation in Python + +def binary_search(arr, target): + low = 0 + high = len(arr) - 1 + + while low <= high: + mid = (low + high) // 2 + if arr[mid] == target: + return mid + elif arr[mid] < target: + low = mid + 1 + else: + high = mid - 1 + + return -1 + +# Example usage +if __name__ == "__main__": + arr = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91] + target = 23 + result = binary_search(arr, target) + if result != -1: + print(f"Element found at index {result}") + else: + print("Element not found in array") diff --git a/python/binary_search_tree.py b/python/binary_search_tree.py index 702f2418..c3fe2c62 100644 --- a/python/binary_search_tree.py +++ b/python/binary_search_tree.py @@ -1,78 +1,45 @@ -from typing import Optional +class Node: + def __init__(self, key): + self.val = key + self.left = None + self.right = None -class TreeNode: - """Each node holds a value and points to left & right children""" - def __init__(self, val): - self.val = val - self.left: Optional['TreeNode'] = None - self.right: Optional['TreeNode'] = None +def insert(root, key): + if root is None: + return Node(key) + if key < root.val: + root.left = insert(root.left, key) + else: + root.right = insert(root.right, key) + return root -class BinarySearchTree: - """ - Binary Search Tree - keeps numbers organized - Smaller values go left, larger go right - This makes searching super fast! - """ - def __init__(self): - self.root: Optional[TreeNode] = None - - def insert(self, val) -> None: - """Add a new number to our tree""" - if not self.root: - self.root = TreeNode(val) # First node becomes the root - return - - # These findes the right spot by comparing values - current = self.root - while True: - if val < current.val: # Go left for smaller values - if not current.left: - current.left = TreeNode(val) - break - current = current.left - else: # Go right for larger values - if not current.right: - current.right = TreeNode(val) - break - current = current.right - - def search(self, val) -> bool: - """Check if a number exists in our tree""" - current = self.root - while current: - if val == current.val: - return True # Found it! - current = current.left if val < current.val else current.right - return False # Nope, not here - - def display(self, node: Optional[TreeNode] = None, level: int = 0): - """Show the tree structure - rotated 90° to the right""" - if node is None: - node = self.root - if node is None: # Handle case where root is None - print("Tree is empty") - return - if node.right: - self.display(node.right, level + 1) - print(' ' * level + f'→ {node.val}') - if node.left: - self.display(node.left, level + 1) +def search(root, key): + if root is None or root.val == key: + return root + if key < root.val: + return search(root.left, key) + return search(root.right, key) +def inorder(root): + if root: + inorder(root.left) + print(root.val, end=' ') + inorder(root.right) -# Let's test it out! -if __name__ == "__main__": - bst = BinarySearchTree() - - # Add some numbers - numbers = [50, 30, 70, 20, 40, 60, 80] - print("Building tree with:", numbers) - for num in numbers: - bst.insert(num) - - # Show our tree - print("\nTree structure:") - bst.display() - - # Try searching - print(f"\nIs 40 in tree? {bst.search(40)}") - print(f"Is 100 in tree? {bst.search(100)}") \ No newline at end of file +# Example usage +root = None +keys = [20, 10, 30, 5, 15, 25, 35] + +for key in keys: + root = insert(root, key) + +print("Inorder traversal of BST:") +inorder(root) +print() + +search_key = 15 +result = search(root, search_key) +if result: + print(f"Found {search_key} in BST") +else: + print(f"{search_key} not found in BST") diff --git a/python/binary_tree.py b/python/binary_tree.py index 48b9c979..cf4abf55 100644 --- a/python/binary_tree.py +++ b/python/binary_tree.py @@ -1,41 +1,33 @@ - -from collections import deque - class Node: - def __init__(self, val, left=None, right=None): - self.val = val - self.left = left - self.right = right + def __init__(self, key): + self.left = None + self.right = None + self.val = key + +def inorder(root): + if root: + inorder(root.left) + print(root.val, end=" ") + inorder(root.right) -def build_tree_level_order(values): - if not values: - return None - it = iter(values) - root_val = next(it) - if root_val is None: - return None +def preorder(root): + if root: + print(root.val, end=" ") + preorder(root.left) + preorder(root.right) - root = Node(root_val) - q = deque([root]) +def postorder(root): + if root: + postorder(root.left) + postorder(root.right) + print(root.val, end=" ") - for v in it: - parent = q[0] - if parent.left is None: - if v is not None: - parent.left = Node(v) - q.append(parent.left) - else: - parent.left = None - continue - if parent.right is None: - if v is not None: - parent.right = Node(v) - q.append(parent.right) - else: - parent.right = None - q.popleft() - return root +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) -if __name__ == "__main__": - vals = [1, 2, 3, 4, 5, None, 7] - root = build_tree_level_order(vals) +print("Inorder:", end=" "); inorder(root) +print("\nPreorder:", end=" "); preorder(root) +print("\nPostorder:", end=" "); postorder(root) diff --git a/python/binary_tree_serialize_deserialize.py b/python/binary_tree_serialize_deserialize.py new file mode 100644 index 00000000..68d8c743 --- /dev/null +++ b/python/binary_tree_serialize_deserialize.py @@ -0,0 +1,35 @@ +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +class Codec: + def serialize(self, root): + """Encodes a tree to a single string.""" + def recur(node): + if not node: + vals.append('null') + return + vals.append(str(node.val)) + recur(node.left) + recur(node.right) + + vals = [] + recur(root) + return ','.join(vals) + + def deserialize(self, data): + """Decodes your encoded data to tree.""" + def recur(): + if self.vals[0] == 'null': + self.vals.pop(0) + return None + node = TreeNode(int(self.vals[0])) + self.vals.pop(0) + node.left = recur() + node.right = recur() + return node + + self.vals = data.split(',') + return recur() diff --git a/python/binary_tree_traversal.py b/python/binary_tree_traversal.py new file mode 100644 index 00000000..4b690e6b --- /dev/null +++ b/python/binary_tree_traversal.py @@ -0,0 +1,37 @@ +class Node: + def __init__(self, key): + self.left = None + self.right = None + self.val = key + +def inorder(root): + if root: + inorder(root.left) + print(root.val, end=' ') + inorder(root.right) + +def preorder(root): + if root: + print(root.val, end=' ') + preorder(root.left) + preorder(root.right) + +def postorder(root): + if root: + postorder(root.left) + postorder(root.right) + print(root.val, end=' ') + +# Example usage +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) + +print("Inorder traversal:") +inorder(root) +print("\nPreorder traversal:") +preorder(root) +print("\nPostorder traversal:") +postorder(root) diff --git a/python/bubble_sort.py b/python/bubble_sort.py index 76cf858a..861dfcd4 100644 --- a/python/bubble_sort.py +++ b/python/bubble_sort.py @@ -1,31 +1,11 @@ def bubble_sort(arr): - """ - Bubble sort algorithm implementation - Time Complexity: O(n²) - Space Complexity: O(1) - """ n = len(arr) - for i in range(n): - # Flag to optimize - if no swapping occurs, array is sorted - swapped = False - for j in range(0, n - i - 1): if arr[j] > arr[j + 1]: - # Swap elements arr[j], arr[j + 1] = arr[j + 1], arr[j] - swapped = True - - # If no swapping occurred, array is already sorted - if not swapped: - break - - return arr -# Test the function -if __name__ == "__main__": - numbers = [64, 34, 25, 12, 22, 11, 90] - print(f"Original array: {numbers}") - - sorted_numbers = bubble_sort(numbers.copy()) - print(f"Sorted array: {sorted_numbers}") \ No newline at end of file +# Example usage +arr = [64, 25, 12, 22, 11] +bubble_sort(arr) +print("Sorted array:", arr) diff --git a/python/bubblesort.py b/python/bubblesort.py new file mode 100644 index 00000000..98281bda --- /dev/null +++ b/python/bubblesort.py @@ -0,0 +1,16 @@ +def bubble_sort(arr): + n = len(arr) + for i in range(n): + # After each pass, the largest element moves to the end + for j in range(0, n - i - 1): + if arr[j] > arr[j + 1]: + # Swap if elements are in wrong order + arr[j], arr[j + 1] = arr[j + 1], arr[j] + +# Example usage +numbers = [64, 34, 25, 12, 22, 11, 90] +print("Before sorting:", numbers) + +bubble_sort(numbers) + +print("After sorting:", numbers) diff --git a/python/bulls_and_cows.py b/python/bulls_and_cows.py new file mode 100644 index 00000000..92ba28ed --- /dev/null +++ b/python/bulls_and_cows.py @@ -0,0 +1,21 @@ +from collections import defaultdict + +class Solution: + def getHint(self, secret: str, guess: str) -> str: + bulls = 0 + cows = 0 + + secret_count = defaultdict(int) + guess_count = defaultdict(int) + + for s, g in zip(secret, guess): + if s == g: + bulls += 1 + else: + secret_count[s] += 1 + guess_count[g] += 1 + + for digit in guess_count: + cows += min(secret_count[digit], guess_count[digit]) + + return f"{bulls}A{cows}B" diff --git a/python/calcu.py b/python/calcu.py new file mode 100644 index 00000000..19302c6e --- /dev/null +++ b/python/calcu.py @@ -0,0 +1,40 @@ +def add(x, y): + return x + y + +def subtract(x, y): + return x - y + +def multiply(x, y): + return x * y + +def divide(x, y): + if y != 0: + return x / y + else: + return "Error! Division by zero." + +def calculator(): + print("Select operation:") + print("1. Add") + print("2. Subtract") + print("3. Multiply") + print("4. Divide") + + choice = input("Enter choice (1/2/3/4): ") + + if choice in ('1', '2', '3', '4'): + num1 = float(input("Enter first number: ")) + num2 = float(input("Enter second number: ")) + + if choice == '1': + print(f"{num1} + {num2} = {add(num1, num2)}") + elif choice == '2': + print(f"{num1} - {num2} = {subtract(num1, num2)}") + elif choice == '3': + print(f"{num1} * {num2} = {multiply(num1, num2)}") + elif choice == '4': + print(f"{num1} / {num2} = {divide(num1, num2)}") + else: + print("Invalid input. Please select a valid operation.") + +calculator() diff --git a/python/calendar-module.py b/python/calendar-module.py new file mode 100644 index 00000000..d5b72f91 --- /dev/null +++ b/python/calendar-module.py @@ -0,0 +1,13 @@ +#Challenge- You are given a date. Your task is to find what the day is on that date. +import calendar as c + +#take input in MM_DD_YYYY format +month, day, year = map(int, input().split()) + +#weekday() -> returns 0 (Monday) to 6 (Sunday) +day_index = c.weekday(year, month, day) + +#to uppercase weekday name +day_name = c.day_name[day_index].upper() + +print(day_name) \ No newline at end of file diff --git a/python/chatbot.py b/python/chatbot.py new file mode 100644 index 00000000..cabcb7c7 --- /dev/null +++ b/python/chatbot.py @@ -0,0 +1,13 @@ +print("Chatbot: Hi! I am a simple chatbot. How can I help you today?") + +while True: + user_input = input("You: ") + if user_input.lower() == "hello": + print("Chatbot: Hello! How are you?") + elif user_input.lower() == "how are you?": + print("Chatbot: I am just a program, but I’m doing well. Thank you!") + elif user_input.lower() == "bye": + print("Chatbot: Goodbye! Have a great day!") + break + else: + print("Chatbot: Sorry, I don’t understand that.") diff --git a/python/check prime.py b/python/check prime.py index 6731f494..fdad0bc2 100644 --- a/python/check prime.py +++ b/python/check prime.py @@ -1,10 +1,10 @@ -n=int(input("Enter a number to check if it is prime: ")) -if n> - for i in range(2,int(n/2)+1): - if(n%i==0): - print(n,"is not a prime number") +n = int(input("Enter a number to check if it is prime: ")) +if n <= 1: + print(n, "is not a prime number") +else: + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + print(n, "is not a prime number") break else: - print(n,"is a prime number") -else: - print(n,"is not a prime number") \ No newline at end of file + print(n, "is a prime number") diff --git a/python/circular_subarray_palindrome_check.py b/python/circular_subarray_palindrome_check.py new file mode 100644 index 00000000..d934baa7 --- /dev/null +++ b/python/circular_subarray_palindrome_check.py @@ -0,0 +1,23 @@ +# Circular Subarray Palindrome Check + +# Problem: +# Given an array of integers, check if the array can be rearranged in a circular fashion such that the sequence forms a palindrome when traversed clockwise. + +# Example: + +# Input: [1, 2, 3, 2, 1] → Output: True +# Input: [1, 2, 3, 4] → Output: False + + +# Solution (Python): + +from collections import Counter + +def circular_palindrome(arr): + freq = Counter(arr) + odd_count = sum(v % 2 for v in freq.values()) + return odd_count <= 1 + +# Example +print(circular_palindrome([1,2,3,2,1])) # True +print(circular_palindrome([1,2,3,4])) # False \ No newline at end of file diff --git a/python/coin_change.py b/python/coin_change.py new file mode 100644 index 00000000..7f311d20 --- /dev/null +++ b/python/coin_change.py @@ -0,0 +1,14 @@ +def coin_change(coins, amount): + dp = [0] * (amount + 1) + dp[0] = 1 + + for coin in coins: + for x in range(coin, amount + 1): + dp[x] += dp[x - coin] + + return dp[amount] + +# Example usage +coins = [1, 2, 5] +amount = 5 +print(f"Number of ways to make amount {amount}:", coin_change(coins, amount)) diff --git a/python/container_with_water.py b/python/container_with_water.py new file mode 100644 index 00000000..4b0415c7 --- /dev/null +++ b/python/container_with_water.py @@ -0,0 +1,16 @@ +class Solution: + def maxArea(self, h: List[int]) -> int: + l=0 + r=len(h)-1 + + ans=0 + while(lans: + ans=mult + if min(h[l],h[r])==h[r]: + r-=1 + else: + l+=1 + + return ans \ No newline at end of file diff --git a/python/convert_sorted_array_to_binary_search_tree.py b/python/convert_sorted_array_to_binary_search_tree.py new file mode 100644 index 00000000..9d130ef2 --- /dev/null +++ b/python/convert_sorted_array_to_binary_search_tree.py @@ -0,0 +1,12 @@ +def TreeNode(val): + raise NotImplementedError + +class Solution(object): + def sortedArrayToBST(self, nums): + if len(nums) == 0: + return None + mid = len(nums)//2 + root = TreeNode(nums[mid]) + root.left = self.sortedArrayToBST(nums[:mid]) + root.right = self.sortedArrayToBST(nums[mid+1:]) + return root \ No newline at end of file diff --git a/python/counting_sort.py b/python/counting_sort.py new file mode 100644 index 00000000..d40889ef --- /dev/null +++ b/python/counting_sort.py @@ -0,0 +1,213 @@ +""" +Counting Sort Algorithm Implementation + +Counting Sort is a non-comparison based sorting algorithm that works well +when the range of input data (k) is not significantly larger than the number +of objects to be sorted (n). It has a time complexity of O(n+k). + +Time Complexity: O(n + k) where n is the number of elements and k is the range +Space Complexity: O(k) for the count array + +Advantages: +- Stable sorting algorithm +- Linear time complexity when k = O(n) +- Doesn't use comparisons + +Disadvantages: +- Not suitable for large ranges of input data +- Only works with non-negative integers (or can be modified for other types) +""" + +def counting_sort(arr): + """ + Sorts an array using the counting sort algorithm. + + Args: + arr (list): List of non-negative integers to be sorted + + Returns: + list: Sorted array in ascending order + + Example: + >>> counting_sort([4, 2, 2, 8, 3, 3, 1]) + [1, 2, 2, 3, 3, 4, 8] + """ + if not arr: + return arr + + # Find the maximum element to determine the range + max_val = max(arr) + min_val = min(arr) + + # Handle negative numbers by shifting the range + range_size = max_val - min_val + 1 + + # Create count array to store count of each element + count = [0] * range_size + + # Store count of each element + for num in arr: + count[num - min_val] += 1 + + # Modify count array to store actual positions + for i in range(1, range_size): + count[i] += count[i - 1] + + # Build the result array + result = [0] * len(arr) + + # Build result array from right to left to maintain stability + for i in range(len(arr) - 1, -1, -1): + result[count[arr[i] - min_val] - 1] = arr[i] + count[arr[i] - min_val] -= 1 + + return result + +def counting_sort_simple(arr): + """ + Simple version of counting sort for educational purposes. + Works only with non-negative integers starting from 0. + + Args: + arr (list): List of non-negative integers to be sorted + + Returns: + list: Sorted array in ascending order + """ + if not arr: + return arr + + max_val = max(arr) + count = [0] * (max_val + 1) + + # Count occurrences of each element + for num in arr: + count[num] += 1 + + # Reconstruct the sorted array + result = [] + for i in range(len(count)): + result.extend([i] * count[i]) + + return result + +def demonstrate_counting_sort(): + """ + Demonstrates the counting sort algorithm with various test cases. + """ + print("=== Counting Sort Demonstration ===\n") + + test_cases = [ + [4, 2, 2, 8, 3, 3, 1], + [1, 4, 1, 2, 7, 5, 2], + [1, 1, 1, 1], + [5, 4, 3, 2, 1], + [1, 2, 3, 4, 5], + [], + [42], + [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] + ] + + for i, test_case in enumerate(test_cases, 1): + print(f"Test Case {i}:") + print(f"Original: {test_case}") + sorted_arr = counting_sort(test_case.copy()) + print(f"Sorted: {sorted_arr}") + print(f"Verification: {sorted_arr == sorted(test_case)}") + print("-" * 40) + +def counting_sort_with_objects(arr, key_func): + """ + Counting sort implementation that works with objects. + + Args: + arr (list): List of objects to be sorted + key_func (function): Function to extract the sorting key from objects + + Returns: + list: Sorted array based on the key function + """ + if not arr: + return arr + + # Extract keys and find range + keys = [key_func(obj) for obj in arr] + max_key = max(keys) + min_key = min(keys) + range_size = max_key - min_key + 1 + + # Create buckets for each possible key value + buckets = [[] for _ in range(range_size)] + + # Place objects in appropriate buckets + for obj in arr: + key = key_func(obj) + buckets[key - min_key].append(obj) + + # Concatenate all buckets to get sorted result + result = [] + for bucket in buckets: + result.extend(bucket) + + return result + +# Example usage and testing +if __name__ == "__main__": + # Run demonstration + demonstrate_counting_sort() + + # Test with objects + print("\n=== Counting Sort with Objects ===") + + class Student: + def __init__(self, name, grade): + self.name = name + self.grade = grade + + def __repr__(self): + return f"Student({self.name}, {self.grade})" + + students = [ + Student("Alice", 85), + Student("Bob", 90), + Student("Charlie", 85), + Student("David", 95), + Student("Eve", 80) + ] + + print("Original students:") + for student in students: + print(f" {student}") + + sorted_students = counting_sort_with_objects(students, lambda s: s.grade) + + print("\nSorted by grade:") + for student in sorted_students: + print(f" {student}") + + # Performance comparison + print("\n=== Performance Test ===") + import time + import random + + # Generate random data + large_arr = [random.randint(0, 1000) for _ in range(10000)] + + # Test counting sort + start_time = time.time() + counting_sorted = counting_sort(large_arr.copy()) + counting_time = time.time() - start_time + + # Test built-in sort + start_time = time.time() + builtin_sorted = sorted(large_arr) + builtin_time = time.time() - start_time + + print(f"Counting Sort time: {counting_time:.4f} seconds") + print(f"Built-in Sort time: {builtin_time:.4f} seconds") + print(f"Results match: {counting_sorted == builtin_sorted}") + + if counting_time < builtin_time: + print("Counting Sort is faster!") + else: + print("Built-in Sort is faster!") \ No newline at end of file diff --git a/python/cycle_detection.py b/python/cycle_detection.py new file mode 100644 index 00000000..3fbfaca1 --- /dev/null +++ b/python/cycle_detection.py @@ -0,0 +1,58 @@ +class Node: + def __init__(self, data): + self.data = data + self.next = None + +class LinkedList: + def __init__(self): + self.head = None + + def append(self, data): + new_node = Node(data) + if not self.head: + self.head = new_node + return + temp = self.head + while temp.next: + temp = temp.next + temp.next = new_node + + def create_cycle(self, pos): + """Creates a cycle in the linked list at the given position""" + if pos < 0: + return + cycle_node = self.head + last_node = self.head + count = 0 + while count < pos and cycle_node: + cycle_node = cycle_node.next + count += 1 + while last_node.next: + last_node = last_node.next + last_node.next = cycle_node + + def detect_cycle(self): + """Floyd’s Cycle Detection Algorithm (Tortoise and Hare)""" + slow = self.head + fast = self.head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + if slow == fast: + return True + return False + + +# Example usage: +if __name__ == "__main__": + ll = LinkedList() + ll.append(1) + ll.append(2) + ll.append(3) + ll.append(4) + ll.append(5) + + print("Cycle detected?" , ll.detect_cycle()) # False + + ll.create_cycle(2) # Create cycle at node with value 3 + print("Cycle detected?" , ll.detect_cycle()) # True diff --git a/python/decode.py b/python/decode.py new file mode 100644 index 00000000..ea1a9d05 --- /dev/null +++ b/python/decode.py @@ -0,0 +1,13 @@ +def longestConsecutive(nums): + num_set = set(nums) + longest = 0 + + for n in num_set: + if n - 1 not in num_set: # new sequence start + length = 1 + while n + length in num_set: + length += 1 + longest = max(longest, length) + return longest + +print(longestConsecutive([100, 4, 200, 1, 3, 2])) diff --git a/python/detect_cycle_undirected.py b/python/detect_cycle_undirected.py new file mode 100644 index 00000000..f782ae34 --- /dev/null +++ b/python/detect_cycle_undirected.py @@ -0,0 +1,27 @@ +def is_cyclic_util(graph, v, visited, parent): + visited[v] = True + for neighbor in graph[v]: + if not visited[neighbor]: + if is_cyclic_util(graph, neighbor, visited, v): + return True + elif parent != neighbor: + return True + return False + +def is_cyclic(graph): + visited = [False] * len(graph) + for i in range(len(graph)): + if not visited[i]: + if is_cyclic_util(graph, i, visited, -1): + return True + return False + +# Example usage +graph = [ + [1, 2], + [0, 2], + [0, 1, 3], + [2] +] + +print("Graph has cycle:" , is_cyclic(graph)) diff --git a/python/dfs.py b/python/dfs.py new file mode 100644 index 00000000..69396708 --- /dev/null +++ b/python/dfs.py @@ -0,0 +1,20 @@ +def dfs(graph, start, visited=None): + if visited is None: + visited = set() + visited.add(start) + print(start, end=" ") + for neighbor in graph[start]: + if neighbor not in visited: + dfs(graph, neighbor, visited) + +# Example usage +graph = [ + [1, 4], + [0, 2, 3, 4], + [1, 3], + [1, 2, 4], + [0, 1, 3] +] + +print("DFS starting from vertex 0:") +dfs(graph, 0) diff --git a/python/dfs_bfs_algo.py b/python/dfs_bfs_algo.py new file mode 100644 index 00000000..1d3ce95e --- /dev/null +++ b/python/dfs_bfs_algo.py @@ -0,0 +1,122 @@ +import collections + +class Node: + """ + A simple class for a binary tree node. + """ + def __init__(self, key): + self.val = key + self.left = None + self.right = None + +# --- Depth-First Search (DFS) Traversal Algorithms --- + +def print_preorder(root): + """ + Performs Pre-order traversal (Root -> Left -> Right). + """ + if root: + # 1. Visit the root node + print(root.val, end=" ") + + # 2. Recursively visit the left subtree + print_preorder(root.left) + + # 3. Recursively visit the right subtree + print_preorder(root.right) + +def print_inorder(root): + """ + Performs In-order traversal (Left -> Root -> Right). + For a Binary Search Tree (BST), this prints nodes in sorted order. + """ + if root: + # 1. Recursively visit the left subtree + print_inorder(root.left) + + # 2. Visit the root node + print(root.val, end=" ") + + # 3. Recursively visit the right subtree + print_inorder(root.right) + +def print_postorder(root): + """ + Performs Post-order traversal (Left -> Right -> Root). + Useful for operations like deleting nodes. + """ + if root: + # 1. Recursively visit the left subtree + print_postorder(root.left) + + # 2. Recursively visit the right subtree + print_postorder(root.right) + + # 3. Visit the root node + print(root.val, end=" ") + +# --- Breadth-First Search (BFS) Traversal Algorithm --- + +def print_level_order(root): + """ + Performs Level-order (BFS) traversal, visiting nodes level by level. + Uses a queue to keep track of nodes. + """ + if not root: + return + + # Use a deque (double-ended queue) for efficient pop(0) + queue = collections.deque([root]) + + while queue: + # Dequeue the first node in the queue + node = queue.popleft() + + print(node.val, end=" ") + + # Enqueue the left child if it exists + if node.left: + queue.append(node.left) + + # Enqueue the right child if it exists + if node.right: + queue.append(node.right) + + +# --- Main function to run the example --- +if __name__ == "__main__": + + # Let's manually create a simple binary tree: + # + # 1 + # / \ + # 2 3 + # / \ \ + # 4 5 6 + + root = Node(1) + root.left = Node(2) + root.right = Node(3) + root.left.left = Node(4) + root.left.right = Node(5) + root.right.right = Node(6) + + print("Pre-order traversal (Root, Left, Right):") + print_preorder(root) + # Expected: 1 2 4 5 3 6 + print("\n") + + print("In-order traversal (Left, Root, Right):") + print_inorder(root) + # Expected: 4 2 5 1 3 6 + print("\n") + + print("Post-order traversal (Left, Right, Root):") + print_postorder(root) + # Expected: 4 5 2 6 3 1 + print("\n") + + print("Level-order traversal (BFS):") + print_level_order(root) + # Expected: 1 2 3 4 5 6 + print("\n") diff --git a/python/dice_roller.py b/python/dice_roller.py new file mode 100644 index 00000000..78c819c8 --- /dev/null +++ b/python/dice_roller.py @@ -0,0 +1,15 @@ +# dice_roller.py +import random + +def roll_dice(): + return random.randint(1, 6) + +if __name__ == "__main__": + while True: + input("Press Enter to roll the dice...") + print(f"You rolled a {roll_dice()}!") + again = input("Roll again? (y/n): ").lower() + if again != 'y': + print("Thanks for playing!") + break + diff --git a/python/dijkstra's_algorithm.py b/python/dijkstra's_algorithm.py new file mode 100644 index 00000000..812cc510 --- /dev/null +++ b/python/dijkstra's_algorithm.py @@ -0,0 +1,37 @@ +import heapq + +def dijkstra(graph, start): + # dist: {node: shortest_distance} + dist = {node: float('inf') for node in graph} + dist[start] = 0 + # pq: stores tuples of (distance, node) + pq = [(0, start)] + + while pq: + d, u = heapq.heappop(pq) + + # Skip if we found a shorter path already + if d > dist[u]: + continue + + for v, weight in graph[u].items(): + new_dist = dist[u] + weight + + if new_dist < dist[v]: + dist[v] = new_dist + heapq.heappush(pq, (new_dist, v)) + + return dist + +# Example +# Graph format: {node: {neighbor: weight, ...}, ...} +G = { + 'A': {'B': 1, 'C': 4}, + 'B': {'C': 2, 'D': 5}, + 'C': {'D': 1}, + 'D': {'E': 3}, + 'E': {} +} + +shortest_paths = dijkstra(G, 'A') +print(f"Dijkstra's Shortest Paths from A: {shortest_paths}") \ No newline at end of file diff --git a/python/dijkstra.py b/python/dijkstra.py new file mode 100644 index 00000000..72a1378c --- /dev/null +++ b/python/dijkstra.py @@ -0,0 +1,45 @@ +import heapq + +def dijkstra(graph, start_node): + # Initialize distances: all to infinity, start_node to 0 + distances = {node: float('inf') for node in graph} + distances[start_node] = 0 + + # Priority queue: stores (distance, node) + priority_queue = [(0, start_node)] + + # Stores the path (parent node) + predecessors = {node: None for node in graph} + + while priority_queue: + current_distance, current_node = heapq.heappop(priority_queue) + + # Ignore if we found a shorter path to current_node already + if current_distance > distances[current_node]: + continue + + # Explore neighbors + for neighbor, weight in graph[current_node].items(): + distance = current_distance + weight + + # If a shorter path is found + if distance < distances[neighbor]: + distances[neighbor] = distance + predecessors[neighbor] = current_node + heapq.heappush(priority_queue, (distance, neighbor)) + + return distances, predecessors + +# Example Usage: +# graph = {node: {neighbor: weight, ...}, ...} +example_graph = { + 'A': {'B': 1, 'C': 4}, + 'B': {'C': 2, 'D': 5}, + 'C': {'D': 1}, + 'D': {} +} + +shortest_distances, paths = dijkstra(example_graph, 'A') + +# print(f"Shortest Distances: {shortest_distances}") +# print(f"Predecessors: {paths}") \ No newline at end of file diff --git a/python/disjoint_set.py b/python/disjoint_set.py new file mode 100644 index 00000000..d2f9993e --- /dev/null +++ b/python/disjoint_set.py @@ -0,0 +1,41 @@ +class DSU: + def __init__(self, n): + # Initially, each node is its own parent + self.parent = [i for i in range(n)] + self.rank = [0] * n # Rank for union by rank + + def find(self, x): + if self.parent[x] != x: + # Path compression + self.parent[x] = self.find(self.parent[x]) + return self.parent[x] + + def union(self, x, y): + xroot = self.find(x) + yroot = self.find(y) + + if xroot == yroot: + return # Already in the same set + + # Union by rank + if self.rank[xroot] < self.rank[yroot]: + self.parent[xroot] = yroot + elif self.rank[xroot] > self.rank[yroot]: + self.parent[yroot] = xroot + else: + self.parent[yroot] = xroot + self.rank[xroot] += 1 + +# Example usage +if __name__ == "__main__": + n = 5 + dsu = DSU(n) + + # Merge sets + dsu.union(0, 1) + dsu.union(1, 2) + dsu.union(3, 4) + + # Find representatives + for i in range(n): + print(f"Parent of {i}: {dsu.find(i)}") diff --git a/python/disjoint_set_union.py b/python/disjoint_set_union.py new file mode 100644 index 00000000..502cb8f5 --- /dev/null +++ b/python/disjoint_set_union.py @@ -0,0 +1,97 @@ +class DisjointSetUnion: + """ + Disjoint Set Union (Union-Find) data structure with path compression + and union by rank optimization. + + Used for: Connected components, Kruskal's MST, cycle detection + Time: O(α(n)) ≈ O(1) for both union and find operations + """ + + def __init__(self, n): + """Initialize n elements, each in its own set""" + self.parent = list(range(n)) + self.rank = [0] * n + self.size = [1] * n + + def find(self, x): + """Find the root of element x with path compression""" + if self.parent[x] != x: + self.parent[x] = self.find(self.parent[x]) # Path compression + return self.parent[x] + + def union(self, x, y): + """Union two sets containing x and y""" + root_x = self.find(x) + root_y = self.find(y) + + if root_x == root_y: + return False # Already in same set + + # Union by rank + if self.rank[root_x] < self.rank[root_y]: + self.parent[root_x] = root_y + self.size[root_y] += self.size[root_x] + elif self.rank[root_x] > self.rank[root_y]: + self.parent[root_y] = root_x + self.size[root_x] += self.size[root_y] + else: + self.parent[root_y] = root_x + self.size[root_x] += self.size[root_y] + self.rank[root_x] += 1 + + return True + + def connected(self, x, y): + """Check if x and y are in the same set""" + return self.find(x) == self.find(y) + + def get_size(self, x): + """Get the size of the set containing x""" + return self.size[self.find(x)] + + +# Example usage: Number of connected components +def count_components(n, edges): + """ + Count number of connected components in an undirected graph. + + Args: + n: number of nodes (0 to n-1) + edges: list of [u, v] edges + + Returns: + number of connected components + """ + dsu = DisjointSetUnion(n) + + for u, v in edges: + dsu.union(u, v) + + # Count unique roots + return len(set(dsu.find(i) for i in range(n))) + + +# Test cases +if __name__ == "__main__": + # Example 1: Simple connected components + n = 5 + edges = [[0, 1], [1, 2], [3, 4]] + print(f"Components: {count_components(n, edges)}") # Output: 2 + + # Example 2: Detecting cycle + dsu = DisjointSetUnion(4) + edges = [[0, 1], [1, 2], [2, 3], [3, 0]] + + has_cycle = False + for u, v in edges: + if dsu.connected(u, v): + has_cycle = True + print(f"Cycle detected at edge ({u}, {v})") + break + dsu.union(u, v) + + # Example 3: Size tracking + dsu2 = DisjointSetUnion(6) + dsu2.union(0, 1) + dsu2.union(1, 2) + print(f"Size of component containing 0: {dsu2.get_size(0)}") # Output: 3 \ No newline at end of file diff --git a/python/distinct_subsequences.py b/python/distinct_subsequences.py new file mode 100644 index 00000000..e69de29b diff --git a/python/dynamic_programming.py b/python/dynamic_programming.py new file mode 100644 index 00000000..d1a2bc1e --- /dev/null +++ b/python/dynamic_programming.py @@ -0,0 +1,300 @@ +def knapsack_01(weights, values, capacity): + """ + 0/1 Knapsack problem using dynamic programming + Time Complexity: O(n * W) + Space Complexity: O(n * W) + """ + n = len(weights) + + # Create a 2D DP table + dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)] + + # Build table dp[][] in bottom-up manner + for i in range(1, n + 1): + for w in range(1, capacity + 1): + # If weight of current item is more than capacity, skip it + if weights[i-1] > w: + dp[i][w] = dp[i-1][w] + else: + # Take maximum of including or excluding current item + include = values[i-1] + dp[i-1][w - weights[i-1]] + exclude = dp[i-1][w] + dp[i][w] = max(include, exclude) + + # Backtrack to find which items to include + result_weight = capacity + items_included = [] + + for i in range(n, 0, -1): + if dp[i][result_weight] != dp[i-1][result_weight]: + items_included.append(i-1) # Item index + result_weight -= weights[i-1] + + return dp[n][capacity], items_included[::-1] + +def longest_common_subsequence(text1, text2): + """ + Longest Common Subsequence using dynamic programming + Time Complexity: O(m * n) + Space Complexity: O(m * n) + """ + m, n = len(text1), len(text2) + + # Create DP table + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # Fill the DP table + for i in range(1, m + 1): + for j in range(1, n + 1): + if text1[i-1] == text2[j-1]: + dp[i][j] = dp[i-1][j-1] + 1 + else: + dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + + # Backtrack to find the actual LCS + lcs = [] + i, j = m, n + while i > 0 and j > 0: + if text1[i-1] == text2[j-1]: + lcs.append(text1[i-1]) + i -= 1 + j -= 1 + elif dp[i-1][j] > dp[i][j-1]: + i -= 1 + else: + j -= 1 + + return dp[m][n], ''.join(reversed(lcs)) + +def edit_distance(str1, str2): + """ + Edit Distance (Levenshtein Distance) using dynamic programming + Time Complexity: O(m * n) + Space Complexity: O(m * n) + """ + m, n = len(str1), len(str2) + + # Create DP table + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # Initialize base cases + for i in range(m + 1): + dp[i][0] = i # Delete all characters from str1 + for j in range(n + 1): + dp[0][j] = j # Insert all characters to str1 + + # Fill the DP table + for i in range(1, m + 1): + for j in range(1, n + 1): + if str1[i-1] == str2[j-1]: + dp[i][j] = dp[i-1][j-1] # No operation needed + else: + dp[i][j] = 1 + min( + dp[i-1][j], # Delete + dp[i][j-1], # Insert + dp[i-1][j-1] # Replace + ) + + return dp[m][n] + +def coin_change_min_coins(coins, amount): + """ + Minimum number of coins to make amount + Time Complexity: O(amount * len(coins)) + Space Complexity: O(amount) + """ + dp = [float('inf')] * (amount + 1) + dp[0] = 0 + + for i in range(1, amount + 1): + for coin in coins: + if coin <= i: + dp[i] = min(dp[i], dp[i - coin] + 1) + + return dp[amount] if dp[amount] != float('inf') else -1 + +def coin_change_ways(coins, amount): + """ + Number of ways to make amount using given coins + Time Complexity: O(amount * len(coins)) + Space Complexity: O(amount) + """ + dp = [0] * (amount + 1) + dp[0] = 1 + + for coin in coins: + for i in range(coin, amount + 1): + dp[i] += dp[i - coin] + + return dp[amount] + +def longest_increasing_subsequence(nums): + """ + Longest Increasing Subsequence using dynamic programming + Time Complexity: O(n²) + Space Complexity: O(n) + """ + if not nums: + return 0, [] + + n = len(nums) + dp = [1] * n + parent = [-1] * n + + for i in range(1, n): + for j in range(i): + if nums[j] < nums[i] and dp[j] + 1 > dp[i]: + dp[i] = dp[j] + 1 + parent[i] = j + + # Find the index with maximum LIS length + max_length = max(dp) + max_index = dp.index(max_length) + + # Reconstruct the LIS + lis = [] + current = max_index + while current != -1: + lis.append(nums[current]) + current = parent[current] + + return max_length, list(reversed(lis)) + +def matrix_chain_multiplication(dimensions): + """ + Matrix Chain Multiplication using dynamic programming + Time Complexity: O(n³) + Space Complexity: O(n²) + """ + n = len(dimensions) - 1 # Number of matrices + + # dp[i][j] represents minimum scalar multiplications for matrices i to j + dp = [[0] * n for _ in range(n)] + + # l is chain length + for l in range(2, n + 1): + for i in range(n - l + 1): + j = i + l - 1 + dp[i][j] = float('inf') + + for k in range(i, j): + cost = (dp[i][k] + dp[k+1][j] + + dimensions[i] * dimensions[k+1] * dimensions[j+1]) + dp[i][j] = min(dp[i][j], cost) + + return dp[0][n-1] + +def rod_cutting(prices, length): + """ + Rod Cutting problem using dynamic programming + Time Complexity: O(n²) + Space Complexity: O(n) + """ + dp = [0] * (length + 1) + cuts = [0] * (length + 1) + + for i in range(1, length + 1): + for j in range(i): + if prices[j] + dp[i - j - 1] > dp[i]: + dp[i] = prices[j] + dp[i - j - 1] + cuts[i] = j + 1 + + # Reconstruct the solution + cut_lengths = [] + remaining = length + while remaining > 0: + cut_length = cuts[remaining] + cut_lengths.append(cut_length) + remaining -= cut_length + + return dp[length], cut_lengths + +def max_subarray_sum(nums): + """ + Maximum Subarray Sum (Kadane's Algorithm) + Time Complexity: O(n) + Space Complexity: O(1) + """ + max_ending_here = max_so_far = nums[0] + start = end = 0 + temp_start = 0 + + for i in range(1, len(nums)): + if max_ending_here < 0: + max_ending_here = nums[i] + temp_start = i + else: + max_ending_here += nums[i] + + if max_ending_here > max_so_far: + max_so_far = max_ending_here + start = temp_start + end = i + + return max_so_far, nums[start:end+1] + +# Test all dynamic programming algorithms +if __name__ == "__main__": + print("=== Dynamic Programming Algorithms ===\n") + + # Test 0/1 Knapsack + print("1. 0/1 Knapsack Problem:") + weights = [10, 20, 30] + values = [60, 100, 120] + capacity = 50 + max_value, items = knapsack_01(weights, values, capacity) + print(f" Weights: {weights}, Values: {values}, Capacity: {capacity}") + print(f" Maximum value: {max_value}, Items selected: {items}\n") + + # Test LCS + print("2. Longest Common Subsequence:") + text1, text2 = "AGGTAB", "GXTXAYB" + lcs_length, lcs_string = longest_common_subsequence(text1, text2) + print(f" Text1: {text1}, Text2: {text2}") + print(f" LCS length: {lcs_length}, LCS: '{lcs_string}'\n") + + # Test Edit Distance + print("3. Edit Distance:") + str1, str2 = "kitten", "sitting" + distance = edit_distance(str1, str2) + print(f" String1: '{str1}', String2: '{str2}'") + print(f" Edit distance: {distance}\n") + + # Test Coin Change + print("4. Coin Change:") + coins = [1, 3, 4] + amount = 6 + min_coins = coin_change_min_coins(coins, amount) + ways = coin_change_ways(coins, amount) + print(f" Coins: {coins}, Amount: {amount}") + print(f" Minimum coins needed: {min_coins}") + print(f" Number of ways: {ways}\n") + + # Test LIS + print("5. Longest Increasing Subsequence:") + nums = [10, 9, 2, 5, 3, 7, 101, 18] + lis_length, lis_sequence = longest_increasing_subsequence(nums) + print(f" Array: {nums}") + print(f" LIS length: {lis_length}, LIS: {lis_sequence}\n") + + # Test Matrix Chain Multiplication + print("6. Matrix Chain Multiplication:") + dimensions = [1, 2, 3, 4] # Matrices: 1x2, 2x3, 3x4 + min_multiplications = matrix_chain_multiplication(dimensions) + print(f" Matrix dimensions: {dimensions}") + print(f" Minimum scalar multiplications: {min_multiplications}\n") + + # Test Rod Cutting + print("7. Rod Cutting:") + prices = [1, 5, 8, 9, 10, 17, 17, 20] + length = 8 + max_profit, cuts = rod_cutting(prices, length) + print(f" Prices: {prices}, Rod length: {length}") + print(f" Maximum profit: {max_profit}, Cuts: {cuts}\n") + + # Test Maximum Subarray + print("8. Maximum Subarray Sum:") + nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] + max_sum, subarray = max_subarray_sum(nums) + print(f" Array: {nums}") + print(f" Maximum sum: {max_sum}, Subarray: {subarray}") \ No newline at end of file diff --git a/python/edit_distance.py b/python/edit_distance.py new file mode 100644 index 00000000..38082f51 --- /dev/null +++ b/python/edit_distance.py @@ -0,0 +1,23 @@ +def edit_distance(str1, str2): + m, n = len(str1), len(str2) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(m + 1): + for j in range(n + 1): + if i == 0: + dp[i][j] = j + elif j == 0: + dp[i][j] = i + elif str1[i-1] == str2[j-1]: + dp[i][j] = dp[i-1][j-1] + else: + dp[i][j] = 1 + min(dp[i-1][j], # Remove + dp[i][j-1], # Insert + dp[i-1][j-1]) # Replace + + return dp[m][n] + +# Example usage +str1 = "sunday" +str2 = "saturday" +print(f"Edit distance between '{str1}' and '{str2}' is {edit_distance(str1, str2)}") diff --git a/python/exampledictionary.py b/python/exampledictionary.py new file mode 100644 index 00000000..8c358784 --- /dev/null +++ b/python/exampledictionary.py @@ -0,0 +1,55 @@ +# Create a dictionary +student_info = { + "name": "Alice", + "age": 20, + "major": "Computer Science", + "gpa": 3.8 +} + +print("Original student information:") +print(student_info) + +# Accessing values +print(f"\nStudent's name: {student_info['name']}") +print(f"Student's major: {student_info['major']}") + +# Adding a new key-value pair +student_info["university"] = "State University" +print("\nAfter adding university:") +print(student_info) + +# Modifying a value +student_info["gpa"] = 3.9 +print("\nAfter updating GPA:") +print(student_info) + +# Removing a key-value pair +removed_item = student_info.pop("age") +print(f"\nAfter removing age: {student_info}") +print(f"Removed item (age): {removed_item}") + +# Iterating through keys +print("\nAll keys in the dictionary:") +for key in student_info: + print(key) + +# Iterating through values +print("\nAll values in the dictionary:") +for value in student_info.values(): + print(value) + +# Iterating through key-value pairs +print("\nAll key-value pairs:") +for key, value in student_info.items(): + print(f"{key}: {value}") + +# Checking if a key exists +if "major" in student_info: + print("\n'major' key exists in the dictionary.") + +# Getting the length of the dictionary +print(f"\nLength of the dictionary: {len(student_info)}") + +# Clearing the dictionary +student_info.clear() +print(f"\nAfter clearing the dictionary: {student_info}") \ No newline at end of file diff --git a/python/factorial of a number.py b/python/factorial of a number.py new file mode 100644 index 00000000..c48370a4 --- /dev/null +++ b/python/factorial of a number.py @@ -0,0 +1,14 @@ +# define a factorial function + +def factorial(num): + +if num == 0: # return 1 if num is 0 + +return 1 + +return num * factorial(num - 1) # return factorial of num + +ans = int(input("Enter a number to find factorial: ")) # getting input to find factorial + +print(f"The Factorial of {ans} is {factorial(ans)}") # printing factorial of a number + diff --git a/python/factorial_recursion.py b/python/factorial_recursion.py new file mode 100644 index 00000000..c85063da --- /dev/null +++ b/python/factorial_recursion.py @@ -0,0 +1,8 @@ +def factorial(n): + if n == 0 or n == 1: + return 1 + return n * factorial(n - 1) + +# Example usage +num = 5 +print(f"Factorial of {num} is {factorial(num)}") diff --git a/python/fibonacci-new.py b/python/fibonacci-new.py new file mode 100644 index 00000000..194a1722 --- /dev/null +++ b/python/fibonacci-new.py @@ -0,0 +1,13 @@ +""" +Program: Fibonacci Sequence using Iteration +""" + +def fibonacci(n): + a, b = 0, 1 + for _ in range(n): + print(a, end=" ") + a, b = b, a + b + +if __name__ == "__main__": + n = int(input("Enter number of terms: ")) + fibonacci(n) diff --git a/python/fibonacci_dp.py b/python/fibonacci_dp.py new file mode 100644 index 00000000..42a85edc --- /dev/null +++ b/python/fibonacci_dp.py @@ -0,0 +1,11 @@ +def fibonacci(n, memo={}): + if n in memo: + return memo[n] + if n <= 1: + return n + memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo) + return memo[n] + +# Example usage +n = 10 +print(f"Fibonacci number at position {n} is {fibonacci(n)}") diff --git a/python/fibonacci_recursion.py b/python/fibonacci_recursion.py new file mode 100644 index 00000000..ac5a0007 --- /dev/null +++ b/python/fibonacci_recursion.py @@ -0,0 +1,8 @@ +def fibonacci(n): + if n <= 1: + return n + return fibonacci(n - 1) + fibonacci(n - 2) + +# Example usage +n = 7 +print(f"Fibonacci number at position {n} is {fibonacci(n)}") diff --git a/python/find_index.py b/python/find_index.py new file mode 100644 index 00000000..f395f9c2 --- /dev/null +++ b/python/find_index.py @@ -0,0 +1,18 @@ +# Defining a tuple with 8 elements +tuple_1 = (111, 256, 348, 789, 123, 456, 789, 1009) +# Displaying the elements of the tuple +print("The elements of Tuple are::\n", tuple_1, "\n") +counter = 0 +index = 0 +for items in tuple_1: + counter += 1 + print("Value ", counter, " = ", items) + +# Asking user to input an element to find its index in the tuple +item_index = int(input("\nEnter the element in the tuple of the element to find its index: ")) + +# Checking if the item exists in the tuple +if item_index in tuple_1: + print("\nThe index of element ",item_index," in the tuple is: ",tuple_1.index(item_index)) +else: + print("\nElement ",item_index," does not exist in the tuple. Check your input and try again!!") \ No newline at end of file diff --git a/python/find_leaders.py b/python/find_leaders.py new file mode 100644 index 00000000..07bb2c0a --- /dev/null +++ b/python/find_leaders.py @@ -0,0 +1,23 @@ +def find_leaders(arr): + n = len(arr) + leaders = [] + + # Start from the last element, which is always a leader + max_from_right = arr[-1] + leaders.append(max_from_right) + + # Traverse the array from right to left + for i in range(n - 2, -1, -1): + if arr[i] > max_from_right: + leaders.append(arr[i]) + max_from_right = arr[i] + + # Reverse the result since we collected leaders from the right + leaders.reverse() + return leaders + + +#main +arr = list(map(int, input("Enter elements of array separated by space: ").split())) + +print("Leaders in the array are:", find_leaders(arr)) diff --git a/python/first_missing_positive.py b/python/first_missing_positive.py new file mode 100644 index 00000000..e69de29b diff --git a/python/fizzbuzz.py b/python/fizzbuzz.py new file mode 100644 index 00000000..31f5212c --- /dev/null +++ b/python/fizzbuzz.py @@ -0,0 +1,9 @@ +for i in range(1, 101): + if i % 3 == 0 and i % 5 == 0: + print("FizzBuzz") + elif i % 3 == 0: + print("Fizz") + elif i % 5 == 0: + print("Buzz") + else: + print(i) \ No newline at end of file diff --git a/python/fourth_from_first.py b/python/fourth_from_first.py new file mode 100644 index 00000000..9328f87e --- /dev/null +++ b/python/fourth_from_first.py @@ -0,0 +1,13 @@ +# Defining a tuple with 10 elements +tuple_1 = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) +# # Displaying the elements of the tuple +print("The elements of Tuple are::\n", tuple_1, "\n") +counter = 0 +for items in tuple_1: + counter += 1 + print("Value ",counter," = ",items) + +# Displaying the 4th element from first and last +print("\nOUTPUT::") +print("The 4th element from first is = ",tuple_1[3]) +print("The 4th element from last is = ",tuple_1[-4]) \ No newline at end of file diff --git a/python/github_username_validator.py b/python/github_username_validator.py new file mode 100644 index 00000000..10381a66 --- /dev/null +++ b/python/github_username_validator.py @@ -0,0 +1,14 @@ +import re + +def is_valid_github_username(username): + # GitHub username rules: + # 1. 1-39 characters + # 2. Only alphanumeric or hyphens + # 3. Cannot start or end with hyphen + # 4. Cannot have consecutive hyphens + pattern = r'^(?!-)(?!.*--)[A-Za-z0-9-]{1,39}(?= 90): + Grade="A" +elif(marks >=80 and marks<90 ): + Grade= "B" +elif(marks>=70 and marks<80): + Grade= "C" +elif(70>marks): + Grade ="D" +else: + Grade="fail" + +print("the grade of student is:-",Grade) diff --git a/python/graph2.py b/python/graph2.py new file mode 100644 index 00000000..a4e34f04 --- /dev/null +++ b/python/graph2.py @@ -0,0 +1,34 @@ +# Problem: Given a grid of '1's (land) and '0's (water), count the number of islands. + +def numIslands(grid): + if not grid: + return 0 + + rows, cols = len(grid), len(grid[0]) + visited = set() + + def dfs(r, c): + if (r < 0 or c < 0 or r >= rows or c >= cols or + grid[r][c] == "0" or (r, c) in visited): + return + visited.add((r, c)) + dfs(r+1, c) + dfs(r-1, c) + dfs(r, c+1) + dfs(r, c-1) + + islands = 0 + for r in range(rows): + for c in range(cols): + if grid[r][c] == "1" and (r, c) not in visited: + dfs(r, c) + islands += 1 + return islands + +grid = [ + ["1","1","0","0","0"], + ["1","1","0","0","0"], + ["0","0","1","0","0"], + ["0","0","0","1","1"] +] +print(numIslands(grid)) diff --git a/python/graph_adjacency_list.py b/python/graph_adjacency_list.py new file mode 100644 index 00000000..8a0c8625 --- /dev/null +++ b/python/graph_adjacency_list.py @@ -0,0 +1,27 @@ +class Graph: + def __init__(self, vertices): + self.V = vertices + self.graph = [[] for _ in range(vertices)] + + def add_edge(self, u, v): + self.graph[u].append(v) + self.graph[v].append(u) # For undirected graph + + def print_graph(self): + for i in range(self.V): + print(f"Vertex {i}: ", end="") + for j in self.graph[i]: + print(f"->{j}", end=" ") + print() + +# Example usage +g = Graph(5) +g.add_edge(0, 1) +g.add_edge(0, 4) +g.add_edge(1, 2) +g.add_edge(1, 3) +g.add_edge(1, 4) +g.add_edge(2, 3) +g.add_edge(3, 4) + +g.print_graph() diff --git a/python/graph_algorithms.py b/python/graph_algorithms.py new file mode 100644 index 00000000..655fe6f0 --- /dev/null +++ b/python/graph_algorithms.py @@ -0,0 +1,296 @@ +class Graph: + """ + Graph implementation using adjacency list + Supports both directed and undirected graphs + """ + + def __init__(self, directed=False): + self.graph = {} + self.directed = directed + + def add_vertex(self, vertex): + """Add a vertex to the graph""" + if vertex not in self.graph: + self.graph[vertex] = [] + + def add_edge(self, u, v, weight=1): + """Add an edge between vertices u and v""" + # Add vertices if they don't exist + self.add_vertex(u) + self.add_vertex(v) + + # Add edge from u to v + self.graph[u].append((v, weight)) + + # If undirected, add edge from v to u + if not self.directed: + self.graph[v].append((u, weight)) + + def get_vertices(self): + """Get all vertices in the graph""" + return list(self.graph.keys()) + + def get_edges(self): + """Get all edges in the graph""" + edges = [] + for u in self.graph: + for v, weight in self.graph[u]: + if self.directed or u <= v: # Avoid duplicates in undirected graph + edges.append((u, v, weight)) + return edges + + def bfs(self, start): + """ + Breadth-First Search traversal + Time Complexity: O(V + E) + Space Complexity: O(V) + """ + if start not in self.graph: + return [] + + visited = set() + queue = [start] + result = [] + + while queue: + vertex = queue.pop(0) + if vertex not in visited: + visited.add(vertex) + result.append(vertex) + + # Add unvisited neighbors to queue + for neighbor, _ in self.graph[vertex]: + if neighbor not in visited: + queue.append(neighbor) + + return result + + def dfs(self, start): + """ + Depth-First Search traversal (iterative) + Time Complexity: O(V + E) + Space Complexity: O(V) + """ + if start not in self.graph: + return [] + + visited = set() + stack = [start] + result = [] + + while stack: + vertex = stack.pop() + if vertex not in visited: + visited.add(vertex) + result.append(vertex) + + # Add unvisited neighbors to stack (reverse order for consistent traversal) + for neighbor, _ in reversed(self.graph[vertex]): + if neighbor not in visited: + stack.append(neighbor) + + return result + + def dfs_recursive(self, start, visited=None, result=None): + """ + Depth-First Search traversal (recursive) + """ + if visited is None: + visited = set() + if result is None: + result = [] + + if start not in self.graph: + return result + + visited.add(start) + result.append(start) + + for neighbor, _ in self.graph[start]: + if neighbor not in visited: + self.dfs_recursive(neighbor, visited, result) + + return result + + def has_path(self, start, end): + """Check if there's a path between start and end vertices""" + if start not in self.graph or end not in self.graph: + return False + + visited = set() + queue = [start] + + while queue: + vertex = queue.pop(0) + if vertex == end: + return True + + if vertex not in visited: + visited.add(vertex) + for neighbor, _ in self.graph[vertex]: + if neighbor not in visited: + queue.append(neighbor) + + return False + + def shortest_path_bfs(self, start, end): + """ + Find shortest path using BFS (unweighted graph) + Returns the path and its length + """ + if start not in self.graph or end not in self.graph: + return None, 0 + + if start == end: + return [start], 0 + + visited = set() + queue = [(start, [start])] + + while queue: + vertex, path = queue.pop(0) + + if vertex not in visited: + visited.add(vertex) + + for neighbor, _ in self.graph[vertex]: + if neighbor == end: + return path + [neighbor], len(path) + + if neighbor not in visited: + queue.append((neighbor, path + [neighbor])) + + return None, 0 + + def is_cyclic(self): + """Check if the graph contains a cycle""" + if self.directed: + return self._is_cyclic_directed() + else: + return self._is_cyclic_undirected() + + def _is_cyclic_directed(self): + """Check for cycle in directed graph using DFS""" + color = {vertex: 'white' for vertex in self.graph} + + def dfs_visit(vertex): + color[vertex] = 'gray' + + for neighbor, _ in self.graph[vertex]: + if color[neighbor] == 'gray': # Back edge found + return True + if color[neighbor] == 'white' and dfs_visit(neighbor): + return True + + color[vertex] = 'black' + return False + + for vertex in self.graph: + if color[vertex] == 'white': + if dfs_visit(vertex): + return True + return False + + def _is_cyclic_undirected(self): + """Check for cycle in undirected graph using DFS""" + visited = set() + + def dfs_visit(vertex, parent): + visited.add(vertex) + + for neighbor, _ in self.graph[vertex]: + if neighbor not in visited: + if dfs_visit(neighbor, vertex): + return True + elif neighbor != parent: # Back edge found + return True + return False + + for vertex in self.graph: + if vertex not in visited: + if dfs_visit(vertex, None): + return True + return False + + def connected_components(self): + """Find all connected components in undirected graph""" + if self.directed: + raise ValueError("Connected components are defined for undirected graphs") + + visited = set() + components = [] + + for vertex in self.graph: + if vertex not in visited: + component = [] + self._dfs_component(vertex, visited, component) + components.append(component) + + return components + + def _dfs_component(self, vertex, visited, component): + """Helper method for finding connected components""" + visited.add(vertex) + component.append(vertex) + + for neighbor, _ in self.graph[vertex]: + if neighbor not in visited: + self._dfs_component(neighbor, visited, component) + + def __str__(self): + """String representation of the graph""" + result = [] + for vertex in self.graph: + neighbors = [f"{v}({w})" for v, w in self.graph[vertex]] + result.append(f"{vertex} -> {', '.join(neighbors)}") + return '\n'.join(result) + +# Test the graph implementation +if __name__ == "__main__": + # Test undirected graph + print("=== Undirected Graph Test ===") + g = Graph(directed=False) + + # Add edges + edges = [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'), ('D', 'E')] + for u, v in edges: + g.add_edge(u, v) + + print("Graph structure:") + print(g) + + print(f"\nVertices: {g.get_vertices()}") + print(f"Edges: {g.get_edges()}") + + # Test traversals + start_vertex = 'A' + print(f"\nBFS from {start_vertex}: {g.bfs(start_vertex)}") + print(f"DFS from {start_vertex}: {g.dfs(start_vertex)}") + print(f"DFS Recursive from {start_vertex}: {g.dfs_recursive(start_vertex)}") + + # Test path finding + start, end = 'A', 'E' + print(f"\nPath from {start} to {end} exists: {g.has_path(start, end)}") + path, length = g.shortest_path_bfs(start, end) + print(f"Shortest path from {start} to {end}: {path} (length: {length})") + + # Test cycle detection + print(f"\nGraph has cycle: {g.is_cyclic()}") + + # Test connected components + print(f"Connected components: {g.connected_components()}") + + # Test directed graph + print("\n=== Directed Graph Test ===") + dg = Graph(directed=True) + + # Create a directed graph with cycle + directed_edges = [('X', 'Y'), ('Y', 'Z'), ('Z', 'X'), ('X', 'W')] + for u, v in directed_edges: + dg.add_edge(u, v) + + print("Directed graph structure:") + print(dg) + + print(f"\nDFS from X: {dg.dfs('X')}") + print(f"Directed graph has cycle: {dg.is_cyclic()}") \ No newline at end of file diff --git a/python/graph_bfs.py b/python/graph_bfs.py new file mode 100644 index 00000000..513fbd1c --- /dev/null +++ b/python/graph_bfs.py @@ -0,0 +1,26 @@ +from collections import deque + +def bfs(graph, start): + visited = set() + queue = deque([start]) + visited.add(start) + + while queue: + node = queue.popleft() + print(node, end=" ") + + for neighbor in graph[node]: + if neighbor not in visited: + visited.add(neighbor) + queue.append(neighbor) + +graph = { + 0: [1, 2], + 1: [0, 3, 4], + 2: [0, 5], + 3: [1], + 4: [1, 5], + 5: [2, 4] +} +print("BFS Traversal starting from node 0:") +bfs(graph, 0) diff --git a/python/graph_dfs.py b/python/graph_dfs.py new file mode 100644 index 00000000..89dbf56a --- /dev/null +++ b/python/graph_dfs.py @@ -0,0 +1,17 @@ +def dfs(graph, node, visited): + if node not in visited: + print(node, end=" ") + visited.add(node) + for neighbor in graph[node]: + dfs(graph, neighbor, visited) + +graph = { + 0: [1, 2], + 1: [0, 3, 4], + 2: [0, 5], + 3: [1], + 4: [1, 5], + 5: [2, 4] +} +print("\nDFS Traversal starting from node 0:") +dfs(graph, 0, set()) diff --git a/python/half_linklist.py b/python/half_linklist.py index 44d14c01..54bcdca3 100644 --- a/python/half_linklist.py +++ b/python/half_linklist.py @@ -1,4 +1,4 @@ -head = [1,2,3,4,5,6] +sumhead = [1,2,3,4,5,6] def middleLinkList(head): temp = head diff --git a/python/hash_count.py b/python/hash_count.py new file mode 100644 index 00000000..d2ba6cfe --- /dev/null +++ b/python/hash_count.py @@ -0,0 +1,21 @@ +class Solution: + def hashCount(self, arr,n): + hash={} + for i in range (n): + if arr[i] in hash: + hash[arr[i]]+=1 + else: + hash[arr[i]]=1 + + for key,value in hash.items(): + print(key,value) + + +n=int(input("Enter how many numbers you want in the array")) +arr=[] +for i in range(n): + ele=int(input("Enter: ")) + arr.append(ele) + +soution=Solution() +soution.hashCount(arr,n) \ No newline at end of file diff --git a/python/heap_operations.py b/python/heap_operations.py new file mode 100644 index 00000000..ca89f2ef --- /dev/null +++ b/python/heap_operations.py @@ -0,0 +1,230 @@ +import heapq + +class MinHeap: + """ + Min Heap implementation using Python's heapq + """ + + def __init__(self): + self.heap = [] + + def push(self, val): + """Add an element to the heap""" + heapq.heappush(self.heap, val) + + def pop(self): + """Remove and return the smallest element""" + if not self.heap: + raise IndexError("pop from empty heap") + return heapq.heappop(self.heap) + + def peek(self): + """Return the smallest element without removing it""" + if not self.heap: + raise IndexError("peek from empty heap") + return self.heap[0] + + def size(self): + """Return the number of elements in the heap""" + return len(self.heap) + + def is_empty(self): + """Check if the heap is empty""" + return len(self.heap) == 0 + + def heapify(self, arr): + """Convert an array into a heap""" + self.heap = arr.copy() + heapq.heapify(self.heap) + +class MaxHeap: + """ + Max Heap implementation (using min heap with negated values) + """ + + def __init__(self): + self.heap = [] + + def push(self, val): + """Add an element to the heap""" + heapq.heappush(self.heap, -val) + + def pop(self): + """Remove and return the largest element""" + if not self.heap: + raise IndexError("pop from empty heap") + return -heapq.heappop(self.heap) + + def peek(self): + """Return the largest element without removing it""" + if not self.heap: + raise IndexError("peek from empty heap") + return -self.heap[0] + + def size(self): + """Return the number of elements in the heap""" + return len(self.heap) + + def is_empty(self): + """Check if the heap is empty""" + return len(self.heap) == 0 + +def heap_sort(arr): + """ + Heap sort algorithm implementation + Time Complexity: O(n log n) + Space Complexity: O(1) + """ + # Build max heap + n = len(arr) + + # Heapify the array (build max heap from bottom up) + for i in range(n // 2 - 1, -1, -1): + max_heapify(arr, n, i) + + # Extract elements one by one + for i in range(n - 1, 0, -1): + # Move current root to end + arr[0], arr[i] = arr[i], arr[0] + + # Call heapify on the reduced heap + max_heapify(arr, i, 0) + + return arr + +def max_heapify(arr, n, i): + """ + Maintain max heap property + """ + largest = i # Initialize largest as root + left = 2 * i + 1 # Left child + right = 2 * i + 2 # Right child + + # If left child exists and is greater than root + if left < n and arr[left] > arr[largest]: + largest = left + + # If right child exists and is greater than largest so far + if right < n and arr[right] > arr[largest]: + largest = right + + # If largest is not root + if largest != i: + arr[i], arr[largest] = arr[largest], arr[i] + + # Recursively heapify the affected sub-tree + max_heapify(arr, n, largest) + +def find_kth_largest(nums, k): + """ + Find kth largest element using min heap + Time Complexity: O(n log k) + Space Complexity: O(k) + """ + heap = [] + + for num in nums: + if len(heap) < k: + heapq.heappush(heap, num) + elif num > heap[0]: + heapq.heappop(heap) + heapq.heappush(heap, num) + + return heap[0] + +def find_kth_smallest(nums, k): + """ + Find kth smallest element using max heap + Time Complexity: O(n log k) + Space Complexity: O(k) + """ + heap = [] + + for num in nums: + if len(heap) < k: + heapq.heappush(heap, -num) # Use negative for max heap + elif num < -heap[0]: + heapq.heappop(heap) + heapq.heappush(heap, -num) + + return -heap[0] + +def merge_k_sorted_arrays(arrays): + """ + Merge k sorted arrays using min heap + Time Complexity: O(n log k) where n is total elements + Space Complexity: O(k) + """ + heap = [] + result = [] + + # Initialize heap with first element from each array + for i, arr in enumerate(arrays): + if arr: # Check if array is not empty + heapq.heappush(heap, (arr[0], i, 0)) # (value, array_index, element_index) + + while heap: + val, arr_idx, elem_idx = heapq.heappop(heap) + result.append(val) + + # Add next element from the same array + if elem_idx + 1 < len(arrays[arr_idx]): + next_val = arrays[arr_idx][elem_idx + 1] + heapq.heappush(heap, (next_val, arr_idx, elem_idx + 1)) + + return result + +# Test the heap implementations +if __name__ == "__main__": + # Test Min Heap + print("=== Min Heap Test ===") + min_heap = MinHeap() + values = [20, 15, 30, 10, 5, 7, 6, 12] + + print(f"Adding values: {values}") + for val in values: + min_heap.push(val) + + print("Extracting all elements from min heap:") + while not min_heap.is_empty(): + print(min_heap.pop(), end=" ") + print() + + # Test Max Heap + print("\n=== Max Heap Test ===") + max_heap = MaxHeap() + + print(f"Adding values: {values}") + for val in values: + max_heap.push(val) + + print("Extracting all elements from max heap:") + while not max_heap.is_empty(): + print(max_heap.pop(), end=" ") + print() + + # Test Heap Sort + print("\n=== Heap Sort Test ===") + unsorted_array = [64, 34, 25, 12, 22, 11, 90] + print(f"Original array: {unsorted_array}") + sorted_array = heap_sort(unsorted_array.copy()) + print(f"Heap sorted array: {sorted_array}") + + # Test kth largest/smallest + print("\n=== Kth Element Tests ===") + test_nums = [3, 2, 1, 5, 6, 4] + k = 2 + print(f"Array: {test_nums}") + print(f"{k}nd largest element: {find_kth_largest(test_nums, k)}") + print(f"{k}nd smallest element: {find_kth_smallest(test_nums, k)}") + + # Test merge k sorted arrays + print("\n=== Merge K Sorted Arrays Test ===") + sorted_arrays = [ + [1, 4, 5], + [1, 3, 4], + [2, 6] + ] + print(f"Input arrays: {sorted_arrays}") + merged = merge_k_sorted_arrays(sorted_arrays) + print(f"Merged array: {merged}") \ No newline at end of file diff --git a/python/hello_world.py b/python/hello_world.py new file mode 100644 index 00000000..b0589609 --- /dev/null +++ b/python/hello_world.py @@ -0,0 +1 @@ +print("hello world"); diff --git a/python/infix to postfix conversion using stack.py b/python/infix to postfix conversion using stack.py new file mode 100644 index 00000000..bf10d1e7 --- /dev/null +++ b/python/infix to postfix conversion using stack.py @@ -0,0 +1,43 @@ +#infix to postfix conversion using stack in python +#We will convert infix expression to postfix using stack based approach implemented in python using this code + +#code +def precedence(op): + if op == '+' or op == '-': + return 1 + if op == '*' or op == '/': + return 2 + if op == '^': + return 3 + return 0 + +def is_operand(ch): + return ch.isalnum() + +def infix_to_postfix(expression): + result = [] + stack = [] + + for ch in expression: + if is_operand(ch): + result.append(ch) + elif ch == '(': + stack.append(ch) + elif ch == ')': + while stack and stack[-1] != '(': + result.append(stack.pop()) + stack.pop() + else: + while stack and precedence(stack[-1]) >= precedence(ch): + result.append(stack.pop()) + stack.append(ch) + + while stack: + result.append(stack.pop()) + + return "".join(result) + + +'''expr = "A*(B+C)/D" +print("Infix:", expr) +print("Postfix:", infix_to_postfix(expr))''' ##example code to try \ No newline at end of file diff --git a/python/insertion_sort.py b/python/insertion_sort.py new file mode 100644 index 00000000..6432dfa5 --- /dev/null +++ b/python/insertion_sort.py @@ -0,0 +1,13 @@ +def insertion_sort(arr): + for i in range(1, len(arr)): + key = arr[i] + j = i - 1 + while j >= 0 and arr[j] > key: + arr[j + 1] = arr[j] + j -= 1 + arr[j + 1] = key + +# Example usage +arr = [12, 11, 13, 5, 6] +insertion_sort(arr) +print("Sorted array:", arr) diff --git a/python/interleaving_string.py b/python/interleaving_string.py new file mode 100644 index 00000000..e69de29b diff --git a/python/intersection_of_two_array.py b/python/intersection_of_two_array.py new file mode 100644 index 00000000..a68a1442 --- /dev/null +++ b/python/intersection_of_two_array.py @@ -0,0 +1,6 @@ +num1 = [1,2,2,1] +num2 = [2,2] +set1 = set(num1) +set2 = set(num2) +intersection = set1 & set2 +print("interstion of two array", list(intersection)) \ No newline at end of file diff --git a/python/josephus_problem(using deque).py b/python/josephus_problem(using deque).py new file mode 100644 index 00000000..9e2feeaf --- /dev/null +++ b/python/josephus_problem(using deque).py @@ -0,0 +1,42 @@ +#Josephus problem implementation using queue! +#Josephus problem:The Josephus Problem is a mathematical counting-out game where people stand in a circle and are eliminated one by one until only one remains, with the goal of finding the starting position of the last survivor. Named after the historian Flavius Josephus, it involves eliminating every kth person in a circle of n people, with the challenge being to determine the starting position that guarantees survival. + +#CODE +#double ended queue based opearations +class Deque: + def __init__(self): + self.items = [] + + def append(self, item): + self.items.append(item) + + def popleft(self): + if self.items: + return self.items.pop(0) + return None + + def rotate(self, n): + n = n % len(self.items) # handle n > length + self.items = self.items[n:] + self.items[:n] + + def __len__(self): + return len(self.items) + + def front(self): + return self.items[0] if self.items else None + +#solution for josephus +def josephus_queue(n, k): + q = Deque() + for i in range(1, n + 1): + q.append(i) + while len(q) > 1: + q.rotate(k - 1) + q.popleft() + return q.front() + +#sample to test +'''n = 7 +k = 3 +survivor = josephus_queue(n, k) +print("The survivor is at position:", survivor)''' diff --git a/python/kadanes_algo.py b/python/kadanes_algo.py new file mode 100644 index 00000000..27a43e4b --- /dev/null +++ b/python/kadanes_algo.py @@ -0,0 +1,33 @@ + +# Program Name: +# Maximum Subarray Sum using Kadane’s Algorithm + +# Problem Statement: +# Given an array of integers, find the contiguous subarray (containing at least one number) +# which has the largest sum and return its sum. + +# Example 1: +# Input: arr = [-2,1,-3,4,-1,2,1,-5,4] +# Output: 6 +# Explanation: Subarray [4,-1,2,1] has the maximum sum = 6 + +# Approach: +# Use Kadane’s Algorithm: +# - Initialize max_sum and current_sum with arr[0] +# - Traverse the array: +# current_sum = max(arr[i], current_sum + arr[i]) +# max_sum = max(max_sum, current_sum) +# - Return max_sum + + +def kadane(arr): + max_sum = current_sum = arr[0] + for num in arr[1:]: + current_sum = max(num, current_sum + num) + max_sum = max(max_sum, current_sum) + return max_sum + +if __name__ == "__main__": + n = int(input("Enter number of elements: ")) + arr = list(map(int, input("Enter the elements: ").split())) + print("Maximum Subarray Sum:", kadane(arr)) diff --git a/python/kmp_search.py b/python/kmp_search.py new file mode 100644 index 00000000..c929d70f --- /dev/null +++ b/python/kmp_search.py @@ -0,0 +1,55 @@ +def make_lps(P): + M = len(P) + lps = [0] * M + length = 0 + i = 1 + + while i < M: + if P[i] == P[length]: + length += 1 + lps[i] = length + i += 1 + else: + if length != 0: + length = lps[length - 1] + else: + lps[i] = 0 + i += 1 + return lps + +def kmp_find(T, P): + N = len(T) + M = len(P) + + if M == 0: + return [] + + lps = make_lps(P) + + i = 0 + j = 0 + occs = [] + + while i < N: + if P[j] == T[i]: + i += 1 + j += 1 + + if j == M: + occs.append(i - j) + j = lps[j - 1] + + elif i < N and P[j] != T[i]: + if j != 0: + j = lps[j - 1] + else: + i += 1 + + return occs + +# Example +text_str = "ABABDABACDABABCABAB" +pat = "ABABCABAB" +result = kmp_find(text_str, pat) + +print(f"Pattern found at: {result}") \ No newline at end of file diff --git a/python/knapsack_01.py b/python/knapsack_01.py new file mode 100644 index 00000000..a1d9f044 --- /dev/null +++ b/python/knapsack_01.py @@ -0,0 +1,17 @@ +def knapsack(weights, values, W): + n = len(weights) + dp = [[0] * (W + 1) for _ in range(n + 1)] + + for i in range(1, n + 1): + for w in range(1, W + 1): + if weights[i-1] <= w: + dp[i][w] = max(values[i-1] + dp[i-1][w - weights[i-1]], dp[i-1][w]) + else: + dp[i][w] = dp[i-1][w] + return dp[n][W] + +# Example usage +values = [60, 100, 120] +weights = [10, 20, 30] +W = 50 +print(f"Maximum value in knapsack: {knapsack(weights, values, W)}") diff --git a/python/knapsnack.py b/python/knapsnack.py new file mode 100644 index 00000000..2eb4365b --- /dev/null +++ b/python/knapsnack.py @@ -0,0 +1,26 @@ +wt=[5,10,20,30] +val=[200,120,80,60] +ratio=[] +value=0 +cap=20 +i=0 +k=0 +b=0 +h=0 +for i in range(4): + k=wt[i] + b=val[i] + h=b/k + ratio.append(h) + if cap>=wt[i]: + cap=cap-wt[i] + value=value+val[i] + print(value) + + else : + value=value+(ratio[i]*cap) + print(value) + break + +print(value) +print(ratio) diff --git a/python/kruskals_algorithm.py b/python/kruskals_algorithm.py new file mode 100644 index 00000000..fc3ab241 --- /dev/null +++ b/python/kruskals_algorithm.py @@ -0,0 +1,57 @@ +class DSU: + def __init__(self, nodes): + self.parent = {n: n for n in nodes} + self.rank = {n: 0 for n in nodes} + + def find(self, i): + if self.parent[i] == i: + return i + self.parent[i] = self.find(self.parent[i]) + return self.parent[i] + + def union(self, i, j): + root_i = self.find(i) + root_j = self.find(j) + + if root_i != root_j: + if self.rank[root_i] < self.rank[root_j]: + self.parent[root_i] = root_j + elif self.rank[root_i] > self.rank[root_j]: + self.parent[root_j] = root_i + else: + self.parent[root_j] = root_i + self.rank[root_i] += 1 + return True + return False + +def kruskals_mst(nodes, edges): + + # Edges are (weight, u, v) + edges.sort() + + dsu = DSU(nodes) + mst = [] + + for w, u, v in edges: + if dsu.union(u, v): + mst.append((u, v, w)) + + return mst + +# Example +# nodes: a list of all vertices +N = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] +# edges: a list of (weight, u, v) +E = [ + (4, 'A', 'B'), (8, 'A', 'H'), + (8, 'B', 'C'), (11, 'B', 'H'), + (7, 'C', 'D'), (4, 'C', 'F'), + (9, 'D', 'E'), (14, 'D', 'F'), + (10, 'E', 'F'), + (2, 'F', 'G'), + (1, 'G', 'H'), (6, 'G', 'I'), + (7, 'H', 'I') +] + +mst_kruskal = kruskals_mst(N, E) +print(f"\nKruskal's MST Edges: {mst_kruskal}") \ No newline at end of file diff --git a/python/kth_largest.py b/python/kth_largest.py new file mode 100644 index 00000000..bca66fb9 --- /dev/null +++ b/python/kth_largest.py @@ -0,0 +1,35 @@ +# Problem Statement + +# Given an unsorted array of integers nums and an integer k, find the k-th largest element in the array. +# The k-th largest element is the element that would appear in position len(nums) - k if the array were sorted in descending order. + +#Approach: +#We use a min-heap of size k to efficiently keep track of the k largest elements seen so far. + +# Steps: + +# ->Build a min-heap with the first k elements of the array. +# -> For each remaining element in nums[k:]: +# ->If the element is greater than the smallest in the heap (heap[0]), +# ->remove the smallest (heappop) and insert the new element (heappush). +# ->After processing all elements, the smallest element in the heap (heap[0]) is the k-th largest element. + +import heapq + +def KthLargest(nums, k): + + heap = nums[:k] + heapq.heapify(heap) #converts list to min-heap + + for num in nums[k:]: + if num > heap[0]: + heapq.heappushpop(heap, num) + + #at last root element is the kth-largest element + return heap[0] + + +nums = [3, 2, 3, 1, 2, 4, 5, 5, 6] +k = 4 +result = KthLargest(nums, k) +print(f"The {k}th largest element is:", result) diff --git a/python/lc_66_plusone.py b/python/lc_66_plusone.py new file mode 100644 index 00000000..1a46223e --- /dev/null +++ b/python/lc_66_plusone.py @@ -0,0 +1,6 @@ +class Solution: + def plusOne(self, digits: List[int]) -> List[int]: + result = int("".join(map(str, digits))) + result = result + 1 + re = list(map(int, str(result))) + return re \ No newline at end of file diff --git a/python/leetcode_contest/weekly_472.1.py b/python/leetcode_contest/weekly_472.1.py new file mode 100644 index 00000000..f1fff2e0 --- /dev/null +++ b/python/leetcode_contest/weekly_472.1.py @@ -0,0 +1,10 @@ +# 3718. Smallest Missing Multiple of K +# weekly contest 472, problem 1 + +class Solution: + def missingMultiple(self, nums: List[int], k: int) -> int: + s = set(nums) + current = k + while current in s: + current += k + return current diff --git a/python/letterCombinationsOfPhoneNumber.py b/python/letterCombinationsOfPhoneNumber.py new file mode 100644 index 00000000..86da6cd1 --- /dev/null +++ b/python/letterCombinationsOfPhoneNumber.py @@ -0,0 +1,53 @@ +# Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent. Return the answer in any order. + +# A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters. +def letterCombinations(digits): + """ + :type digits: str + :rtype: List[str] + """ + #here we use back tracking approach + + + if digits=="": + return [] + else: + + st="" + dic={ + 2:"abc", + 3:"def", + 4:"ghi", + 5:"jkl", + 6:"mno", + 7:"pqrs", + 8:"tuv", + 9:"wxyz" + } + # for i in digits: + # st+=dic[int(i)] + li=[] + + #this function will give combinations of letters + def combi(comb,start): + if len(comb)==len(digits): + li.append("".join(comb)) + return + + curdig=digits[start] + letters=dic[int(curdig)] + for l in letters: + + #add letter to comb and call function for next digit + comb.append(l) + combi(comb,start+1) + #after returning remove the letter from comb to make it ready for next letter + comb.pop() + + + + + + combi([],0) + + return li diff --git a/python/levelorder_bfs.py b/python/levelorder_bfs.py new file mode 100644 index 00000000..b028cb58 --- /dev/null +++ b/python/levelorder_bfs.py @@ -0,0 +1,15 @@ +from collections import deque + +def levelOrder(root): + if not root: + return + queue = deque([root]) + while queue: + node = queue.popleft() + print(node.val, end=" ") + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + +print("\nLevel Order:", end=" "); levelOrder(root) diff --git a/python/linear_search.py b/python/linear_search.py index f5e7febb..e69de29b 100644 --- a/python/linear_search.py +++ b/python/linear_search.py @@ -1,56 +0,0 @@ -def linear_search(arr, target): - """ - Linear search algorithm to find target in array - Time Complexity: O(n) - Space Complexity: O(1) - """ - for i in range(len(arr)): - if arr[i] == target: - return i - return -1 - -def linear_search_all_occurrences(arr, target): - """ - Find all occurrences of target in array - Time Complexity: O(n) - Space Complexity: O(k) where k is number of occurrences - """ - indices = [] - for i in range(len(arr)): - if arr[i] == target: - indices.append(i) - return indices - -def linear_search_with_count(arr, target): - """ - Linear search that returns index and count of comparisons - """ - comparisons = 0 - for i in range(len(arr)): - comparisons += 1 - if arr[i] == target: - return i, comparisons - return -1, comparisons - -# Test the functions -if __name__ == "__main__": - test_array = [3, 7, 1, 9, 4, 7, 2, 7, 5] - search_target = 7 - - # Basic linear search - result = linear_search(test_array, search_target) - print(f"Array: {test_array}") - print(f"Searching for: {search_target}") - - if result != -1: - print(f"First occurrence found at index: {result}") - else: - print("Target not found") - - # Find all occurrences - all_indices = linear_search_all_occurrences(test_array, search_target) - print(f"All occurrences at indices: {all_indices}") - - # Search with comparison count - index, count = linear_search_with_count(test_array, search_target) - print(f"Found at index {index} with {count} comparisons") \ No newline at end of file diff --git a/python/linkedlist.py b/python/linkedlist.py new file mode 100644 index 00000000..be28bf4c --- /dev/null +++ b/python/linkedlist.py @@ -0,0 +1,17 @@ +# Problem: Reverse a singly linked list. + +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + +def reverseList(head: ListNode): + prev, curr = None, head + while curr: + nxt = curr.next + curr.next = prev + prev, curr = curr, nxt + return prev + +# Input: 1 -> 2 -> 3 -> None +# Output: 3 -> 2 -> 1 -> None diff --git a/python/longest.py b/python/longest.py new file mode 100644 index 00000000..ea1a9d05 --- /dev/null +++ b/python/longest.py @@ -0,0 +1,13 @@ +def longestConsecutive(nums): + num_set = set(nums) + longest = 0 + + for n in num_set: + if n - 1 not in num_set: # new sequence start + length = 1 + while n + length in num_set: + length += 1 + longest = max(longest, length) + return longest + +print(longestConsecutive([100, 4, 200, 1, 3, 2])) diff --git a/python/longest_balanced_substring.py b/python/longest_balanced_substring.py new file mode 100644 index 00000000..e69de29b diff --git a/python/longest_palindromic_substring.py b/python/longest_palindromic_substring.py new file mode 100644 index 00000000..a447f0f9 --- /dev/null +++ b/python/longest_palindromic_substring.py @@ -0,0 +1,32 @@ +# longest_palindromic_substring.py +# Author: Garima Bisht +# This program finds the longest palindromic substring in a given string. + +def longest_palindrome(s: str) -> str: + if not s: + return "" + + start = 0 + end = 0 + + def expand_from_center(left: int, right: int) -> int: + while left >= 0 and right < len(s) and s[left] == s[right]: + left -= 1 + right += 1 + return right - left - 1 + + for i in range(len(s)): + len1 = expand_from_center(i, i) # Odd length palindrome + len2 = expand_from_center(i, i + 1) # Even length palindrome + max_len = max(len1, len2) + if max_len > end - start: + start = i - (max_len - 1) // 2 + end = i + max_len // 2 + + return s[start:end+1] + +# Example usage +if __name__ == "__main__": + test_string = "babad" + result = longest_palindrome(test_string) + print(f"Longest palindromic substring of '{test_string}' is: '{result}'") diff --git a/python/lowest_common_ancestor.py b/python/lowest_common_ancestor.py new file mode 100644 index 00000000..5c8c56a7 --- /dev/null +++ b/python/lowest_common_ancestor.py @@ -0,0 +1,38 @@ +class Node: + def __init__(self, key): + self.val = key + self.left = None + self.right = None + +def find_lca(root, n1, n2): + if root is None: + return None + + if root.val == n1 or root.val == n2: + return root + + left_lca = find_lca(root.left, n1, n2) + right_lca = find_lca(root.right, n1, n2) + + if left_lca and right_lca: + return root + + return left_lca if left_lca else right_lca + +# Example usage +root = Node(3) +root.left = Node(5) +root.right = Node(1) +root.left.left = Node(6) +root.left.right = Node(2) +root.right.left = Node(0) +root.right.right = Node(8) +root.left.right.left = Node(7) +root.left.right.right = Node(4) + +n1, n2 = 7, 4 +lca = find_lca(root, n1, n2) +if lca: + print(f"LCA of {n1} and {n2} is {lca.val}") +else: + print("LCA not found") diff --git a/python/m b/python/m new file mode 100644 index 00000000..e69de29b diff --git "a/python/manacher\342\200\231s_Algorithm.py" "b/python/manacher\342\200\231s_Algorithm.py" new file mode 100644 index 00000000..8b860453 --- /dev/null +++ "b/python/manacher\342\200\231s_Algorithm.py" @@ -0,0 +1,37 @@ +def manacher(s): + # Preprocess string + T = '#' + '#'.join(s) + '#' + n = len(T) + P = [0] * n # Palindrome radius array + C = 0 # Center of current palindrome + R = 0 # Right boundary of current palindrome + + for i in range(n): + mirr = 2*C - i # Mirror of i around center C + + if i < R: + P[i] = min(R - i, P[mirr]) + + # Expand around center i + a = i + P[i] + 1 + b = i - P[i] - 1 + while a < n and b >= 0 and T[a] == T[b]: + P[i] += 1 + a += 1 + b -= 1 + + # Update center and right boundary + if i + P[i] > R: + C = i + R = i + P[i] + + # Find maximum palindrome + max_len = max(P) + center_index = P.index(max_len) + start = (center_index - max_len)//2 # Index in original string + longest_palindrome = s[start: start + max_len] + return longest_palindrome + +# Example usage +s = "babad" +print("Longest Palindromic Substring:", manacher(s)) diff --git a/python/mathprob.py b/python/mathprob.py new file mode 100644 index 00000000..8733db28 --- /dev/null +++ b/python/mathprob.py @@ -0,0 +1,22 @@ +import math + +def solve_quadratic(a, b, c): + discriminant = b**2 - 4*a*c + + if discriminant > 0: + root1 = (-b + math.sqrt(discriminant)) / (2*a) + root2 = (-b - math.sqrt(discriminant)) / (2*a) + return f"Two real roots: {root1}, {root2}" + elif discriminant == 0: + root = -b / (2*a) + return f"One real root: {root}" + else: + real = -b / (2*a) + imaginary = math.sqrt(-discriminant) / (2*a) + return f"Two complex roots: {real}+{imaginary}i, {real}-{imaginary}i" + +a = float(input("Enter a: ")) +b = float(input("Enter b: ")) +c = float(input("Enter c: ")) + +print(solve_quadratic(a, b, c)) diff --git a/python/matrix_chain.py b/python/matrix_chain.py new file mode 100644 index 00000000..84582eca --- /dev/null +++ b/python/matrix_chain.py @@ -0,0 +1,34 @@ +import sys + +def matrix_chain_order(dims): + n = len(dims) - 1 + + # m[i][j] is the minimum number of scalar multiplications + # needed to compute the matrix product A[i..j] + m = [[0] * (n + 1) for _ in range(n + 1)] + + for length in range(2, n + 1): + for i in range(1, n - length + 2): + j = i + length - 1 + m[i][j] = sys.maxsize + + for k in range(i, j): + # q = multiplications needed for A[i..k] * A[k+1..j] + q = m[i][k] + m[k+1][j] + dims[i-1] * dims[k] * dims[j] + + if q < m[i][j]: + m[i][j] = q + + return m[1][n] + +# Example +# dims[0...n] represents the dimensions of n matrices: +# Matrix 1: dims[0] x dims[1] +# Matrix 2: dims[1] x dims[2] +# ... +# Matrix n: dims[n-1] x dims[n] +p = [10, 30, 5, 60] + +# Corresponds to 3 matrices: (10x30), (30x5), (5x60) +min_ops = matrix_chain_order(p) +print(f"Matrix Chain Multiplication Min Operations: {min_ops}") \ No newline at end of file diff --git a/python/max_depth_binarytree.py b/python/max_depth_binarytree.py new file mode 100644 index 00000000..3ae9a880 --- /dev/null +++ b/python/max_depth_binarytree.py @@ -0,0 +1,14 @@ +# Problem: Find the maximum depth of a binary tree. + +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +def maxDepth(root: TreeNode) -> int: + if not root: + return 0 + return 1 + max(maxDepth(root.left), maxDepth(root.right)) + + diff --git a/python/maximum_depth_of_binary_tree.py b/python/maximum_depth_of_binary_tree.py new file mode 100644 index 00000000..3bbb1b93 --- /dev/null +++ b/python/maximum_depth_of_binary_tree.py @@ -0,0 +1,14 @@ +class Solution(object): + def maxDepth(self, root): + + if not root: + return 0 + def m(node): + if not node: + return 0 + l=m(node.left) + r=m(node.right) + return 1+max(l,r) + return m(root) + + \ No newline at end of file diff --git a/python/maximumprodsubarray.py b/python/maximumprodsubarray.py new file mode 100644 index 00000000..c1afc783 --- /dev/null +++ b/python/maximumprodsubarray.py @@ -0,0 +1,25 @@ +from typing import List + +class Solution: + def maxProduct(self, nums: List[int]) -> int: + """ + Finds the contiguous subarray within an array that has the largest product. + """ + if not nums: + return 0 + max_so_far = nums[0] + min_so_far = nums[0] + result = nums[0] + + for i in range(1, len(nums)): + current = nums[i] + + temp_max = max_so_far + + max_so_far = max(current, max_so_far * current, min_so_far * current) + + min_so_far = min(current, temp_max * current, min_so_far * current) + + result = max(result, max_so_far) + + return result \ No newline at end of file diff --git a/python/maxof.py b/python/maxof.py new file mode 100644 index 00000000..92639a5f --- /dev/null +++ b/python/maxof.py @@ -0,0 +1,4 @@ +def max_of_two_numbers(a, b): + return a if a > b else b + +print(max_of_two_numbers(max_of_two_numbers(10, 20), max_of_two_numbers(-5, -10))) \ No newline at end of file diff --git a/python/maxprouct.py b/python/maxprouct.py new file mode 100644 index 00000000..e9d36301 --- /dev/null +++ b/python/maxprouct.py @@ -0,0 +1,24 @@ +class Solution(object): + def maxProduct(self, nums): + """ + :type nums: List[int] + :rtype: int + """ + if not nums: + return 0 + + max_prod = min_prod = result = nums[0] + + for i in range(1, len(nums)): + num = nums[i] + + # Calculate the maximum and minimum product up to the current position + temp_max = max(num, max_prod * num, min_prod * num) + min_prod = min(num, max_prod * num, min_prod * num) + + max_prod = temp_max + + # Update the result with the maximum product found so far + result = max(result, max_prod) + + return result diff --git a/python/maze_solver.py b/python/maze_solver.py new file mode 100644 index 00000000..345bd14d --- /dev/null +++ b/python/maze_solver.py @@ -0,0 +1,36 @@ +def is_safe(maze, x, y, n): + return 0 <= x < n and 0 <= y < n and maze[x][y] == 1 + +def solve_maze_util(maze, x, y, sol, n): + if x == n - 1 and y == n - 1: + sol[x][y] = 1 + return True + + if is_safe(maze, x, y, n): + sol[x][y] = 1 + if solve_maze_util(maze, x + 1, y, sol, n): + return True + if solve_maze_util(maze, x, y + 1, sol, n): + return True + sol[x][y] = 0 + return False + +def solve_maze(maze): + n = len(maze) + sol = [[0 for _ in range(n)] for _ in range(n)] + + if solve_maze_util(maze, 0, 0, sol, n): + for row in sol: + print(row) + else: + print("No path found") + +# Example maze +maze = [ + [1, 0, 0, 0], + [1, 1, 0, 1], + [0, 1, 0, 0], + [1, 1, 1, 1] +] + +solve_maze(maze) diff --git a/python/merge_sort.py b/python/merge_sort.py index 4799ea79..c594b3fc 100644 --- a/python/merge_sort.py +++ b/python/merge_sort.py @@ -1,112 +1,73 @@ -def merge_sort(arr): +import doctest +from typing import List, TypeVar + +# A generic type for comparable elements +T = TypeVar('T') + + +def merge_sort(arr: List[T]) -> List[T]: """ - Merge sort algorithm implementation - Time Complexity: O(n log n) - Space Complexity: O(n) + Sorts a list in ascending order using the Merge Sort algorithm. + + This function is not in-place; it returns a new sorted list, leaving + the original list unmodified. + + Args: + arr: A list of comparable elements. + + Returns: + A new list containing the sorted elements. + + Examples: + >>> merge_sort([38, 27, 43, 3, 9, 82, 10]) + [3, 9, 10, 27, 38, 43, 82] + >>> merge_sort([]) + [] + >>> merge_sort([5]) + [5] + >>> merge_sort([10, 9, 8, 7, 6]) + [6, 7, 8, 9, 10] """ + # Base case: A list with 0 or 1 element is already sorted if len(arr) <= 1: return arr - - # Divide the array into two halves + + # 1. Divide: Find the middle and split the list into two halves mid = len(arr) // 2 left_half = arr[:mid] right_half = arr[mid:] - - # Recursively sort both halves - left_sorted = merge_sort(left_half) - right_sorted = merge_sort(right_half) - - # Merge the sorted halves - return merge(left_sorted, right_sorted) - -def merge(left, right): - """ - Merge two sorted arrays into one sorted array - """ - result = [] - i = j = 0 - - # Compare elements from both arrays and merge - while i < len(left) and j < len(right): - if left[i] <= right[j]: - result.append(left[i]) - i += 1 - else: - result.append(right[j]) - j += 1 - - # Add remaining elements from left array - while i < len(left): - result.append(left[i]) - i += 1 - - # Add remaining elements from right array - while j < len(right): - result.append(right[j]) - j += 1 - - return result - -def merge_sort_inplace(arr, left=0, right=None): - """ - In-place merge sort implementation - """ - if right is None: - right = len(arr) - 1 - - if left < right: - mid = (left + right) // 2 - - # Sort first and second halves - merge_sort_inplace(arr, left, mid) - merge_sort_inplace(arr, mid + 1, right) - - # Merge the sorted halves - merge_inplace(arr, left, mid, right) - -def merge_inplace(arr, left, mid, right): - """ - Merge function for in-place merge sort - """ - # Create temporary arrays for left and right subarrays - left_arr = arr[left:mid + 1] - right_arr = arr[mid + 1:right + 1] - - i = j = 0 - k = left - - # Merge the temporary arrays back into arr[left..right] - while i < len(left_arr) and j < len(right_arr): - if left_arr[i] <= right_arr[j]: - arr[k] = left_arr[i] - i += 1 + + # 2. Conquer: Recursively sort both halves + sorted_left = merge_sort(left_half) + sorted_right = merge_sort(right_half) + + # 3. Combine: Merge the two sorted halves + merged_array = [] + left_pointer, right_pointer = 0, 0 + + while left_pointer < len(sorted_left) and right_pointer < len(sorted_right): + if sorted_left[left_pointer] < sorted_right[right_pointer]: + merged_array.append(sorted_left[left_pointer]) + left_pointer += 1 else: - arr[k] = right_arr[j] - j += 1 - k += 1 - - # Copy remaining elements of left_arr - while i < len(left_arr): - arr[k] = left_arr[i] - i += 1 - k += 1 - - # Copy remaining elements of right_arr - while j < len(right_arr): - arr[k] = right_arr[j] - j += 1 - k += 1 - -# Test the functions + merged_array.append(sorted_right[right_pointer]) + right_pointer += 1 + + # Append any remaining elements from the left or right half + merged_array.extend(sorted_left[left_pointer:]) + merged_array.extend(sorted_right[right_pointer:]) + + return merged_array + + if __name__ == "__main__": - numbers = [38, 27, 43, 3, 9, 82, 10] - print(f"Original array: {numbers}") - - # Test regular merge sort - sorted_numbers = merge_sort(numbers.copy()) - print(f"Sorted array (merge sort): {sorted_numbers}") - - # Test in-place merge sort - inplace_numbers = numbers.copy() - merge_sort_inplace(inplace_numbers) - print(f"Sorted array (in-place): {inplace_numbers}") \ No newline at end of file + # Run the embedded doctests to verify the function's correctness + doctest.testmod() + + # --- Example Usage --- + original_list = [38, 27, 43, 3, 9, 82, 10] + print(f"Original list: {original_list}") + + sorted_list = merge_sort(original_list) + print(f"New sorted list: {sorted_list}") + print(f"Original list remains unchanged: {original_list}") \ No newline at end of file diff --git a/python/merge_soted_array.py b/python/merge_soted_array.py new file mode 100644 index 00000000..ccb55965 --- /dev/null +++ b/python/merge_soted_array.py @@ -0,0 +1,22 @@ +num1 = [1,2,3,0,0,0] +num2 = [2,5,6] +m = 3 +n = 3 +left = 0 +right = 0 +result = [] +while left < m and right < n: + if num1[left] < num2[right]: + result.append(num1[left]) + left+=1 + else: + result.append(num2[right]) + right+=1 +while left < m: + result.append(num1[left]) + left+=1 +while right < n: + result.append(num2[right]) + right+=1 +for i in range(m+n): + num1[i] = result[i] \ No newline at end of file diff --git a/python/min_number.py b/python/min_number.py new file mode 100644 index 00000000..29b44139 --- /dev/null +++ b/python/min_number.py @@ -0,0 +1,13 @@ +class Solution(object): + def minNumberOperations(self, target): + """ + :type target: List[int] + :rtype: int + """ + operations = target[0] + + for i in range(1, len(target)): + if target[i] > target[i-1]: + operations += target[i] - target[i-1] + + return operations \ No newline at end of file diff --git a/python/min_parentheses.py b/python/min_parentheses.py new file mode 100644 index 00000000..0c6ab38d --- /dev/null +++ b/python/min_parentheses.py @@ -0,0 +1,31 @@ +class Solution: + def minParentheses(self, s: str) -> int: + stack = [] + ans = 0 + for e in s: + if e == "(": + stack.append(e) + else: # e == ")" + if stack: + stack.pop() + else: + ans += 1 + ans += len(stack) + return ans + + +# ✅ Testing +if __name__ == "__main__": + obj = Solution() + + # Example test cases + test_cases = [ + "())", # needs 1 "(" + "(((", # needs 3 ")" + ")))", # needs 3 "(" + "()()", # already balanced + "(()))(", # needs 2 + ] + + for s in test_cases: + print(f"Input: {s} -> Min insertions needed: {obj.minParentheses(s)}") diff --git a/python/min_time_brew_potions.py b/python/min_time_brew_potions.py new file mode 100644 index 00000000..e96c85e3 --- /dev/null +++ b/python/min_time_brew_potions.py @@ -0,0 +1,12 @@ +class Solution: + def minTime(self, skill: List[int], mana: List[int]) -> int: + n, m = len(skill), len(mana) + done = [0] * (n + 1) + + for j in range(m): + for i in range(n): + done[i + 1] = max(done[i + 1], done[i]) + mana[j] * skill[i] + for i in range(n - 1, 0, -1): + done[i] = done[i + 1] - mana[j] * skill[i] + + return done[n] diff --git a/python/minimum_steps_to_equalize_towers.py b/python/minimum_steps_to_equalize_towers.py new file mode 100644 index 00000000..e69de29b diff --git a/python/minimum_window_substring.py b/python/minimum_window_substring.py new file mode 100644 index 00000000..8862d302 --- /dev/null +++ b/python/minimum_window_substring.py @@ -0,0 +1,28 @@ +# Minimum Window Substring + +from collections import Counter + +def minWindow(s: str, t: str) -> str: + if not t or not s: + return "" + need = Counter(t) + missing = len(t) + left = start = end = 0 + for right, ch in enumerate(s, 1): + if need[ch] > 0: + missing -= 1 + need[ch] -= 1 + if missing == 0: + while left < right and need[s[left]] < 0: + need[s[left]] += 1 + left += 1 + if end == 0 or right - left <= end - start: + start, end = left, right + need[s[left]] += 1 + missing += 1 + left += 1 + return s[start:end] + +s = "ADOBECODEBANC" +t = "ABC" +print(minWindow(s, t)) diff --git a/python/multiplystrings.py b/python/multiplystrings.py new file mode 100644 index 00000000..0261a421 --- /dev/null +++ b/python/multiplystrings.py @@ -0,0 +1,19 @@ +def multiplyStrings(num1, num2): + if num1 == "0" or num2 == "0": + return "0" + res = [0] * (len(num1) + len(num2)) + + num1, num2 = num1[::-1], num2[::-1] + + for i in range(len(num1)): + for j in range(len(num2)): + res[i+j] += int(num1[i]) * int(num2[j]) + if res[i+j] >= 10: + res[i+j+1] += res[i+j] // 10 + res[i+j] %= 10 + + while len(res) > 1 and res[-1] == 0: + res.pop() + return ''.join(map(str, res[::-1])) + +print(multiplyStrings("123", "45")) diff --git a/python/n_queens_problem.py b/python/n_queens_problem.py new file mode 100644 index 00000000..1f841606 --- /dev/null +++ b/python/n_queens_problem.py @@ -0,0 +1,39 @@ +def print_board(board): + for row in board: + print(" ".join("Q" if cell else "." for cell in row)) + print() + +def is_safe(board, row, col, n): + for i in range(row): + if board[i][col] == 1: + return False + i, j = row - 1, col - 1 + while i >= 0 and j >= 0: + if board[i][j] == 1: + return False + i -= 1 + j -= 1 + i, j = row - 1, col + 1 + while i >= 0 and j < n: + if board[i][j] == 1: + return False + i -= 1 + j += 1 + return True + +def solve_n_queens(board, row, n): + if row == n: + print_board(board) + return True + + res = False + for col in range(n): + if is_safe(board, row, col, n): + board[row][col] = 1 + res = solve_n_queens(board, row + 1, n) or res + board[row][col] = 0 + return res + +n = 4 +board = [[0 for _ in range(n)] for _ in range(n)] +solve_n_queens(board, 0, n) diff --git a/python/numprime.py b/python/numprime.py new file mode 100644 index 00000000..249e44be --- /dev/null +++ b/python/numprime.py @@ -0,0 +1,14 @@ +num = int(input("Enter a number: ")) + +if num <= 1: + print(num, "is not prime") +else: + is_prime = True + for i in range(2, int(num**0.5)+1): + if num % i == 0: + is_prime = False + break + if is_prime: + print(num, "is prime") + else: + print(num, "is not prime") diff --git a/python/pacificAtlanticWaterFlow.py b/python/pacificAtlanticWaterFlow.py new file mode 100644 index 00000000..e32025b0 --- /dev/null +++ b/python/pacificAtlanticWaterFlow.py @@ -0,0 +1,36 @@ +# Leetcode problem 417. Pacific Atlantic Water Flow + +class Solution(object): + def pacificAtlantic(self, heights): + """ + :type heights: List[List[int]] + :rtype: List[List[int]] + """ + rows,cols=len(heights),len(heights[0]) + pac,atl =set(),set() + + def search(r,c,visit,prev): + if((r,c) in visit or r<0 or c<0 or r==rows or c==cols or heights[r][c] 0: - reversed_num = reversed_num * 10 + num % 10 - num //= 10 - - return original == reversed_num - -def longest_palindrome_substring(s): - """ - Find the longest palindromic substring - Time Complexity: O(n²) - Space Complexity: O(1) - """ - if not s: - return "" - - start = 0 - max_len = 1 - - for i in range(len(s)): - # Check for odd length palindromes - left, right = i, i - while left >= 0 and right < len(s) and s[left] == s[right]: - current_len = right - left + 1 - if current_len > max_len: - start = left - max_len = current_len - left -= 1 - right += 1 - - # Check for even length palindromes - left, right = i, i + 1 - while left >= 0 and right < len(s) and s[left] == s[right]: - current_len = right - left + 1 - if current_len > max_len: - start = left - max_len = current_len - left -= 1 - right += 1 - - return s[start:start + max_len] - -# Test the functions -if __name__ == "__main__": - # Test string palindrome - test_strings = ["racecar", "A man a plan a canal Panama", "hello", "Madam"] - print("String Palindrome Tests:") - for string in test_strings: - result = is_palindrome_string(string) - print(f"'{string}' is palindrome: {result}") - - print("\nNumber Palindrome Tests:") - test_numbers = [121, 12321, 123, -121, 0] - for num in test_numbers: - result = is_palindrome_number(num) - print(f"{num} is palindrome: {result}") - - print("\nLongest Palindrome Substring Tests:") - test_strings = ["babad", "cbbd", "racecar", "abcdef"] - for string in test_strings: - result = longest_palindrome_substring(string) - print(f"Longest palindrome in '{string}': '{result}'") \ No newline at end of file diff --git a/python/palindrome_number.py b/python/palindrome_number.py new file mode 100644 index 00000000..f1239809 --- /dev/null +++ b/python/palindrome_number.py @@ -0,0 +1,11 @@ +x = 121 +n = x +rev = 0 +while n > 0: + digit = n % 10 + rev = rev * 10 + digit + n = n // 10 +if x == rev: + print("Number is Palindrome") +else: + print("Number is not palindrome") \ No newline at end of file diff --git a/python/palindrome_numer.py b/python/palindrome_numer.py new file mode 100644 index 00000000..ee3e14f3 --- /dev/null +++ b/python/palindrome_numer.py @@ -0,0 +1,15 @@ +# Palindrome Number +# Given an integer x, return true if x is a palindrome, and false otherwise. + +class Solution(object): + def isPalindrome(self,x): + x = str(x) + return x == x[::-1] + +# Example Usage + +if __name__ == "__main__": + s = Solution() + print(s.isPalindrome(121)) # Prints True + print(s.isPalindrome(-121)) # Prints False + print(s.isPalindrome(10)) # Prints False \ No newline at end of file diff --git a/python/palindrome_pattern.py b/python/palindrome_pattern.py new file mode 100644 index 00000000..797cc445 --- /dev/null +++ b/python/palindrome_pattern.py @@ -0,0 +1,60 @@ +"""Palindrome pattern generator + +Provides a function `generate_palindrome_pattern(n)` which returns a list of +strings representing a numeric palindrome pyramid with `n` rows, and a small +CLI to print the pattern. + +Example for n=4: + + 1 + 121 + 12321 +1234321 + +Each row has leading spaces so the pyramid is centered on the left edge. +""" +from typing import List + + +def generate_palindrome_pattern(n: int) -> List[str]: + """Generate a palindrome number pattern with n rows. + + Args: + n: number of rows (must be a positive integer) + + Returns: + A list of strings, each string is one line of the pattern. + + Raises: + ValueError: if n is not a positive integer. + """ + if not isinstance(n, int) or n < 1: + raise ValueError("n must be a positive integer (>=1)") + + lines: List[str] = [] + for row in range(1, n + 1): + # leading spaces + spaces = " " * (n - row) + # increasing part 1..row + inc = "".join(str(i) for i in range(1, row + 1)) + # decreasing part row-1..1 + dec = "".join(str(i) for i in range(row - 1, 0, -1)) + lines.append(f"{spaces}{inc}{dec}") + + return lines + + +def main() -> None: + """Simple CLI: read an integer from command-line and print the pattern.""" + import argparse + + parser = argparse.ArgumentParser(description="Print palindrome number pattern") + parser.add_argument("n", type=int, nargs="?", default=5, help="number of rows (default: 5)") + args = parser.parse_args() + + for line in generate_palindrome_pattern(args.n): + print(line) + + +if __name__ == "__main__": + main() diff --git a/python/pancake_sort.py b/python/pancake_sort.py new file mode 100644 index 00000000..66c6ab32 --- /dev/null +++ b/python/pancake_sort.py @@ -0,0 +1,37 @@ +def reverse_prefix(number_list, end_index): + start_index = 0 + while start_index < end_index: + number_list[start_index], number_list[end_index] = number_list[end_index], number_list[start_index] + start_index += 1 + end_index -= 1 + +def pancake_sort(numbers): + num_elements = len(numbers) + + for unsorted_size in range(num_elements, 1, -1): + + sub_list = numbers[:unsorted_size] + index_of_max = sub_list.index(max(sub_list)) + + last_index_of_unsorted = unsorted_size - 1 + + if index_of_max != last_index_of_unsorted: + + if index_of_max != 0: + reverse_prefix(numbers, index_of_max) + reverse_prefix(numbers, last_index_of_unsorted) + + return numbers + +first_list = [23, 10, 20, 11, 12, 6, 7] +print(f"Original: {first_list}") + +pancake_sort(first_list) +print(f"Sorted: {first_list}") + + +second_list = [5, 2, 8, 1, 9, 4] +print(f"\nOriginal: {second_list}") + +sorted_list = pancake_sort(second_list) +print(f"Sorted: {sorted_list}") \ No newline at end of file diff --git a/python/power.py b/python/power.py new file mode 100644 index 00000000..9accc871 --- /dev/null +++ b/python/power.py @@ -0,0 +1,6 @@ +a = int(input()) +b = int(input()) +m = int(input()) + +print(pow(a, b)) +print(pow(a, b, m)) \ No newline at end of file diff --git a/python/prefix_sum.py b/python/prefix_sum.py new file mode 100644 index 00000000..0d63f0a0 --- /dev/null +++ b/python/prefix_sum.py @@ -0,0 +1,23 @@ +def range_sum_prefix(nums, queries): + # Step 1: Precompute the prefix sum array + n = len(nums) + prefix = [0] * n + prefix[0] = nums[0] + for i in range(1, n): + prefix[i] = prefix[i - 1] + nums[i] + + # Step 2: Answer each query in O(1) + results = [] + for l, r in queries: + if l == 0: + results.append(prefix[r]) # sum from start to r + else: + results.append(prefix[r] - prefix[l - 1]) # subtract prefix before l + return results + + +# Example usage +nums = [1, 2, 3, 4, 5] # array +queries = [(0, 2), (1, 3), (2, 4)] + +print(range_sum_prefix(nums, queries)) diff --git a/python/prims_algorithm.py b/python/prims_algorithm.py new file mode 100644 index 00000000..b3cb0819 --- /dev/null +++ b/python/prims_algorithm.py @@ -0,0 +1,44 @@ +import heapq + +def prims_mst(graph): + V = list(graph.keys()) + if not V: + return [] + + start = V[0] + visited = {start} + mst = [] + + # Priority queue stores (weight, u, v) + edges = [(w, start, v) for v, w in graph.get(start, [])] + heapq.heapify(edges) + + while edges and len(mst) < len(V) - 1: + w, u, v = heapq.heappop(edges) + + if v not in visited: + visited.add(v) + mst.append((u, v, w)) + + for neighbor, weight in graph.get(v, []): + if neighbor not in visited: + heapq.heappush(edges, (weight, v, neighbor)) + + return mst + +# Example +# Graph represented as an adjacency list: {node: [(neighbor, weight), ...]} +G = { + 'A': [('B', 4), ('H', 8)], + 'B': [('A', 4), ('C', 8), ('H', 11)], + 'C': [('B', 8), ('D', 7), ('F', 4)], + 'D': [('C', 7), ('E', 9), ('F', 14)], + 'E': [('D', 9), ('F', 10)], + 'F': [('C', 4), ('D', 14), ('E', 10), ('G', 2)], + 'G': [('F', 2), ('H', 1), ('I', 6)], + 'H': [('A', 8), ('B', 11), ('G', 1), ('I', 7)], + 'I': [('G', 6), ('H', 7)] +} + +mst_edges = prims_mst(G) +print(f"Prim's MST Edges: {mst_edges}") \ No newline at end of file diff --git a/python/python password_generator.py b/python/python password_generator.py new file mode 100644 index 00000000..61040ef7 --- /dev/null +++ b/python/python password_generator.py @@ -0,0 +1,12 @@ +# password_generator.py +import random +import string + +def generate_password(length=12): + characters = string.ascii_letters + string.digits + string.punctuation + password = ''.join(random.choice(characters) for _ in range(length)) + return password + +if __name__ == "__main__": + length = int(input("Enter password length: ")) + print("Generated Password:", generate_password(length)) diff --git a/python/python_hashmap.py b/python/python_hashmap.py new file mode 100644 index 00000000..e69de29b diff --git a/python/queue_using_stack.py b/python/queue_using_stack.py new file mode 100644 index 00000000..ed8e03ec --- /dev/null +++ b/python/queue_using_stack.py @@ -0,0 +1,22 @@ +# Problem: Implement a queue using two stacks. + +class MyQueue: + def __init__(self): + self.stack1 = [] + self.stack2 = [] + + def push(self, x): + self.stack1.append(x) + + def pop(self): + self.peek() + return self.stack2.pop() + + def peek(self): + if not self.stack2: + while self.stack1: + self.stack2.append(self.stack1.pop()) + return self.stack2[-1] + + def empty(self): + return not self.stack1 and not self.stack2 diff --git a/python/quick_sort.py b/python/quick_sort.py new file mode 100644 index 00000000..d85ef1f1 --- /dev/null +++ b/python/quick_sort.py @@ -0,0 +1,117 @@ +def quick_sort(arr): + """ + Quick sort algorithm implementation + Time Complexity: O(n log n) average, O(n²) worst case + Space Complexity: O(log n) + """ + if len(arr) <= 1: + return arr + + pivot = arr[len(arr) // 2] + left = [x for x in arr if x < pivot] + middle = [x for x in arr if x == pivot] + right = [x for x in arr if x > pivot] + + return quick_sort(left) + middle + quick_sort(right) + +def quick_sort_inplace(arr, low=0, high=None): + """ + In-place quick sort implementation + """ + if high is None: + high = len(arr) - 1 + + if low < high: + # Partition the array and get pivot index + pivot_index = partition(arr, low, high) + + # Sort elements before and after partition + quick_sort_inplace(arr, low, pivot_index - 1) + quick_sort_inplace(arr, pivot_index + 1, high) + +def partition(arr, low, high): + """ + Partition function for quick sort + Uses last element as pivot + """ + pivot = arr[high] + i = low - 1 # Index of smaller element + + for j in range(low, high): + # If current element is smaller than or equal to pivot + if arr[j] <= pivot: + i += 1 + arr[i], arr[j] = arr[j], arr[i] + + arr[i + 1], arr[high] = arr[high], arr[i + 1] + return i + 1 + +def quick_sort_random_pivot(arr, low=0, high=None): + """ + Quick sort with random pivot selection + Better average case performance + """ + import random + + if high is None: + high = len(arr) - 1 + + if low < high: + # Choose random pivot and swap with last element + random_index = random.randint(low, high) + arr[random_index], arr[high] = arr[high], arr[random_index] + + pivot_index = partition(arr, low, high) + quick_sort_random_pivot(arr, low, pivot_index - 1) + quick_sort_random_pivot(arr, pivot_index + 1, high) + +def quick_select(arr, k): + """ + Quick select algorithm to find kth smallest element + Time Complexity: O(n) average case + """ + if not arr: + return None + + pivot = arr[len(arr) // 2] + left = [x for x in arr if x < pivot] + middle = [x for x in arr if x == pivot] + right = [x for x in arr if x > pivot] + + if k < len(left): + return quick_select(left, k) + elif k < len(left) + len(middle): + return pivot + else: + return quick_select(right, k - len(left) - len(middle)) + +# Test the functions +if __name__ == "__main__": + # Test quick sort + numbers = [64, 34, 25, 12, 22, 11, 90] + print(f"Original array: {numbers}") + + sorted_numbers = quick_sort(numbers.copy()) + print(f"Quick sorted: {sorted_numbers}") + + # Test in-place quick sort + inplace_numbers = numbers.copy() + quick_sort_inplace(inplace_numbers) + print(f"In-place quick sorted: {inplace_numbers}") + + # Test random pivot quick sort + random_numbers = numbers.copy() + quick_sort_random_pivot(random_numbers) + print(f"Random pivot sorted: {random_numbers}") + + # Test quick select + test_array = [3, 6, 8, 10, 1, 2, 1] + k = 3 + kth_smallest = quick_select(test_array, k - 1) # k-1 for 0-based indexing + print(f"\n{k}rd smallest element in {test_array}: {kth_smallest}") + + # Find median using quick select + sorted_test = sorted(test_array) + median_index = len(test_array) // 2 + median = quick_select(test_array, median_index) + print(f"Median of {sorted_test}: {median}") diff --git a/python/red_black_tree.py b/python/red_black_tree.py new file mode 100644 index 00000000..e59bf544 --- /dev/null +++ b/python/red_black_tree.py @@ -0,0 +1,403 @@ +"""Complexity: Insert/Delete/Search: O(log n), Space: O(n)""" + +RED = True +BLACK = False + +class Node: + def __init__(self, data): + self.data = data + self.color = RED + self.left = None + self.right = None + self.parent = None + +class RedBlackTree: + def __init__(self): + self.TNULL = Node(0) + self.TNULL.color = BLACK + self.root = self.TNULL + + def _left_rotate(self, x): + y = x.right + x.right = y.left + if y.left != self.TNULL: + y.left.parent = x + y.parent = x.parent + if x.parent is None: + self.root = y + elif x == x.parent.left: + x.parent.left = y + else: + x.parent.right = y + y.left = x + x.parent = y + + def _right_rotate(self, x): + y = x.left + x.left = y.right + if y.right != self.TNULL: + y.right.parent = x + y.parent = x.parent + if x.parent is None: + self.root = y + elif x == x.parent.right: + x.parent.right = y + else: + x.parent.left = y + y.right = x + x.parent = y + + def insert(self, key): + """Insert a key into the Red-Black Tree""" + if not isinstance(key, (int, float)): + raise ValueError("Key must be a number") + + node = Node(key) + node.left = self.TNULL + node.right = self.TNULL + + y = None + x = self.root + + while x != self.TNULL: + y = x + if node.data < x.data: + x = x.left + else: + x = x.right + node.parent = y + if y is None: + self.root = node + elif node.data < y.data: + y.left = node + else: + y.right = node + + if node.parent is None: + node.color = BLACK + return + + if node.parent.parent is None: + return + + self._fix_insert(node) + + def _fix_insert(self, k): + while k.parent and k.parent.color == RED: + if k.parent == k.parent.parent.right: + u = k.parent.parent.left # uncle + if u and u.color == RED: + u.color = BLACK + k.parent.color = BLACK + k.parent.parent.color = RED + k = k.parent.parent + else: + if k == k.parent.left: + k = k.parent + self._right_rotate(k) + k.parent.color = BLACK + k.parent.parent.color = RED + self._left_rotate(k.parent.parent) + else: + u = k.parent.parent.right + if u and u.color == RED: + u.color = BLACK + k.parent.color = BLACK + k.parent.parent.color = RED + k = k.parent.parent + else: + if k == k.parent.right: + k = k.parent + self._left_rotate(k) + k.parent.color = BLACK + k.parent.parent.color = RED + self._right_rotate(k.parent.parent) + if k == self.root: + break + self.root.color = BLACK + + def search(self, key): + """Search for a key in the tree. Returns Node if found, None otherwise.""" + if not isinstance(key, (int, float)): + raise ValueError("Key must be a number") + return self._search_helper(self.root, key) + + def _search_helper(self, node, key): + if node == self.TNULL or key == node.data: + return node if node != self.TNULL else None + if key < node.data: + return self._search_helper(node.left, key) + return self._search_helper(node.right, key) + + def delete(self, key): + """Delete a key from the tree""" + if not isinstance(key, (int, float)): + raise ValueError("Key must be a number") + + node = self.search(key) + if node is None: + print(f"Key {key} not found in the tree") + return + + self._delete_node(node) + + def _delete_node(self, node): + # Find the node to delete + z = node + y = z + y_original_color = y.color + + if z.left == self.TNULL: + x = z.right + self._rb_transplant(z, z.right) + elif z.right == self.TNULL: + x = z.left + self._rb_transplant(z, z.left) + else: + y = self._minimum(z.right) + y_original_color = y.color + x = y.right + + if y.parent == z: + if x != self.TNULL: + x.parent = y + else: + self._rb_transplant(y, y.right) + y.right = z.right + y.right.parent = y + + self._rb_transplant(z, y) + y.left = z.left + y.left.parent = y + y.color = z.color + + if y_original_color == BLACK: + self._fix_delete(x) + + def _rb_transplant(self, u, v): + if u.parent is None: + self.root = v + elif u == u.parent.left: + u.parent.left = v + else: + u.parent.right = v + if v != self.TNULL: + v.parent = u.parent + + def _minimum(self, node): + while node.left != self.TNULL: + node = node.left + return node + + def _fix_delete(self, x): + while x != self.root and x.color == BLACK: + if x == x.parent.left: + s = x.parent.right + if s.color == RED: + s.color = BLACK + x.parent.color = RED + self._left_rotate(x.parent) + s = x.parent.right + + if s.left.color == BLACK and s.right.color == BLACK: + s.color = RED + x = x.parent + else: + if s.right.color == BLACK: + s.left.color = BLACK + s.color = RED + self._right_rotate(s) + s = x.parent.right + + s.color = x.parent.color + x.parent.color = BLACK + s.right.color = BLACK + self._left_rotate(x.parent) + x = self.root + else: + s = x.parent.left + if s.color == RED: + s.color = BLACK + x.parent.color = RED + self._right_rotate(x.parent) + s = x.parent.left + + if s.right.color == BLACK and s.left.color == BLACK: + s.color = RED + x = x.parent + else: + if s.left.color == BLACK: + s.right.color = BLACK + s.color = RED + self._left_rotate(s) + s = x.parent.left + + s.color = x.parent.color + x.parent.color = BLACK + s.left.color = BLACK + self._right_rotate(x.parent) + x = self.root + + if x != self.TNULL: + x.color = BLACK + + def get_min(self, node=None): + """Get minimum value in the tree""" + if node is None: + node = self.root + if node == self.TNULL: + return None + while node.left != self.TNULL: + node = node.left + return node.data + + def get_max(self, node=None): + """Get maximum value in the tree""" + if node is None: + node = self.root + if node == self.TNULL: + return None + while node.right != self.TNULL: + node = node.right + return node.data + + def height(self, node=None): + """Calculate height of the tree""" + if node is None: + node = self.root + if node == self.TNULL: + return 0 + return 1 + max(self.height(node.left), self.height(node.right)) + + def inorder(self, node=None): + """Inorder traversal of the tree""" + if node is None: + node = self.root + if node != self.TNULL: + self.inorder(node.left) + print(f"{node.data} ({'R' if node.color else 'B'})", end=" ") + self.inorder(node.right) + + def preorder(self, node=None): + """Preorder traversal of the tree""" + if node is None: + node = self.root + if node != self.TNULL: + print(f"{node.data} ({'R' if node.color else 'B'})", end=" ") + self.preorder(node.left) + self.preorder(node.right) + + def postorder(self, node=None): + """Postorder traversal of the tree""" + if node is None: + node = self.root + if node != self.TNULL: + self.postorder(node.left) + self.postorder(node.right) + print(f"{node.data} ({'R' if node.color else 'B'})", end=" ") + + def level_order(self): + """Level order traversal of the tree""" + if self.root == self.TNULL: + return + + queue = [self.root] + while queue: + node = queue.pop(0) + print(f"{node.data} ({'R' if node.color else 'B'})", end=" ") + if node.left != self.TNULL: + queue.append(node.left) + if node.right != self.TNULL: + queue.append(node.right) + + def is_empty(self): + """Check if the tree is empty""" + return self.root == self.TNULL + + def size(self, node=None): + """Get the number of nodes in the tree""" + if node is None: + node = self.root + if node == self.TNULL: + return 0 + return 1 + self.size(node.left) + self.size(node.right) + + def _print_tree(self, node, indent, last): + """Helper function for pretty printing the tree""" + if node != self.TNULL: + print(indent, end="") + if last: + print("R----", end="") + indent += " " + else: + print("L----", end="") + indent += "| " + + color_str = "RED" if node.color else "BLACK" + print(f"{node.data} ({color_str})") + self._print_tree(node.left, indent, False) + self._print_tree(node.right, indent, True) + + def print_tree(self): + """Pretty print the tree structure""" + if self.root != self.TNULL: + self._print_tree(self.root, "", True) + else: + print("Tree is empty") + +def demo_red_black_tree(): + """Demonstrate the Red-Black Tree functionality""" + print("=== Red-Black Tree Demonstration ===\n") + + # Create tree + bst = RedBlackTree() + + # Insert data + data = [7, 3, 18, 10, 22, 8, 11, 26] + print(f"Inserting data: {data}") + for val in data: + bst.insert(val) + + print("\n1. Tree Structure:") + bst.print_tree() + + print("\n2. Tree Traversals:") + print("Inorder:", end=" ") + bst.inorder() + print("\nPreorder:", end=" ") + bst.preorder() + print("\nPostorder:", end=" ") + bst.postorder() + print("\nLevel Order:", end=" ") + bst.level_order() + + print("\n\n3. Tree Properties:") + print(f"Height: {bst.height()}") + print(f"Minimum value: {bst.get_min()}") + print(f"Maximum value: {bst.get_max()}") + print(f"Tree size: {bst.size()}") + print(f"Is tree empty: {bst.is_empty()}") + + print("\n4. Search Operations:") + search_keys = [10, 15, 22, 100] + for key in search_keys: + result = bst.search(key) + if result: + print(f"Key {key} found in tree") + else: + print(f"Key {key} not found in tree") + + print("\n5. Delete Operations:") + delete_keys = [18, 3, 7] + for key in delete_keys: + print(f"Deleting {key}...") + bst.delete(key) + print(f"Inorder after deletion:", end=" ") + bst.inorder() + print() + + print("\n6. Final Tree Structure:") + bst.print_tree() + +if __name__ == "__main__": + demo_red_black_tree() \ No newline at end of file diff --git a/python/reverse.py b/python/reverse.py new file mode 100644 index 00000000..c26ea94c --- /dev/null +++ b/python/reverse.py @@ -0,0 +1,8 @@ +my_list = [10, 20, 30, 40, 50] +print(f"Original list: {my_list}") + +# Reverses the list in place +my_list.reverse() + +print(f"Reversed list (using .reverse()): {my_list}") +# Output: Reversed list (using .reverse()): [50, 40, 30, 20, 10] \ No newline at end of file diff --git a/python/rk.py b/python/rk.py new file mode 100644 index 00000000..0e018676 --- /dev/null +++ b/python/rk.py @@ -0,0 +1,15 @@ +num = int(input("Enter a number: ")) # getting input to reverse it + +rev_num = 0 # initial variable with 0 + +# while loop until num is not 0 + +while num != 0: + +digit = num % 10 # finding the remainder + +rev_num = rev_num * 10 + digit + +num //= 10 + +print(f"Reversed Number Is: {rev_num}") # printing the results \ No newline at end of file diff --git a/python/scramble_string.py b/python/scramble_string.py new file mode 100644 index 00000000..e69de29b diff --git a/python/search_in_rotated_sorted_array.py b/python/search_in_rotated_sorted_array.py new file mode 100644 index 00000000..63d63bf3 --- /dev/null +++ b/python/search_in_rotated_sorted_array.py @@ -0,0 +1,32 @@ +def search_in_rotated_array(nums, target): + left, right = 0, len(nums) - 1 + + while left <= right: + mid = (left + right) // 2 + + # Found target + if nums[mid] == target: + return mid + + # Check if left half is sorted + if nums[left] <= nums[mid]: + if nums[left] <= target < nums[mid]: + right = mid - 1 + else: + left = mid + 1 + # Right half is sorted + else: + if nums[mid] < target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + + # Target not found + return -1 + + +# Example usage: +nums = [4, 5, 6, 7, 0, 1, 2] +target = 0 +result = search_in_rotated_array(nums, target) +print("Index of target:", result) diff --git a/python/segment.py b/python/segment.py new file mode 100644 index 00000000..355415e6 --- /dev/null +++ b/python/segment.py @@ -0,0 +1,43 @@ +class SegmentTree: + def __init__(self, nums): + self.n = len(nums) + self.tree = [0] * (4 * self.n) + self.build(nums, 0, 0, self.n - 1) + + def build(self, nums, node, l, r): + if l == r: + self.tree[node] = nums[l] + return + mid = (l + r) // 2 + self.build(nums, 2*node+1, l, mid) + self.build(nums, 2*node+2, mid+1, r) + self.tree[node] = self.tree[2*node+1] + self.tree[2*node+2] + + def update(self, idx, val, node=0, l=0, r=None): + if r is None: r = self.n - 1 + if l == r: + self.tree[node] = val + return + mid = (l + r) // 2 + if idx <= mid: + self.update(idx, val, 2*node+1, l, mid) + else: + self.update(idx, val, 2*node+2, mid+1, r) + self.tree[node] = self.tree[2*node+1] + self.tree[2*node+2] + + def query(self, L, R, node=0, l=0, r=None): + if r is None: r = self.n - 1 + if R < l or L > r: # No overlap + return 0 + if L <= l and r <= R: # Complete overlap + return self.tree[node] + mid = (l + r) // 2 + return self.query(L, R, 2*node+1, l, mid) + self.query(L, R, 2*node+2, mid+1, r) + + +# Example usage: +nums = [1, 3, 5, 7, 9, 11] +st = SegmentTree(nums) +print("Sum (1-3):", st.query(1, 3)) +st.update(1, 10) +print("After update, Sum (1-3):", st.query(1, 3)) diff --git a/python/segment_tree.py b/python/segment_tree.py new file mode 100644 index 00000000..673ae9b1 --- /dev/null +++ b/python/segment_tree.py @@ -0,0 +1,141 @@ +class SegmentTree: + """ + Segment Tree for range queries and point updates. + Supports range sum, min, max queries. + + Time Complexity: + - Build: O(n) + - Query: O(log n) + - Update: O(log n) + Space: O(4n) + """ + + def __init__(self, arr, operation='sum'): + """ + Initialize segment tree. + + Args: + arr: input array + operation: 'sum', 'min', or 'max' + """ + self.n = len(arr) + self.arr = arr[:] + self.tree = [0] * (4 * self.n) + self.operation = operation + + if operation == 'sum': + self.default = 0 + self.op = lambda a, b: a + b + elif operation == 'min': + self.default = float('inf') + self.op = min + elif operation == 'max': + self.default = float('-inf') + self.op = max + + self._build(0, 0, self.n - 1) + + def _build(self, node, left, right): + """Build the segment tree recursively""" + if left == right: + self.tree[node] = self.arr[left] + return + + mid = (left + right) // 2 + self._build(2 * node + 1, left, mid) + self._build(2 * node + 2, mid + 1, right) + + self.tree[node] = self.op( + self.tree[2 * node + 1], + self.tree[2 * node + 2] + ) + + def query(self, ql, qr): + """ + Query the range [ql, qr] (inclusive). + + Args: + ql: query left bound + qr: query right bound + + Returns: + result based on operation (sum/min/max) + """ + return self._query(0, 0, self.n - 1, ql, qr) + + def _query(self, node, left, right, ql, qr): + """Helper for range query""" + # No overlap + if left > qr or right < ql: + return self.default + + # Complete overlap + if left >= ql and right <= qr: + return self.tree[node] + + # Partial overlap + mid = (left + right) // 2 + left_result = self._query(2 * node + 1, left, mid, ql, qr) + right_result = self._query(2 * node + 2, mid + 1, right, ql, qr) + + return self.op(left_result, right_result) + + def update(self, index, value): + """ + Update value at index. + + Args: + index: position to update + value: new value + """ + self.arr[index] = value + self._update(0, 0, self.n - 1, index, value) + + def _update(self, node, left, right, index, value): + """Helper for point update""" + if left == right: + self.tree[node] = value + return + + mid = (left + right) // 2 + + if index <= mid: + self._update(2 * node + 1, left, mid, index, value) + else: + self._update(2 * node + 2, mid + 1, right, index, value) + + self.tree[node] = self.op( + self.tree[2 * node + 1], + self.tree[2 * node + 2] + ) + + +# Example usage +if __name__ == "__main__": + # Example 1: Range Sum Query + arr = [1, 3, 5, 7, 9, 11] + seg_tree = SegmentTree(arr, operation='sum') + + print(f"Sum of range [1, 3]: {seg_tree.query(1, 3)}") # 3+5+7 = 15 + print(f"Sum of range [0, 5]: {seg_tree.query(0, 5)}") # 36 + + # Update and query + seg_tree.update(1, 10) + print(f"After update, sum [1, 3]: {seg_tree.query(1, 3)}") # 10+5+7 = 22 + + # Example 2: Range Minimum Query + arr2 = [5, 2, 8, 1, 9, 3] + min_tree = SegmentTree(arr2, operation='min') + + print(f"\nMin of range [0, 3]: {min_tree.query(0, 3)}") # 1 + print(f"Min of range [2, 5]: {min_tree.query(2, 5)}") # 1 + + min_tree.update(3, 6) + print(f"After update, min [0, 3]: {min_tree.query(0, 3)}") # 2 + + # Example 3: Range Maximum Query + arr3 = [3, 1, 7, 2, 9, 4] + max_tree = SegmentTree(arr3, operation='max') + + print(f"\nMax of range [1, 4]: {max_tree.query(1, 4)}") # 9 + print(f"Max of range [0, 2]: {max_tree.query(0, 2)}") # 7 \ No newline at end of file diff --git a/python/selection_sort.py b/python/selection_sort.py index b155473b..0096be37 100644 --- a/python/selection_sort.py +++ b/python/selection_sort.py @@ -1,55 +1,13 @@ def selection_sort(arr): - """ - Selection sort algorithm implementation - Time Complexity: O(n²) - Space Complexity: O(1) - """ n = len(arr) - for i in range(n): - # Find the minimum element in the remaining unsorted array min_idx = i for j in range(i + 1, n): if arr[j] < arr[min_idx]: min_idx = j - - # Swap the found minimum element with the first element arr[i], arr[min_idx] = arr[min_idx], arr[i] - - return arr -def selection_sort_with_steps(arr): - """ - Selection sort with step-by-step visualization - """ - n = len(arr) - steps = [] - - for i in range(n): - min_idx = i - for j in range(i + 1, n): - if arr[j] < arr[min_idx]: - min_idx = j - - # Swap and record step - arr[i], arr[min_idx] = arr[min_idx], arr[i] - steps.append(arr.copy()) - - return arr, steps - -# Test the function -if __name__ == "__main__": - numbers = [64, 25, 12, 22, 11] - print(f"Original array: {numbers}") - - # Basic selection sort - sorted_numbers = selection_sort(numbers.copy()) - print(f"Sorted array: {sorted_numbers}") - - # Selection sort with steps - original = [64, 25, 12, 22, 11] - result, sort_steps = selection_sort_with_steps(original) - - print("\nSorting steps:") - for i, step in enumerate(sort_steps): - print(f"Step {i + 1}: {step}") \ No newline at end of file +# Example usage +arr = [64, 25, 12, 22, 11] +selection_sort(arr) +print("Sorted array:", arr) diff --git a/python/sleep_sort.py b/python/sleep_sort.py new file mode 100644 index 00000000..bbb9f2b3 --- /dev/null +++ b/python/sleep_sort.py @@ -0,0 +1,34 @@ +import time +import threading + +def sleep_sort(numbers): + """ + Sorts a list of positive numbers using the Sleep Sort algorithm. + WARNING: This is a conceptual and impractical algorithm. Do not use + it for serious applications. It may not work reliably and is + inefficient for large numbers or lists. + """ + sorted_result = [] + + def sleep_and_append(num): + + time.sleep(num / 100) + sorted_result.append(num) + + threads = [] + for num in numbers: + thread = threading.Thread(target=sleep_and_append, args=(num,)) + threads.append(thread) + thread.start() + + + for thread in threads: + thread.join() + + return sorted_result + +my_numbers = [64, 34, 25, 12, 22, 11, 90] +print(f"Original: {my_numbers}") + +sorted_numbers = sleep_sort(my_numbers) +print(f"Sorted: {sorted_numbers}") diff --git a/python/snake_water_gun.py b/python/snake_water_gun.py new file mode 100644 index 00000000..0226e829 --- /dev/null +++ b/python/snake_water_gun.py @@ -0,0 +1,83 @@ +import time +import random + +print("\033[95m !! WELCOME IN SNAKE WATER GUN !!\033[0m\n") +time.sleep(2) +print("\033[94mRules of the game\033[0m") +time.sleep(1) +print("1.There will be 5 rounds.") +time.sleep(1) +print("2.At the end, player with highest point win the game.") +time.sleep(1) +print("3.WIN = 2 points") +print(" DRAW = 1 points each") +print(" LOSS = 0 points \n") +time.sleep(2) +print("\033[96m ! LET'S GO ! \033[0m\n") +time.sleep(2) + +def start_game(): + print("List of weapons\n snake\n water\n gun") + time.sleep(1) + Player = 0 + Computer = 0 + i = 1 + while i<= 5 : + number = random.choice(["snake","water","gun"]) + + print("\033[93m ********** ROUND", i ,"********** \033[0m") + time.sleep(1) + playerchoice = input("Choose your Weapon:") + print("Computer Weapon:",number) + if playerchoice == number : + time.sleep(1) + print("\033[94mMatch Draw\033[0m") + Player = Player+1 + Computer = Computer+1 + elif playerchoice == "snake" and number == "water" : + time.sleep(1) + print("\033[92mYou WON\033[0m") + Player = Player+2 + elif playerchoice == "snake" and number == "gun" : + time.sleep(1) + print("\033[91mYou LOSS\033[0m") + Computer = Computer+2 + elif playerchoice == "water" and number == "snake" : + time.sleep(1) + print("\033[91mYou LOSS\033[0m") + Computer = Computer+2 + elif playerchoice == "water" and number == "gun" : + time.sleep(1) + print("\033[92mYou WON\033[0m") + Player = Player+2 + elif playerchoice == "gun" and number == "water" : + time.sleep(1) + print("\033[91mYou LOSS\033[0m") + Computer = Computer+2 + elif playerchoice == "gun" and number == "snake" : + time.sleep(1) + print("\033[92mYou WON\033[0m") + Player = Player+2 + else : + time.sleep(1) + print("Enter input in GIVEN ways") + if i == 5 : + print(" **********GAME OVER**********") + print("Your Final Score:",Player) + print("Computer Final Score:",Computer) + time.sleep(2) + if Player > Computer: + print("\033[92mCongratulations! You WIN the game 🎉\033[0m") + elif Computer > Player: + print("\033[91mSorry! You LOST the game 😢\033[0m") + else: + print("\033[93mIt's a TIE!\033[0m") + i=i+1 + +# --- Replay Option Added Below --- +while True: + start_game() + replay = input("\nDo you want to play again? (yes/no): ").strip().lower() + if replay not in ["yes", "y"]: + print("\nThanks for playing! 👋") + break diff --git a/python/squareroot.py b/python/squareroot.py new file mode 100644 index 00000000..dcb8251f --- /dev/null +++ b/python/squareroot.py @@ -0,0 +1,10 @@ +# Python Program to calculate the square root + +# Note: change this value for a different result +num = 8 + +# To take the input from the user +#num = float(input('Enter a number: ')) + +num_sqrt = num ** 0.5 +print('The square root of %0.3f is %0.3f'%(num ,num_sqrt)) diff --git a/python/static_method_implementation.py b/python/static_method_implementation.py new file mode 100644 index 00000000..bfb4c8ca --- /dev/null +++ b/python/static_method_implementation.py @@ -0,0 +1,48 @@ +# static method is used when a particular method is not object specific +# it can be called using class name +# it does not take self or cls as first argument +# no need to create object of class to call static method + +class MaxSubArray: + """A collection of methods for manipulating array.""" + + @staticmethod + def max_sub_array(nums): + """Finds the contiguous subarray with the maximum sum value. + + This method calculates the maximum sum of a contiguous + subarray. + + Args: + nums : A list of integers. + + Returns: + The sum of the contiguous subarray with the largest sum. + + Raises: + ValueError: If the input list `nums` is empty, it raises an value error + + Example: + >>> MaxSubArray.max_sub_array([-2, 1, -3, 4, -1, 2, 1, -5, 4]) + it will return max valus in a contigous sub array is 6 + # The subarray [4, -1, 2, 1] has the largest sum of 6. + """ + # Handles the scenario when nums array is empty. + if not nums: + raise ValueError("Input array nums can not be empty.") + + max_sum = curr_sum = nums[0] + for num in nums[1:]: + curr_sum = max(num, curr_sum + num) + # Update the overall maximum sum found so far + max_sum = max(max_sum, curr_sum) + + return max_sum + +# --- examples--- +nums = [-2, 1, -3, 4, -1, 2, 1, -5, 4] +try: + max_sum = MaxSubArray.max_sub_array(nums) + print(f"The maximum sum of a subarray is: {max_sum}") # Output: 6 +except ValueError as e: + print(f"Error: {e}") \ No newline at end of file diff --git a/python/subsets_78_lc.py b/python/subsets_78_lc.py new file mode 100644 index 00000000..5ee0282f --- /dev/null +++ b/python/subsets_78_lc.py @@ -0,0 +1,17 @@ +class Solution(object): + def subsets(self, nums): + """ + :type nums: List[int] + :rtype: List[List[int]] + """ + res = [] + + def backtrack(l, r): + res.append(r[:]) + for i in range(l, len(nums)): + r.append(nums[i]) + backtrack(i + 1, r) + r.pop() + + backtrack(0, []) + return res \ No newline at end of file diff --git a/python/substring_with_concatenation_of_all_words.py b/python/substring_with_concatenation_of_all_words.py new file mode 100644 index 00000000..e69de29b diff --git a/python/subtree_of_another_tree.py b/python/subtree_of_another_tree.py new file mode 100644 index 00000000..29e35ffb --- /dev/null +++ b/python/subtree_of_another_tree.py @@ -0,0 +1,48 @@ +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +class Solution: + def isSubtree(self, root: TreeNode, subRoot: TreeNode) -> bool: + # Helper function to check if two trees are identical + def isSameTree(s, t): + if not s and not t: + return True + if not s or not t: + return False + return (s.val == t.val and + isSameTree(s.left, t.left) and + isSameTree(s.right, t.right)) + + # Main logic: check if subRoot is a subtree starting from any node in root + if not root: + return False + if isSameTree(root, subRoot): + return True + return self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot) + + +# -------- Example Usage -------- +# Example 1: +# root = [3,4,5,1,2], subRoot = [4,1,2] +# 3 +# / \ +# 4 5 +# / \ +# 1 2 + +root = TreeNode(3) +root.left = TreeNode(4) +root.right = TreeNode(5) +root.left.left = TreeNode(1) +root.left.right = TreeNode(2) + +subRoot = TreeNode(4) +subRoot.left = TreeNode(1) +subRoot.right = TreeNode(2) + +sol = Solution() +print("Is Subtree:", sol.isSubtree(root, subRoot)) # Output: True diff --git a/python/sudoku_solver.py b/python/sudoku_solver.py new file mode 100644 index 00000000..41d59bc8 --- /dev/null +++ b/python/sudoku_solver.py @@ -0,0 +1,47 @@ +def is_valid(board, row, col, num): + for x in range(9): + if board[row][x] == num or board[x][col] == num: + return False + startRow = row - row % 3 + startCol = col - col % 3 + for i in range(3): + for j in range(3): + if board[i + startRow][j + startCol] == num: + return False + return True + +def solve_sudoku(board): + for row in range(9): + for col in range(9): + if board[row][col] == 0: + for num in range(1, 10): + if is_valid(board, row, col, num): + board[row][col] = num + if solve_sudoku(board): + return True + board[row][col] = 0 + return False + return True + +def print_board(board): + for row in board: + print(row) + +# Example 9x9 board with 0 as empty cells +board = [ + [5, 3, 0, 0, 7, 0, 0, 0, 0], + [6, 0, 0, 1, 9, 5, 0, 0, 0], + [0, 9, 8, 0, 0, 0, 0, 6, 0], + [8, 0, 0, 0, 6, 0, 0, 0, 3], + [4, 0, 0, 8, 0, 3, 0, 0, 1], + [7, 0, 0, 0, 2, 0, 0, 0, 6], + [0, 6, 0, 0, 0, 0, 2, 8, 0], + [0, 0, 0, 4, 1, 9, 0, 0, 5], + [0, 0, 0, 0, 8, 0, 0, 7, 9] +] + +if solve_sudoku(board): + print("Sudoku solved:") + print_board(board) +else: + print("No solution exists") diff --git a/python/sumof2darray.py b/python/sumof2darray.py new file mode 100644 index 00000000..98b3782a --- /dev/null +++ b/python/sumof2darray.py @@ -0,0 +1,10 @@ +import numpy as np + +my_2d_array_np = np.array([[10, 20], + [30, 40]]) + +# The .sum() method on a NumPy array, without an axis specified, +# sums up all elements in the entire array. +total_sum = my_2d_array_np.sum() + +print(f"Total sum (NumPy): {total_sum}") # Output: Total sum (NumPy): 100 \ No newline at end of file diff --git a/python/taking_maximum_energy.py b/python/taking_maximum_energy.py new file mode 100644 index 00000000..e3e09225 --- /dev/null +++ b/python/taking_maximum_energy.py @@ -0,0 +1,9 @@ +class Solution: + def maximumEnergy(self, energy: List[int], k: int) -> int: + n = len(energy) + dp = [0] * n + result = float('-inf') + for i in range(n - 1, -1, -1): + dp[i] = energy[i] + (dp[i + k] if i + k < n else 0) + result = max(result, dp[i]) + return result diff --git a/python/tempCodeRunnerFile.py b/python/tempCodeRunnerFile.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/python/tempCodeRunnerFile.py @@ -0,0 +1 @@ + diff --git a/python/text-wrap.py b/python/text-wrap.py new file mode 100644 index 00000000..e84ddd55 --- /dev/null +++ b/python/text-wrap.py @@ -0,0 +1,11 @@ +def wrap(string, max_width): + result = "" + for i in range(0, len(string), max_width): + result += string[i:i+max_width] + "\n" + return result.strip() + +#take input 1. string 2. maximum_width +string = input().strip() +max_width = int(input().strip()) + +print(wrap(string, max_width)) \ No newline at end of file diff --git a/python/todo_list.py b/python/todo_list.py new file mode 100644 index 00000000..660735ab --- /dev/null +++ b/python/todo_list.py @@ -0,0 +1,39 @@ +# todo_list.py +tasks = [] + +def show_tasks(): + if not tasks: + print("No tasks yet!") + else: + for i, task in enumerate(tasks, start=1): + print(f"{i}. {task}") + +def add_task(task): + tasks.append(task) + print(f"Task '{task}' added!") + +def delete_task(index): + if 0 < index <= len(tasks): + removed = tasks.pop(index-1) + print(f"Task '{removed}' removed!") + else: + print("Invalid task number.") + +def menu(): + while True: + print("\n1. Show Tasks\n2. Add Task\n3. Delete Task\n4. Exit") + choice = input("Choose an option: ") + if choice == '1': + show_tasks() + elif choice == '2': + add_task(input("Enter task: ")) + elif choice == '3': + delete_task(int(input("Enter task number to delete: "))) + elif choice == '4': + print("Goodbye!") + break + else: + print("Invalid choice!") + +if __name__ == "__main__": + menu() diff --git a/python/topological_sort.py b/python/topological_sort.py new file mode 100644 index 00000000..74f2f593 --- /dev/null +++ b/python/topological_sort.py @@ -0,0 +1,48 @@ +from collections import deque + +def topological_sort(graph): + # Calculate in-degrees for all nodes + in_degree = {u: 0 for u in graph} + for u in graph: + for v in graph[u]: + in_degree[v] += 1 + + # Initialize queue with all nodes having an in-degree of 0 + queue = deque([u for u in graph if in_degree[u] == 0]) + + result = [] + + while queue: + u = queue.popleft() + result.append(u) + + # "Remove" u and update neighbors' in-degrees + for v in graph[u]: + in_degree[v] -= 1 + if in_degree[v] == 0: + queue.append(v) + + # Check for cycle (if result length != number of nodes) + if len(result) == len(graph): + return result + else: + return "Graph has a cycle" + +# Example: (0 -> 1, 0 -> 2, 1 -> 3, 2 -> 3) +G = { + 0: [1, 2], + 1: [3], + 2: [3], + 3: [] +} + +order = topological_sort(G) +print(f"Topological Order: {order}") + +# Example with cycle: (A -> B, B -> A) +G_cycle = { + 'A': ['B'], + 'B': ['A'], + 'C': [] +} +print(f"Topological Order (Cycle Check): {topological_sort(G_cycle)}") \ No newline at end of file diff --git a/python/tree_height.py b/python/tree_height.py new file mode 100644 index 00000000..c3fedeb3 --- /dev/null +++ b/python/tree_height.py @@ -0,0 +1,21 @@ +class Node: + def __init__(self, key): + self.val = key + self.left = None + self.right = None + +def height(root): + if root is None: + return 0 + left_height = height(root.left) + right_height = height(root.right) + return max(left_height, right_height) + 1 + +# Example usage +root = Node(1) +root.left = Node(2) +root.right = Node(3) +root.left.left = Node(4) +root.left.right = Node(5) + +print("Height of the tree is:", height(root)) diff --git a/python/trie_implementation.py b/python/trie_implementation.py new file mode 100644 index 00000000..43fbc3c2 --- /dev/null +++ b/python/trie_implementation.py @@ -0,0 +1,275 @@ +""" +Trie (Prefix Tree) Implementation in Python + +A Trie is a tree-like data structure that stores strings in a way that makes +searching for prefixes very efficient. It's commonly used for: +- Autocomplete functionality +- Spell checkers +- IP routing (longest prefix matching) +- Word games + +Time Complexity: +- Insert: O(m) where m is the length of the string +- Search: O(m) where m is the length of the string +- Delete: O(m) where m is the length of the string +- Prefix Search: O(m) where m is the length of the prefix + +Space Complexity: O(ALPHABET_SIZE * N * M) where N is the number of strings +and M is the average length of the strings. +""" + +class TrieNode: + """Node class for Trie data structure""" + + def __init__(self): + self.children = {} # Dictionary to store child nodes + self.is_end_of_word = False # Flag to mark end of word + self.word_count = 0 # Count of words that end at this node + + +class Trie: + """Trie (Prefix Tree) implementation""" + + def __init__(self): + self.root = TrieNode() + self.total_words = 0 + + def insert(self, word): + """ + Insert a word into the trie + + Args: + word (str): The word to insert + """ + if not word: + return + + current = self.root + + for char in word: + if char not in current.children: + current.children[char] = TrieNode() + current = current.children[char] + current.word_count += 1 + + if not current.is_end_of_word: + current.is_end_of_word = True + self.total_words += 1 + + def search(self, word): + """ + Search for a word in the trie + + Args: + word (str): The word to search for + + Returns: + bool: True if word exists, False otherwise + """ + if not word: + return False + + current = self.root + + for char in word: + if char not in current.children: + return False + current = current.children[char] + + return current.is_end_of_word + + def starts_with(self, prefix): + """ + Check if any word in the trie starts with the given prefix + + Args: + prefix (str): The prefix to search for + + Returns: + bool: True if prefix exists, False otherwise + """ + if not prefix: + return True + + current = self.root + + for char in prefix: + if char not in current.children: + return False + current = current.children[char] + + return True + + def delete(self, word): + """ + Delete a word from the trie + + Args: + word (str): The word to delete + + Returns: + bool: True if word was deleted, False if word doesn't exist + """ + if not word or not self.search(word): + return False + + current = self.root + + # Navigate to the end of the word + for char in word: + current.children[char].word_count -= 1 + current = current.children[char] + + # Mark as not end of word + current.is_end_of_word = False + self.total_words -= 1 + + # Clean up unused nodes (optional optimization) + self._cleanup_nodes(word) + + return True + + def _cleanup_nodes(self, word): + """ + Helper method to remove unused nodes after deletion + + Args: + word (str): The word that was deleted + """ + current = self.root + path = [] + + for char in word: + path.append((current, char)) + current = current.children[char] + + # Remove nodes from the end if they have no children and are not end of word + for node, char in reversed(path): + if (not node.children[char].children and + not node.children[char].is_end_of_word and + node.children[char].word_count == 0): + del node.children[char] + else: + break + + def get_all_words_with_prefix(self, prefix): + """ + Get all words that start with the given prefix + + Args: + prefix (str): The prefix to search for + + Returns: + list: List of words that start with the prefix + """ + if not self.starts_with(prefix): + return [] + + current = self.root + + # Navigate to the prefix node + for char in prefix: + current = current.children[char] + + words = [] + self._collect_words(current, prefix, words) + return words + + def _collect_words(self, node, current_word, words): + """ + Helper method to collect all words from a given node + + Args: + node (TrieNode): Current node + current_word (str): Current word being built + words (list): List to store found words + """ + if node.is_end_of_word: + words.append(current_word) + + for char, child_node in node.children.items(): + self._collect_words(child_node, current_word + char, words) + + def get_word_count(self): + """ + Get the total number of words in the trie + + Returns: + int: Total number of words + """ + return self.total_words + + def is_empty(self): + """ + Check if the trie is empty + + Returns: + bool: True if trie is empty, False otherwise + """ + return self.total_words == 0 + + def clear(self): + """Clear all words from the trie""" + self.root = TrieNode() + self.total_words = 0 + + +def demo_trie_operations(): + """Demonstrate various trie operations""" + print("=== Trie Implementation Demo ===\n") + + # Create a new trie + trie = Trie() + + # Insert words + words = ["apple", "app", "application", "apply", "banana", "band", "bandana"] + print("Inserting words:", words) + for word in words: + trie.insert(word) + + print(f"Total words in trie: {trie.get_word_count()}\n") + + # Search for words + search_words = ["app", "apple", "application", "banana", "orange"] + print("Searching for words:") + for word in search_words: + result = trie.search(word) + print(f" '{word}': {'Found' if result else 'Not found'}") + + print() + + # Check prefixes + prefixes = ["app", "ban", "ora", "ap"] + print("Checking prefixes:") + for prefix in prefixes: + result = trie.starts_with(prefix) + print(f" Words starting with '{prefix}': {'Yes' if result else 'No'}") + + print() + + # Get all words with specific prefix + prefix = "app" + words_with_prefix = trie.get_all_words_with_prefix(prefix) + print(f"All words starting with '{prefix}': {words_with_prefix}") + + print() + + # Delete a word + word_to_delete = "app" + print(f"Deleting word: '{word_to_delete}'") + deleted = trie.delete(word_to_delete) + print(f"Deletion {'successful' if deleted else 'failed'}") + print(f"Total words after deletion: {trie.get_word_count()}") + + # Check if word still exists + print(f"'{word_to_delete}' still exists: {'Yes' if trie.search(word_to_delete) else 'No'}") + + print() + + # Get all words with prefix after deletion + words_with_prefix = trie.get_all_words_with_prefix("app") + print(f"All words starting with 'app' after deletion: {words_with_prefix}") + + +if __name__ == "__main__": + demo_trie_operations() diff --git a/python/tuples_value_replace.py b/python/tuples_value_replace.py new file mode 100644 index 00000000..4d2acb70 --- /dev/null +++ b/python/tuples_value_replace.py @@ -0,0 +1,26 @@ +# List of tuples with three elements each +list_of_tuples = [(10, 20, 40), + (40, 50, 60), + (70, 80, 90)] +# Displaying the elements of the list of tuples +print("The elements of List of Tuples are::\n", list_of_tuples, "\n") +counter = 0 +for items in list_of_tuples: + counter += 1 + print("Tuple ", counter, " = ", items) + +new_list = [] + +# Replacing the last values of each tuple into 100 +for tuples in list_of_tuples: + # Convert tuple to list to modify + temp_list = list(tuples) + + # Replacing the last values to 100 + temp_list[-1] = 100 + + # Convert back to tuple + temp_tuples = tuple(temp_list) + new_list.append(temp_tuples) + +print("\nOUTPUT::\nThe modified list of tuuples is:",new_list) \ No newline at end of file diff --git a/python/twoosum.py b/python/twoosum.py new file mode 100644 index 00000000..9fa7eb5d --- /dev/null +++ b/python/twoosum.py @@ -0,0 +1,7 @@ +def twoSum(nums, target): + hashmap = {} + for i, num in enumerate(nums): + complement = target - num + if complement in hashmap: + return [hashmap[complement], i] + hashmap[num] = i diff --git a/python/twosum b/python/twosum new file mode 100644 index 00000000..00fa631d --- /dev/null +++ b/python/twosum @@ -0,0 +1,8 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + pair_idx = {} + + for i, num in enumerate(nums): + if target - num in pair_idx: + return [i, pair_idx[target - num]] + pair_idx[num] = i \ No newline at end of file diff --git a/python/undirected_graph_dfs.py b/python/undirected_graph_dfs.py new file mode 100644 index 00000000..cd7b04ba --- /dev/null +++ b/python/undirected_graph_dfs.py @@ -0,0 +1,26 @@ +def is_cycle_dfs(graph, node, visited, parent): + visited.add(node) + for neighbor in graph[node]: + if neighbor not in visited: + if is_cycle_dfs(graph, neighbor, visited, node): + return True + elif neighbor != parent: + return True + return False + +def has_cycle(graph): + visited = set() + for node in graph: + if node not in visited: + if is_cycle_dfs(graph, node, visited, -1): + return True + return False + +graph = { + 0: [1, 2], + 1: [0, 3], + 2: [0], + 3: [1, 4], + 4: [3] +} +print("\nGraph contains cycle?" , has_cycle(graph)) diff --git a/python/unfolding_matrix_vishrutha.py b/python/unfolding_matrix_vishrutha.py new file mode 100644 index 00000000..a0978d4e --- /dev/null +++ b/python/unfolding_matrix_vishrutha.py @@ -0,0 +1,9 @@ +def spiral(matrix): + if not matrix: + return [] + # Step 1: Take first row + first_row = matrix[0] + # Step 2: Rotate remaining matrix 90° counterclockwise + rotated = list(zip(*matrix[1:]))[::-1] + # Step 3: Recur + return first_row + spiral([list(row) for row in rotated]) \ No newline at end of file diff --git a/python/uniquePerms.py b/python/uniquePerms.py new file mode 100644 index 00000000..48d96774 --- /dev/null +++ b/python/uniquePerms.py @@ -0,0 +1,32 @@ +from itertools import permutations +from typing import List + +class Solution: + def uniquePerms(self, arr: List[int]) -> List[List[int]]: + # 1. itertools.permutations generates all possible permutations, including duplicates. + all_perms_iterator = permutations(arr) + + # 2. Using a set removes duplicates (since arr may contain duplicate elements). + unique_perms_set = set(all_perms_iterator) + + # 3. Convert to list of lists and sort them for predictable output. + result = sorted([list(p) for p in unique_perms_set]) + + return result + + +# ✅ Testing the function +if __name__ == "__main__": + obj = Solution() + + # Example 1 + arr1 = [1, 1, 2] + print("Input:", arr1) + print("Unique permutations:") + print(obj.uniquePerms(arr1)) + + # Example 2 + arr2 = [1, 2, 3] + print("\nInput:", arr2) + print("Unique permutations:") + print(obj.uniquePerms(arr2)) diff --git a/python/waterjug.py b/python/waterjug.py new file mode 100644 index 00000000..1050dcb0 --- /dev/null +++ b/python/waterjug.py @@ -0,0 +1,39 @@ +from collections import deque + +def water_jug_problem_trace_path(jug1_capacity, jug2_capacity, target): + # Queue to keep track of states and the path to reach them + queue = deque([((0, 0), [(0, 0)])]) + # Set to keep track of visited states + visited = set() + visited.add((0, 0)) + while queue: + (jug1, jug2), path = queue.popleft() + # Check if we have reached the target amount of water in either jug + if jug1 == target or jug2 == target: + return path + # List of possible actions + actions = [ + (jug1_capacity, jug2), # Fill jug1 + (jug1, jug2_capacity), # Fill jug2 + (0, jug2), # Empty jug1 + (jug1, 0), # Empty jug2 + # Pour jug2 into jug1 + (min(jug1_capacity, jug1 + jug2), jug2 - (min(jug1_capacity, jug1 + jug2) - jug1)), + # Pour jug1 into jug2 + (jug1 - (min(jug2_capacity, jug1 + jug2) - jug2), min(jug2_capacity, jug1 + jug2)) + ] + for action in actions: + if action not in visited: + visited.add(action) + queue.append((action, path + [action])) + return None + +# Example usage +jug1_capacity = 4 +jug2_capacity = 3 +target = 2 +path = water_jug_problem_trace_path(jug1_capacity, jug2_capacity, target) +if path: + print("Path of states followed:", path) +else: + print("No solution found.") diff --git a/python/wildcard.py b/python/wildcard.py new file mode 100644 index 00000000..e69de29b diff --git a/python/word_ladder.py b/python/word_ladder.py new file mode 100644 index 00000000..d4e60405 --- /dev/null +++ b/python/word_ladder.py @@ -0,0 +1,24 @@ +from collections import deque +from typing import List + +class Solution: + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + wordset = set(wordList) + if endWord not in wordset: + return 0 + + q = deque([(beginWord, 1)]) + + while q: + word, steps = q.popleft() + + if word == endWord: + return steps + + for i in range(len(word)): + for ch in range(26): + transformed = word[:i] + chr(ord('a') + ch) + word[i+1:] + if transformed in wordset: + wordset.remove(transformed) + q.append((transformed, steps + 1)) + return 0 \ No newline at end of file diff --git a/python/wordsearch.py b/python/wordsearch.py new file mode 100644 index 00000000..293d8fe2 --- /dev/null +++ b/python/wordsearch.py @@ -0,0 +1,26 @@ +def exist(board, word): + dirs = [(1, 0), (0, 1), (-1, 0), (0, -1)] + + def f(i, j, idx): + if idx == len(word): + return True + + ch = board[i][j] + board[i][j] = "#" + + for dx, dy in dirs: + x = i + dx + y = j + dy + if 0 <= x < len(board) and 0 <= y < len(board[0]) and board[x][y] == word[idx]: + if f(x, y, idx + 1): + return True + + board[i][j] = ch + return False + + for i in range(len(board)): + for j in range(len(board[0])): + if board[i][j] == word[0]: + if f(i, j, 1): + return True + return False \ No newline at end of file diff --git a/quote.py b/quote.py new file mode 100644 index 00000000..e33bdc37 --- /dev/null +++ b/quote.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# quote_server.py +import http.server +import socketserver +import random +import json + +QUOTES = [ + "Be the change you wish to see. — Gandhi", + "Simplicity is the ultimate sophistication. — Leonardo da Vinci", + "Code is like humor. When you have to explain it, it’s bad. — Cory House", + "First, solve the problem. Then, write the code. — John Johnson", +] + +class Handler(http.server.SimpleHTTPRequestHandler): + def do_GET(self): + if self.path in ("/", "/quote"): + q = random.choice(QUOTES) + payload = {"quote": q} + data = json.dumps(payload).encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "application/json; charset=utf-8") + self.send_header("Content-Length", str(len(data))) + self.end_headers() + self.wfile.write(data) + else: + super().do_GET() + +if __name__ == "__main__": + PORT = 8000 + with socketserver.TCPServer(("", PORT), Handler) as httpd: + print(f"Serving on http://localhost:{PORT}/quote") + try: + httpd.serve_forever() + except KeyboardInterrupt: + print("Stopping server.") diff --git a/realworld-dsa/README.md b/realworld-dsa/README.md new file mode 100644 index 00000000..e69de29b diff --git a/realworld-dsa/maze_shortest_path.cpp b/realworld-dsa/maze_shortest_path.cpp new file mode 100644 index 00000000..e69de29b diff --git a/realworld-dsa/priority_task_scheduler.cpp b/realworld-dsa/priority_task_scheduler.cpp new file mode 100644 index 00000000..e69de29b diff --git a/realworld-dsa/trie_autocomplete.cpp b/realworld-dsa/trie_autocomplete.cpp new file mode 100644 index 00000000..e69de29b diff --git a/roadmap/DSA Road Map Basic to Advance.md b/roadmap/DSA Road Map Basic to Advance.md new file mode 100644 index 00000000..e2f857bd --- /dev/null +++ b/roadmap/DSA Road Map Basic to Advance.md @@ -0,0 +1,93 @@ +# DSA Road Map Basic to Advance + +This roadmap provides a step-by-step guide to mastering Data Structures and Algorithms, from beginner to advanced levels. It helps learners and contributors understand the progression of topics and focus on relevant problems. + +## Beginner Level + +### Arrays +- Two Sum +- Maximum Subarray Sum (Kadane's Algorithm) +- Rotate Array +- Find Missing Number in Array + +### Strings +- Valid Palindrome +- Check for Anagrams +- Longest Common Prefix +- Reverse String + +### Linked Lists +- Reverse a Linked List +- Detect Cycle in Linked List +- Merge Two Sorted Lists +- Remove Nth Node from End + +### Stacks and Queues +- Valid Parentheses +- Implement Stack using Queues +- Implement Queue using Stacks +- Next Greater Element + +## Intermediate Level + +### Trees +- Binary Tree Traversals (Inorder, Preorder, Postorder) +- Binary Search Tree Operations (Insert, Delete, Search) +- Lowest Common Ancestor +- Maximum Depth of Binary Tree + +### Graphs +- Breadth-First Search (BFS) +- Depth-First Search (DFS) +- Shortest Path in Unweighted Graph +- Topological Sort + +### Recursion and Backtracking +- Generate All Subsets +- Permutations of Array +- N-Queens Problem +- Sudoku Solver + +### Sorting and Searching +- Merge Sort +- Quick Sort +- Binary Search Variations +- Find Kth Largest Element + +## Advanced Level + +### Dynamic Programming +- 0/1 Knapsack Problem +- Longest Common Subsequence +- Longest Increasing Subsequence +- Coin Change Problem + +### Advanced Graphs +- Dijkstra's Algorithm +- Bellman-Ford Algorithm +- Minimum Spanning Tree (Kruskal/Prim) +- Floyd-Warshall Algorithm + +### Greedy Algorithms +- Activity Selection Problem +- Huffman Coding +- Fractional Knapsack + +### Advanced Data Structures +- Trie (Prefix Tree) +- Segment Tree +- Fenwick Tree (Binary Indexed Tree) +- Disjoint Set Union (Union-Find) + +## Visual Roadmap + +For a visual flowchart representation of the learning path, refer to resources like [Roadmap.sh DSA](https://roadmap.sh/computer-science) or create your own diagram based on the above structure. + +## How to Use This Roadmap + +- Start from the Beginner level and progress to Intermediate and Advanced. +- For each topic, explore and solve problems in the corresponding language folders (e.g., `python/`, `java/`). +- Contribute new problems or solutions to topics you're comfortable with to help the community. +- Practice consistently and revisit topics as needed. + +Happy Learning! 🚀 diff --git a/roadmap/GRAPH.py b/roadmap/GRAPH.py new file mode 100644 index 00000000..a4e34f04 --- /dev/null +++ b/roadmap/GRAPH.py @@ -0,0 +1,34 @@ +# Problem: Given a grid of '1's (land) and '0's (water), count the number of islands. + +def numIslands(grid): + if not grid: + return 0 + + rows, cols = len(grid), len(grid[0]) + visited = set() + + def dfs(r, c): + if (r < 0 or c < 0 or r >= rows or c >= cols or + grid[r][c] == "0" or (r, c) in visited): + return + visited.add((r, c)) + dfs(r+1, c) + dfs(r-1, c) + dfs(r, c+1) + dfs(r, c-1) + + islands = 0 + for r in range(rows): + for c in range(cols): + if grid[r][c] == "1" and (r, c) not in visited: + dfs(r, c) + islands += 1 + return islands + +grid = [ + ["1","1","0","0","0"], + ["1","1","0","0","0"], + ["0","0","1","0","0"], + ["0","0","0","1","1"] +] +print(numIslands(grid)) diff --git a/ruby/BFS.rb b/ruby/BFS.rb new file mode 100644 index 00000000..8eb0f779 --- /dev/null +++ b/ruby/BFS.rb @@ -0,0 +1,29 @@ +def bfs(graph, start) + visited = {} + queue = [start] + visited[start] = true + + while !queue.empty? + node = queue.shift + puts node # Process the node (e.g., print or collect) + + graph[node]&.each do |neighbor| + unless visited[neighbor] + visited[neighbor] = true + queue << neighbor + end + end + end +end + +# Example usage: +graph = { + 'A' => ['B', 'C'], + 'B' => ['D', 'E'], + 'C' => ['F'], + 'D' => [], + 'E' => ['F'], + 'F' => [] +} + +bfs(graph, 'A') \ No newline at end of file diff --git a/ruby/IntroSort.rb b/ruby/IntroSort.rb new file mode 100644 index 00000000..1b1ae5b0 --- /dev/null +++ b/ruby/IntroSort.rb @@ -0,0 +1,144 @@ +# frozen_string_literal: true + +# Main entry point for the Introsort algorithm. +# It calculates the depth limit and calls the recursive sorter. +# +# @param arr [Array] The array to be sorted. +def introsort(arr) + return if arr.empty? + + depth_limit = (2 * Math.log2(arr.size)).floor + introsort_recursive(arr, 0, arr.size - 1, depth_limit) +end + +# The core recursive function for Introsort. +# It switches to Heap Sort if recursion depth is exceeded, +# and to Insertion Sort for small partitions. +# +# @param arr [Array] The array to sort. +# @param begin_idx [Integer] The starting index of the partition. +# @param end_idx [Integer] The ending index of the partition. +# @param depth_limit [Integer] The maximum recursion depth. +def introsort_recursive(arr, begin_idx, end_idx, depth_limit) + return if begin_idx >= end_idx + + size = end_idx - begin_idx + 1 + + if size <= 16 + insertion_sort(arr, begin_idx, end_idx) + return + end + + if depth_limit.zero? + heap_sort(arr, begin_idx, end_idx) + return + end + + pivot_index = partition(arr, begin_idx, end_idx) + introsort_recursive(arr, begin_idx, pivot_index - 1, depth_limit - 1) + introsort_recursive(arr, pivot_index + 1, end_idx, depth_limit - 1) +end + +# Partitions the array for Quick Sort using the Lomuto partition scheme. +# It uses the last element as the pivot. +# +# @param arr [Array] The array to partition. +# @param low [Integer] The starting index. +# @param high [Integer] The ending index. +# @return [Integer] The index of the pivot after partitioning. +def partition(arr, low, high) + pivot = arr[high] + i = low - 1 + (low...high).each do |j| + if arr[j] <= pivot + i += 1 + arr[i], arr[j] = arr[j], arr[i] # Swap + end + end + arr[i + 1], arr[high] = arr[high], arr[i + 1] # Swap pivot into place + i + 1 +end + +# Sorts a small partition of the array using Insertion Sort. +# +# @param arr [Array] The array containing the partition. +# @param left [Integer] The starting index of the partition. +# @param right [Integer] The ending index of the partition. +def insertion_sort(arr, left, right) + (left + 1..right).each do |i| + key = arr[i] + j = i - 1 + while j >= left && arr[j] > key + arr[j + 1] = arr[j] + j -= 1 + end + arr[j + 1] = key + end +end + +# Sorts a partition of the array using Heap Sort. +# +# @param arr [Array] The array containing the partition. +# @param begin_idx [Integer] The starting index of the partition. +# @param end_idx [Integer] The ending index of the partition. +def heap_sort(arr, begin_idx, end_idx) + n = end_idx - begin_idx + 1 + offset = begin_idx + + # Build a maxheap. + (n / 2 - 1).downto(0) do |i| + heapify(arr, n, i, offset) + end + + # One by one extract elements + (n - 1).downto(0) do |i| + arr[offset], arr[offset + i] = arr[offset + i], arr[offset] # Swap + heapify(arr, i, 0, offset) + end +end + +# Helper function to heapify a subtree rooted with node i. +# +# @param arr [Array] The array. +# @param n [Integer] The size of the heap. +# @param i [Integer] The root of the subtree. +# @param offset [Integer] The offset for the start of the array partition. +def heapify(arr, n, i, offset) + largest = i + left = 2 * i + 1 + right = 2 * i + 2 + + largest = left if left < n && arr[offset + left] > arr[offset + largest] + largest = right if right < n && arr[offset + right] > arr[offset + largest] + + return unless largest != i + + arr[offset + i], arr[offset + largest] = arr[offset + largest], arr[offset + i] # Swap + heapify(arr, n, largest, offset) +end + +# --- Driver Code --- +def main + puts '--- Interactive Introsort in Ruby ---' + print 'Enter the elements of the array (space-separated): ' + input = gets.chomp + + if input.strip.empty? + puts 'No input provided. Exiting.' + return + end + + begin + arr = input.split.map(&:to_i) + rescue ArgumentError + puts 'Invalid input. Please enter numbers only. Exiting.' + return + end + + + puts "\nOriginal array: #{arr.inspect}" + introsort(arr) + puts "Sorted array: #{arr.inspect}" +end + +main if __FILE__ == $PROGRAM_NAME \ No newline at end of file diff --git a/ruby/binary_search.rb b/ruby/binary_search.rb new file mode 100644 index 00000000..e981246c --- /dev/null +++ b/ruby/binary_search.rb @@ -0,0 +1,40 @@ +def binary_search(arr, target) + left = 0 + right = arr.length - 1 + + while left <= right + mid = (left + right) / 2 + if arr[mid] == target + return mid + elsif arr[mid] < target + left = mid + 1 + else + right = mid - 1 + end + end + + -1 +end + +def binary_search_recursive(arr, target, left = 0, right = arr.length - 1) + return -1 if left > right + + mid = (left + right) / 2 + if arr[mid] == target + mid + elsif arr[mid] < target + binary_search_recursive(arr, target, mid + 1, right) + else + binary_search_recursive(arr, target, left, mid - 1) + end +end + +arr = [1, 3, 5, 7, 9, 11] + +puts "Iterative Search:" +puts "Index of 7: #{binary_search(arr, 7)}" +puts "Index of 100: #{binary_search(arr, 100)}" + +puts "\nRecursive Search:" +puts "Index of 9: #{binary_search_recursive(arr, 9)}" +puts "Index of 2: #{binary_search_recursive(arr, 2)}" diff --git a/ruby/dfs.rb b/ruby/dfs.rb new file mode 100644 index 00000000..a215b84a --- /dev/null +++ b/ruby/dfs.rb @@ -0,0 +1,9 @@ +def dfs(graph, node, visited = Set.new) + return if visited.include?(node) + visited.add(node) + puts node + + graph[node]&.each do |neighbor| + dfs(graph, neighbor, visited) + end +end \ No newline at end of file diff --git a/ruby/fenwick_Tree.rb b/ruby/fenwick_Tree.rb new file mode 100644 index 00000000..1b9eaa24 --- /dev/null +++ b/ruby/fenwick_Tree.rb @@ -0,0 +1,38 @@ +class FenwickTree + def initialize(size) + @n = size + @bit = Array.new(size + 1, 0) + end + + # Add 'val' to index 'i' (0-based) + def update(i, val) + i += 1 + while i <= @n + @bit[i] += val + i += i & -i + end + end + + # Get prefix sum from 0 to i (0-based) + def query(i) + i += 1 + sum = 0 + while i > 0 + sum += @bit[i] + i -= i & -i + end + sum + end + + # Get sum in range [l, r] (0-based) + def range_sum(l, r) + query(r) - query(l - 1) + end +end + +# Example usage: +ft = FenwickTree.new(10) +ft.update(3, 5) # Add 5 at index 3 +ft.update(5, 2) # Add 2 at index 5 +puts ft.query(5) # Sum from index 0 to 5 → Output: 7 +puts ft.range_sum(3, 5) # Sum from index 3 to 5 → Output: 7 \ No newline at end of file diff --git a/ruby/heap_sort.rb b/ruby/heap_sort.rb new file mode 100644 index 00000000..a8171053 --- /dev/null +++ b/ruby/heap_sort.rb @@ -0,0 +1,28 @@ +def heap_sort(arr) + n = arr.length + + # Build max heap + (n / 2 - 1).downto(0) { |i| heapify(arr, n, i) } + + # Extract elements one by one + (n - 1).downto(1) do |i| + arr[0], arr[i] = arr[i], arr[0] # Swap root with end + heapify(arr, i, 0) # Heapify reduced heap + end + + arr +end + +def heapify(arr, n, i) + largest = i + left = 2 * i + 1 + right = 2 * i + 2 + + largest = left if left < n && arr[left] > arr[largest] + largest = right if right < n && arr[right] > arr[largest] + + if largest != i + arr[i], arr[largest] = arr[largest], arr[i] + heapify(arr, n, largest) + end +end \ No newline at end of file diff --git a/ruby/k-th_smallest_path.rb b/ruby/k-th_smallest_path.rb new file mode 100644 index 00000000..ea6dd60c --- /dev/null +++ b/ruby/k-th_smallest_path.rb @@ -0,0 +1,170 @@ +# Ruby solution: K-th smallest on path using persistent segment tree + LCA +# Works for large n, q when Ruby recursion limits are respected. +# If recursion depth issues occur on very deep trees, you might need to convert DFS to iterative, +# or increase stack, but typical contest inputs are fine with 2e5 and a balanced tree. + +# Read input helper +def read_ints + STDIN.gets.split.map!(&:to_i) +end + +# ---------- Input ---------- +n, q = read_ints +a = [0] + read_ints # 1-indexed values; expects exactly n values + +# adjacency +adj = Array.new(n+1) { [] } +(n-1).times do + u,v = read_ints + adj[u] << v + adj[v] << u +end + +# ---------- Coordinate Compression ---------- +vals = a[1..-1].uniq.sort +compress = {} +vals.each_with_index { |v,i| compress[v] = i+1 } # 1..M +m = vals.length +comp = Array.new(n+1) +(1..n).each { |i| comp[i] = compress[a[i]] } + +# ---------- LCA preparation ---------- +LOG = (Math.log2(n).floor + 2) +parent = Array.new(LOG) { Array.new(n+1, 0) } +depth = Array.new(n+1, 0) + +# ---------- Persistent segment tree structures ---------- +# We'll store nodes as arrays with left index, right index, sum. +left = [0] # index 0 is null node +right = [0] +sumt = [0] +# helper to create node +def new_node(left_arr, right_arr, sumt_arr, l_child, r_child, s) + left_arr << l_child + right_arr << r_child + sumt_arr << s + left_arr.length - 1 +end +# create a null root at index 0 (already present) + +# update: returns new root index based on prev root, adding 1 at position pos +# recursion limits: careful with Ruby recursion for deep segments, but log M small (~20) +def update(prev, l, r, pos, left_arr, right_arr, sumt_arr) + if l == r + # create leaf with sum increased by 1 + return new_node(left_arr, right_arr, sumt_arr, 0, 0, sumt_arr[prev] + 1) + end + mid = (l + r) >> 1 + if pos <= mid + new_left = update(left_arr[prev], l, mid, pos, left_arr, right_arr, sumt_arr) + # right child same as prev's right + prev_right = right_arr[prev] + new_sum = sumt_arr[prev] + 1 + return new_node(left_arr, right_arr, sumt_arr, new_left, prev_right, new_sum) + else + prev_left = left_arr[prev] + new_right = update(right_arr[prev], mid+1, r, pos, left_arr, right_arr, sumt_arr) + new_sum = sumt_arr[prev] + 1 + return new_node(left_arr, right_arr, sumt_arr, prev_left, new_right, new_sum) + end +end + +# Query k-th using four versions: ru, rv, rw, rpw; l..r range +def query_kth(ru, rv, rw, rpw, l, r, k, left_arr, right_arr, sumt_arr) + return -1 if k <= 0 + if l == r + return l + end + mid = (l + r) >> 1 + # count in left children + sum_left = sumt_arr[ left_arr[ru] ] + sumt_arr[ left_arr[rv] ] - sumt_arr[ left_arr[rw] ] - sumt_arr[ left_arr[rpw] ] + if k <= sum_left + query_kth(left_arr[ru], left_arr[rv], left_arr[rw], left_arr[rpw], l, mid, k, left_arr, right_arr, sumt_arr) + else + query_kth(right_arr[ru], right_arr[rv], right_arr[rw], right_arr[rpw], mid+1, r, k - sum_left, left_arr, right_arr, sumt_arr) + end +end + +# versions per node +version = Array.new(n+1, 0) + +# DFS to build parent, depth, version +stack = [] +visited = Array.new(n+1, false) +# iterative DFS: push [node, parent] +stack << [1, 0] +parent[0][1] = 0 +depth[1] = 0 +# We'll do an explicit stack with post-processing to update versions incrementally. +order = [] # DFS order for processing children after parent +while !stack.empty? + u,p = stack.pop + next if visited[u] + visited[u] = true + parent[0][u] = p + depth[u] = (p==0 ? 0 : depth[p] + 1) + order << [u,p] + adj[u].each do |v| + stack << [v,u] unless visited[v] + end +end + +# Build binary lifting table +(1...LOG).each do |j| + (1..n).each do |i| + parent[j][i] = parent[j-1][ parent[j-1][i] ] || 0 + end +end + +# Build versions in order such that parent processed before children. +# The 'order' as built by iterative DFS might visit parent before children if stack LIFO works; +# but to be safe, process increasing depth order so parent always processed earlier: +order.sort_by! { |(u,p)| depth[u] } +order.each do |u,p| + if p == 0 + base = 0 + else + base = version[p] + end + version[u] = update(base, 1, m, comp[u], left, right, sumt) +end + +# LCA function using binary lifting +def lca(u, v, depth, parent, LOG) + if depth[u] < depth[v] + u, v = v, u + end + # lift u + (LOG-1).downto(0) do |j| + if depth[u] - (1<= depth[v] + u = parent[j][u] + end + end + return u if u == v + (LOG-1).downto(0) do |j| + if parent[j][u] != parent[j][v] + u = parent[j][u] + v = parent[j][v] + end + end + return parent[0][u] +end + +# ---------- Answer queries ---------- +out_lines = [] +q.times do + typ, u, v, k = read_ints + if typ == 1 + w = lca(u, v, depth, parent, LOG) + pw = parent[0][w] || 0 + # versions: version[u], version[v], version[w], version[pw] + idx = query_kth(version[u], version[v], version[w], (pw == 0 ? 0 : version[pw]), 1, m, k, left, right, sumt) + # decompress + out_lines << vals[idx-1].to_s + else + # Not implemented: updates if problem variant includes updates. + out_lines << "0" + end +end + +puts out_lines.join("\n") diff --git a/ruby/merge_sort.rb b/ruby/merge_sort.rb new file mode 100644 index 00000000..eee73b25 --- /dev/null +++ b/ruby/merge_sort.rb @@ -0,0 +1,17 @@ +def merge_sort(arr) + return arr if arr.length <= 1 + + mid = arr.length / 2 + left = merge_sort(arr[0...mid]) + right = merge_sort(arr[mid..-1]) + + merge(left, right) +end + +def merge(left, right) + result = [] + until left.empty? || right.empty? + result << (left.first <= right.first ? left.shift : right.shift) + end + result + left + right +end diff --git a/ruby/optimal_network_restoration.rb b/ruby/optimal_network_restoration.rb new file mode 100644 index 00000000..02591b8e --- /dev/null +++ b/ruby/optimal_network_restoration.rb @@ -0,0 +1,106 @@ +# ------------------------------- +# Priority Queue (Min Heap) +# ------------------------------- +class MinHeap + def initialize + @heap = [] + end + + def push(item) + @heap << item + sift_up(@heap.size - 1) + end + + def pop + return nil if @heap.empty? + swap(0, @heap.size - 1) + min = @heap.pop + sift_down(0) + min + end + + def empty? + @heap.empty? + end + + private + + def sift_up(i) + parent = (i - 1) / 2 + return if i <= 0 || @heap[parent][0] <= @heap[i][0] + swap(i, parent) + sift_up(parent) + end + + def sift_down(i) + left = 2 * i + 1 + right = 2 * i + 2 + smallest = i + smallest = left if left < @heap.size && @heap[left][0] < @heap[smallest][0] + smallest = right if right < @heap.size && @heap[right][0] < @heap[smallest][0] + if smallest != i + swap(i, smallest) + sift_down(smallest) + end + end + + def swap(i, j) + @heap[i], @heap[j] = @heap[j], @heap[i] + end +end + +# ------------------------------- +# Network Restoration Solver +# ------------------------------- +class NetworkRestoration + def initialize(edges, budget) + @graph = Hash.new { |h, k| h[k] = [] } + edges.each do |u, v, cost, time| + @graph[u] << [v, cost, time] + @graph[v] << [u, cost, time] + end + @budget = budget + end + + def restore + pq = MinHeap.new + pq.push([0, 0, 0, 0]) # [total_cost, total_time, current_node, connected_count] + visited = {} + best = [0, 0, 0] # [nodes, cost, time] + + until pq.empty? + cost, time, node, count = pq.pop + next if cost > @budget || visited[[node, cost]] + visited[[node, cost]] = true + + best = [count, cost, time] if count > best[0] + + @graph[node].each do |nbr, c, t| + new_cost = cost + c + new_time = time + t + next if new_cost > @budget + pq.push([new_cost, new_time, nbr, count + 1]) + end + end + + best + end +end + +# ------------------------------- +# Example Usage +# ------------------------------- +edges = [ + [0, 1, 5, 2], + [0, 2, 10, 3], + [1, 3, 4, 1], + [2, 3, 6, 2], + [3, 4, 3, 2] +] +budget = 14 + +solver = NetworkRestoration.new(edges, budget) +nodes, total_cost, total_time = solver.restore +puts "Max servers restored: #{nodes}" +puts "Total repair cost: #{total_cost}" +puts "Total repair time: #{total_time}" \ No newline at end of file diff --git a/ruby/search_range.rb b/ruby/search_range.rb new file mode 100644 index 00000000..e2fbdd5d --- /dev/null +++ b/ruby/search_range.rb @@ -0,0 +1,39 @@ +# @param {Integer[]} nums +# @param {Integer} target +# @return {Integer[]} +def search_range(nums, target) + len = nums.length - 1 + return [-1, -1] if len.negative? + return [0, 0] if nums.first == target && len.zero? + return [-1, -1] if len.zero? + + index = binary_search(nums, target, 0, len) + + return index if index == [-1, -1] + + left_index = right_index = index + left = index - 1 + right = index + 1 + + while nums[left] == target || nums[right] == target + left_index = left if nums[left] == target && left >= 0 + right_index = right if nums[right] == target + left -= 1 + right += 1 + end + [left_index, right_index] +end + +def binary_search(array, target, left, right) + return [-1, -1] if left > right + + mid = left + (right - left) / 2 + + if array[mid] == target + mid + elsif array[mid] > target + binary_search(array, target, left, mid - 1) + else + binary_search(array, target, mid + 1, right) + end +end \ No newline at end of file diff --git a/ruby/shippack.rb b/ruby/shippack.rb new file mode 100644 index 00000000..f8f85896 --- /dev/null +++ b/ruby/shippack.rb @@ -0,0 +1,34 @@ +class Solution + def can_ship_within_days(weights, capacity, days) + current_weight = 0 + days_needed = 1 + + weights.each do |weight| + if current_weight + weight > capacity + days_needed += 1 + current_weight = weight + return false if days_needed > days + else + current_weight += weight + end + end + + true + end + + def ship_within_days(weights, days) + left = weights.max + right = weights.sum + + while left < right + mid = left + (right - left) / 2 + if can_ship_within_days(weights, mid, days) + right = mid + else + left = mid + 1 + end + end + + left + end +end diff --git a/ruby/shortest_safe_path_in grid.rb b/ruby/shortest_safe_path_in grid.rb new file mode 100644 index 00000000..dbd85062 --- /dev/null +++ b/ruby/shortest_safe_path_in grid.rb @@ -0,0 +1,95 @@ +class CityRescue + DIRECTIONS = [[1,0], [-1,0], [0,1], [0,-1]] + + def initialize(grid) + @grid = grid + @rows = grid.size + @cols = grid[0].size + @fire_time = Array.new(@rows) { Array.new(@cols, Float::INFINITY) } + @rescue_points = [] + @safe_points = [] + parse_grid + end + + def parse_grid + @rows.times do |r| + @cols.times do |c| + case @grid[r][c] + when 'F' then @fire_time[r][c] = 0 + when 'R' then @rescue_points << [r, c] + when 'S' then @safe_points << [r, c] + end + end + end + end + + def spread_fire + queue = [] + @rows.times do |r| + @cols.times do |c| + queue << [r, c] if @grid[r][c] == 'F' + end + end + + until queue.empty? + r, c = queue.shift + DIRECTIONS.each do |dr, dc| + nr, nc = r + dr, c + dc + next unless valid?(nr, nc) + if @fire_time[nr][nc] == Float::INFINITY + @fire_time[nr][nc] = @fire_time[r][c] + 1 + queue << [nr, nc] + end + end + end + end + + def find_shortest_safe_path + spread_fire + queue = [] + visited = Array.new(@rows) { Array.new(@cols, false) } + + @rescue_points.each do |r, c| + queue << [r, c, 0] + visited[r][c] = true + end + + until queue.empty? + r, c, t = queue.shift + return t if @safe_points.include?([r, c]) + DIRECTIONS.each do |dr, dc| + nr, nc = r + dr, c + dc + next unless valid?(nr, nc) + next if visited[nr][nc] + next if @fire_time[nr][nc] <= t + 1 + visited[nr][nc] = true + queue << [nr, nc, t + 1] + end + end + + nil + end + + private + + def valid?(r, c) + r.between?(0, @rows - 1) && c.between?(0, @cols - 1) && @grid[r][c] != '#' + end +end + +# Example Usage +grid = [ + ['R', '.', '.', 'F', '.'], + ['.', 'F', '.', '.', '.'], + ['.', '.', '.', 'F', '.'], + ['.', '.', '.', '.', 'S'], + ['F', '.', '.', '.', '.'] +] + +solver = CityRescue.new(grid) +result = solver.find_shortest_safe_path +if result + puts "Shortest safe path length: #{result}" +else + puts "No safe path exists." +end diff --git a/ruby/the_whispering_graph.rb b/ruby/the_whispering_graph.rb new file mode 100644 index 00000000..71834fd1 --- /dev/null +++ b/ruby/the_whispering_graph.rb @@ -0,0 +1,48 @@ +# Whispering Graph Problem +# ------------------------ +# Each node whispers its clarity to neighbors. +# The clarity halves each round, and all whispers accumulate. + +def whispering_graph(n, edges, clarities, k) + # Build adjacency list + graph = Array.new(n) { [] } + edges.each do |u, v| + graph[u] << v + graph[v] << u + end + + current = clarities.map(&:to_i) + + k.times do + new_clarities = Array.new(n, 0) + + n.times do |i| + whisper_strength = current[i] / 2 + next if whisper_strength == 0 # Optimization — no point whispering 0s + + graph[i].each do |neighbor| + new_clarities[neighbor] += whisper_strength + end + end + + # Accumulate new whispers into current clarity + n.times { |i| current[i] += new_clarities[i] } + end + + # Return index of node with highest clarity (smallest index in tie) + max_value = current.max + current.index(max_value) +end + + +# ------------------------- +# ✅ Example Usage +# ------------------------- +if __FILE__ == $0 + n = 5 + edges = [[0,1],[1,2],[1,3],[3,4]] + clarities = [10, 5, 2, 8, 1] + k = 2 + + puts whispering_graph(n, edges, clarities, k) # => 1 +end \ No newline at end of file diff --git a/ruby/topological_sort.rb b/ruby/topological_sort.rb new file mode 100644 index 00000000..060740ee --- /dev/null +++ b/ruby/topological_sort.rb @@ -0,0 +1,31 @@ +def topo_sort_dfs(graph) + visited = {} + stack = [] + + graph.keys.each do |node| + dfs(node, graph, visited, stack) unless visited[node] + end + + stack.reverse # topological order +end + +def dfs(node, graph, visited, stack) + visited[node] = true + graph[node].each do |neighbor| + dfs(neighbor, graph, visited, stack) unless visited[neighbor] + end + stack << node +end + +# Example usage +graph = { + 5 => [0, 2], + 4 => [0, 1], + 2 => [3], + 3 => [1], + 0 => [], + 1 => [] +} + +order = topo_sort_dfs(graph) +puts "Topological Order (DFS): #{order.inspect}" diff --git a/ruby/warshsall_algo.rb b/ruby/warshsall_algo.rb new file mode 100644 index 00000000..41e5d46c --- /dev/null +++ b/ruby/warshsall_algo.rb @@ -0,0 +1,43 @@ +def floyd_warshall(n, graph) + dist = Array.new(n) { Array.new(n, Float::INFINITY) } + + # Initialize distances from input graph + n.times do |i| + dist[i][i] = 0 + end + + graph.each do |u, v, w| + dist[u][v] = w + end + + # Floyd-Warshall core logic + n.times do |k| + n.times do |i| + n.times do |j| + if dist[i][k] + dist[k][j] < dist[i][j] + dist[i][j] = dist[i][k] + dist[k][j] + end + end + end + end + + dist +end + +# Example usage: +# Graph edges: [from, to, weight] +edges = [ + [0, 1, 3], + [0, 2, 8], + [1, 2, 2], + [2, 3, 1], + [3, 0, 4] +] + +n = 4 # Number of nodes +result = floyd_warshall(n, edges) + +# Output shortest distances +result.each_with_index do |row, i| + puts "From node #{i}: #{row.map { |d| d == Float::INFINITY ? 'INF' : d }.join(' ')}" +end \ No newline at end of file diff --git a/rust/A_star.rs b/rust/A_star.rs new file mode 100644 index 00000000..850a960f --- /dev/null +++ b/rust/A_star.rs @@ -0,0 +1,129 @@ +use std::collections::{BinaryHeap, HashMap}; +use std::cmp::Ordering; + +// A point on the grid +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +struct Point { + x: i32, + y: i32, +} + +// Node with cost info for A* +#[derive(Clone, Eq, PartialEq)] +struct Node { + position: Point, + cost: i32, // g(n): cost from start to this node + priority: i32, // f(n) = g(n) + h(n) +} + +// Implement ordering so BinaryHeap pops lowest f(n) +impl Ord for Node { + fn cmp(&self, other: &Self) -> Ordering { + other.priority.cmp(&self.priority) + .then_with(|| self.cost.cmp(&other.cost)) + } +} +impl PartialOrd for Node { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// Heuristic function: Manhattan distance +fn heuristic(a: Point, b: Point) -> i32 { + (a.x - b.x).abs() + (a.y - b.y).abs() +} + +// Get all valid neighboring points +fn neighbors(p: Point, width: i32, height: i32) -> Vec { + let mut result = Vec::new(); + let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]; + for (dx, dy) in directions { + let nx = p.x + dx; + let ny = p.y + dy; + if nx >= 0 && nx < width && ny >= 0 && ny < height { + result.push(Point { x: nx, y: ny }); + } + } + result +} + +// A* search function +fn astar( + start: Point, + goal: Point, + width: i32, + height: i32, + obstacles: &Vec, +) -> Option> { + let mut open_set = BinaryHeap::new(); + open_set.push(Node { + position: start, + cost: 0, + priority: heuristic(start, goal), + }); + + let mut came_from: HashMap = HashMap::new(); + let mut cost_so_far: HashMap = HashMap::new(); + cost_so_far.insert(start, 0); + + while let Some(current) = open_set.pop() { + if current.position == goal { + // Reconstruct path + let mut path = vec![goal]; + let mut current = goal; + while let Some(&prev) = came_from.get(¤t) { + path.push(prev); + current = prev; + } + path.reverse(); + return Some(path); + } + + for next in neighbors(current.position, width, height) { + if obstacles.contains(&next) { + continue; // skip obstacles + } + + let new_cost = cost_so_far[¤t.position] + 1; + if !cost_so_far.contains_key(&next) || new_cost < cost_so_far[&next] { + cost_so_far.insert(next, new_cost); + let priority = new_cost + heuristic(next, goal); + open_set.push(Node { + position: next, + cost: new_cost, + priority, + }); + came_from.insert(next, current.position); + } + } + } + + None // no path found +} + +fn main() { + let width = 10; + let height = 10; + + let start = Point { x: 0, y: 0 }; + let goal = Point { x: 7, y: 5 }; + + let obstacles = vec![ + Point { x: 3, y: 1 }, + Point { x: 3, y: 2 }, + Point { x: 3, y: 3 }, + Point { x: 3, y: 4 }, + ]; + + match astar(start, goal, width, height, &obstacles) { + Some(path) => { + println!("Path found:"); + for p in path { + print!("({},{}) ", p.x, p.y); + } + println!(); + } + None => println!("No path found."), + } +} diff --git a/rust/bellman_ford_algo.rs b/rust/bellman_ford_algo.rs new file mode 100644 index 00000000..b29c4d36 --- /dev/null +++ b/rust/bellman_ford_algo.rs @@ -0,0 +1,68 @@ +use std::f64; + +#[derive(Debug)] +struct Edge { + src: usize, + dest: usize, + weight: f64, +} + +fn bellman_ford(vertices: usize, edges: &Vec, src: usize) -> Option> { + let mut dist = vec![f64::INFINITY; vertices]; + dist[src] = 0.0; + + // Step 1: Relax edges |V| - 1 times + for _ in 0..vertices - 1 { + let mut updated = false; + for edge in edges.iter() { + if dist[edge.src] + edge.weight < dist[edge.dest] { + dist[edge.dest] = dist[edge.src] + edge.weight; + updated = true; + } + } + // Optimization: if no update in a full pass, stop early + if !updated { + break; + } + } + + // Step 2: Detect negative weight cycles + for edge in edges.iter() { + if dist[edge.src] + edge.weight < dist[edge.dest] { + println!("Graph contains a negative weight cycle!"); + return None; + } + } + + Some(dist) +} + +fn main() { + // Example graph (directed, weighted) + let vertices = 5; + let edges = vec![ + Edge { src: 0, dest: 1, weight: -1.0 }, + Edge { src: 0, dest: 2, weight: 4.0 }, + Edge { src: 1, dest: 2, weight: 3.0 }, + Edge { src: 1, dest: 3, weight: 2.0 }, + Edge { src: 1, dest: 4, weight: 2.0 }, + Edge { src: 3, dest: 2, weight: 5.0 }, + Edge { src: 3, dest: 1, weight: 1.0 }, + Edge { src: 4, dest: 3, weight: -3.0 }, + ]; + + let source = 0; + match bellman_ford(vertices, &edges, source) { + Some(distances) => { + println!("Vertex\tDistance from Source ({})", source); + for (i, &d) in distances.iter().enumerate() { + if d == f64::INFINITY { + println!("{}\t{}", i, "∞"); + } else { + println!("{}\t{:.1}", i, d); + } + } + } + None => println!("Negative weight cycle detected, no valid shortest paths!"), + } +} diff --git a/rust/bfs.rs b/rust/bfs.rs new file mode 100644 index 00000000..6ab85e4d --- /dev/null +++ b/rust/bfs.rs @@ -0,0 +1,34 @@ +use std::collections::VecDeque; + +fn bfs(adj: &Vec>, start: usize) -> Vec { + let n = adj.len(); + let mut visited = vec![false; n]; + let mut order = Vec::new(); + let mut q = VecDeque::new(); + visited[start] = true; + q.push_back(start); + while let Some(u) = q.pop_front() { + order.push(u); + for &v in &adj[u] { + if !visited[v] { + visited[v] = true; + q.push_back(v); + } + } + } + order +} + +fn main() { + let adj = vec![ + vec![1, 2], + vec![0, 3], + vec![0, 3], + vec![1, 2, 4], + vec![3], + ]; + let order = bfs(&adj, 0); + for v in order { + println!("{}", v); + } +} diff --git a/rust/binary_search.rs b/rust/binary_search.rs new file mode 100644 index 00000000..2044f22d --- /dev/null +++ b/rust/binary_search.rs @@ -0,0 +1,26 @@ +fn binary_search(arr: &[i32], target: i32) -> Option { + let mut low = 0; + let mut high = arr.len(); + + while low < high { + let mid = low + (high - low) / 2; + if arr[mid] == target { + return Some(mid); + } else if arr[mid] < target { + low = mid + 1; + } else { + high = mid; + } + } + None +} + +fn main() { + let arr = [1, 3, 5, 7, 9, 11, 13]; + let target = 7; + + match binary_search(&arr, target) { + Some(index) => println!("Found {} at index {}", target, index), + None => println!("{} not found in array", target), + } +} diff --git a/rust/bubble_sort.rs b/rust/bubble_sort.rs new file mode 100644 index 00000000..9c562179 --- /dev/null +++ b/rust/bubble_sort.rs @@ -0,0 +1,28 @@ +fn bubble_sort(arr: &mut [i32]) { + let n = arr.len(); + + for i in 0..n { + let mut swapped = false; + + for j in 0..(n - i - 1) { + if arr[j] > arr[j + 1] { + arr.swap(j, j + 1); + swapped = true; + } + } + + // If no elements were swapped in this pass, array is sorted + if !swapped { + break; + } + } +} + +fn main() { + let mut arr = [64, 34, 25, 12, 22, 11, 90]; + println!("Before sorting: {:?}", arr); + + bubble_sort(&mut arr); + + println!("After sorting: {:?}", arr); +} diff --git a/rust/decision_tree.rs b/rust/decision_tree.rs new file mode 100644 index 00000000..e6046838 --- /dev/null +++ b/rust/decision_tree.rs @@ -0,0 +1,145 @@ +use std::collections::HashMap; + +/// Calculate entropy of a dataset +fn entropy(labels: &Vec) -> f64 { + let mut counts = HashMap::new(); + for label in labels { + *counts.entry(label).or_insert(0) += 1; + } + + let total = labels.len() as f64; + let mut ent = 0.0; + + for count in counts.values() { + let p = *count as f64 / total; + ent -= p * p.log2(); + } + + ent +} + +/// Structure representing a dataset +#[derive(Debug, Clone)] +struct Dataset { + features: Vec>, + labels: Vec, +} + +/// A Decision Tree Node +#[derive(Debug)] +enum Node { + Leaf(String), + Decision { + feature_index: usize, + threshold: f64, + left: Box, + right: Box, + }, +} + +/// Split dataset based on a feature threshold +fn split_dataset(dataset: &Dataset, feature_index: usize, threshold: f64) -> (Dataset, Dataset) { + let mut left_features = vec![]; + let mut left_labels = vec![]; + let mut right_features = vec![]; + let mut right_labels = vec![]; + + for i in 0..dataset.features.len() { + if dataset.features[i][feature_index] <= threshold { + left_features.push(dataset.features[i].clone()); + left_labels.push(dataset.labels[i].clone()); + } else { + right_features.push(dataset.features[i].clone()); + right_labels.push(dataset.labels[i].clone()); + } + } + + ( + Dataset { features: left_features, labels: left_labels }, + Dataset { features: right_features, labels: right_labels }, + ) +} + +/// Build the decision tree recursively +fn build_tree(dataset: &Dataset, depth: usize) -> Node { + if depth == 0 || dataset.labels.iter().all(|x| *x == dataset.labels[0]) { + // Leaf node + return Node::Leaf(dataset.labels[0].clone()); + } + + let mut best_gain = 0.0; + let mut best_feature = 0; + let mut best_threshold = 0.0; + let current_entropy = entropy(&dataset.labels); + + for feature_index in 0..dataset.features[0].len() { + for sample in &dataset.features { + let threshold = sample[feature_index]; + let (left, right) = split_dataset(dataset, feature_index, threshold); + + if left.labels.is_empty() || right.labels.is_empty() { + continue; + } + + let p_left = left.labels.len() as f64 / dataset.labels.len() as f64; + let gain = current_entropy + - (p_left * entropy(&left.labels) + (1.0 - p_left) * entropy(&right.labels)); + + if gain > best_gain { + best_gain = gain; + best_feature = feature_index; + best_threshold = threshold; + } + } + } + + if best_gain == 0.0 { + return Node::Leaf(dataset.labels[0].clone()); + } + + let (left, right) = split_dataset(dataset, best_feature, best_threshold); + Node::Decision { + feature_index: best_feature, + threshold: best_threshold, + left: Box::new(build_tree(&left, depth - 1)), + right: Box::new(build_tree(&right, depth - 1)), + } +} + +/// Predict the label for a given sample +fn predict(node: &Node, sample: &Vec) -> String { + match node { + Node::Leaf(label) => label.clone(), + Node::Decision { feature_index, threshold, left, right } => { + if sample[*feature_index] <= *threshold { + predict(left, sample) + } else { + predict(right, sample) + } + } + } +} + +fn main() { + let dataset = Dataset { + features: vec![ + vec![2.0, 3.0], + vec![1.0, 5.0], + vec![3.0, 2.0], + vec![5.0, 1.0], + ], + labels: vec![ + "A".to_string(), + "A".to_string(), + "B".to_string(), + "B".to_string(), + ], + }; + + let tree = build_tree(&dataset, 3); + println!("Trained Tree: {:#?}", tree); + + let test_sample = vec![2.5, 3.0]; + let prediction = predict(&tree, &test_sample); + println!("Prediction for {:?}: {}", test_sample, prediction); +} diff --git a/rust/dfs.rs b/rust/dfs.rs new file mode 100644 index 00000000..ebe38d35 --- /dev/null +++ b/rust/dfs.rs @@ -0,0 +1,31 @@ +fn dfs_util(u: usize, adj: &Vec>, visited: &mut Vec, order: &mut Vec) { + visited[u] = true; + order.push(u); + for &v in &adj[u] { + if !visited[v] { + dfs_util(v, adj, visited, order); + } + } +} + +fn dfs(adj: &Vec>, start: usize) -> Vec { + let n = adj.len(); + let mut visited = vec![false; n]; + let mut order = Vec::new(); + dfs_util(start, adj, &mut visited, &mut order); + order +} + +fn main() { + let adj = vec![ + vec![1, 2], + vec![0, 3], + vec![0, 3], + vec![1, 2, 4], + vec![3], + ]; + let order = dfs(&adj, 0); + for v in order { + println!("{}", v); + } +} diff --git a/rust/dijkstra_algorithm.rs b/rust/dijkstra_algorithm.rs new file mode 100644 index 00000000..bf941064 --- /dev/null +++ b/rust/dijkstra_algorithm.rs @@ -0,0 +1,77 @@ +use std::collections::BinaryHeap; +use std::cmp::Ordering; + +#[derive(Copy, Clone, Eq, PartialEq)] +struct State { + cost: usize, + position: usize, +} + +// Implement `Ord` for min-heap using BinaryHeap +impl Ord for State { + fn cmp(&self, other: &Self) -> Ordering { + // Notice we flip the ordering here + other.cost.cmp(&self.cost) + } +} + +impl PartialOrd for State { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +// Edge structure +#[derive(Copy, Clone)] +struct Edge { + node: usize, + weight: usize, +} + +// Dijkstra’s Algorithm +fn dijkstra(graph: &Vec>, start: usize) -> Vec { + let n = graph.len(); + let mut dist = vec![usize::MAX; n]; + let mut heap = BinaryHeap::new(); + + dist[start] = 0; + heap.push(State { cost: 0, position: start }); + + while let Some(State { cost, position }) = heap.pop() { + if cost > dist[position] { + continue; + } + + for edge in &graph[position] { + let next = State { cost: cost + edge.weight, position: edge.node }; + if next.cost < dist[next.position] { + dist[next.position] = next.cost; + heap.push(next); + } + } + } + + dist +} + +fn main() { + // Graph represented as adjacency list + // Each node has a vector of edges (neighbor, weight) + let graph = vec![ + vec![Edge { node: 1, weight: 4 }, Edge { node: 2, weight: 1 }], + vec![Edge { node: 3, weight: 1 }], + vec![Edge { node: 1, weight: 2 }, Edge { node: 3, weight: 5 }], + vec![], + ]; + + let start = 0; + let distances = dijkstra(&graph, start); + + for (i, &d) in distances.iter().enumerate() { + if d == usize::MAX { + println!("Vertex {} is unreachable", i); + } else { + println!("Distance from {} to {} is {}", start, i, d); + } + } +} diff --git a/rust/helloworld.rs b/rust/helloworld.rs index 0672e510..e5a8cbd5 100644 --- a/rust/helloworld.rs +++ b/rust/helloworld.rs @@ -1,3 +1,3 @@ fn main() { - println!("Hello, World!"); + println!("Hello, Rust 2025"); } diff --git a/rust/introsort.rs b/rust/introsort.rs new file mode 100644 index 00000000..75969b01 --- /dev/null +++ b/rust/introsort.rs @@ -0,0 +1,154 @@ +// Introsort implementation in Rust (generic, in-place) +pub fn introsort(arr: &mut [T]) { + if arr.len() <= 1 { return; } + let depth_limit = 2 * ((arr.len() as f64).log2().floor() as usize); + introsort_impl(arr, depth_limit); +} + +fn introsort_impl(arr: &mut [T], mut depth_limit: usize) { + const INSERTION_THRESHOLD: usize = 16; + + let mut low = 0usize; + let mut high = arr.len(); + + // Use a manual stack to avoid deep recursion on tail calls + let mut stack: Vec<(usize, usize, usize)> = Vec::new(); + stack.push((low, high, depth_limit)); + + while let Some((lo, hi, depth)) = stack.pop() { + let len = hi.saturating_sub(lo); + if len <= 1 { continue; } + + if len <= INSERTION_THRESHOLD { + insertion_sort(&mut arr[lo..hi]); + continue; + } + + if depth == 0 { + heapsort(&mut arr[lo..hi]); + continue; + } + + // Partition with median-of-three pivot + let pivot_index = partition_median3(&mut arr[lo..hi]); + // pivot_index is relative to the subslice [lo..hi] + // push larger side first so smaller side is processed next (keeps stack small) + let left_len = pivot_index; + let right_len = len - pivot_index - 1; + + if left_len < right_len { + // push right, then left + if pivot_index + 1 < len { + stack.push((lo + pivot_index + 1, hi, depth - 1)); + } + if left_len > 0 { + stack.push((lo, lo + pivot_index, depth - 1)); + } + } else { + if left_len > 0 { + stack.push((lo, lo + pivot_index, depth - 1)); + } + if pivot_index + 1 < len { + stack.push((lo + pivot_index + 1, hi, depth - 1)); + } + } + } +} + +fn insertion_sort(slice: &mut [T]) { + for i in 1..slice.len() { + let mut j = i; + while j > 0 && slice[j] < slice[j - 1] { + slice.swap(j, j - 1); + j -= 1; + } + } +} + +fn partition_median3(slice: &mut [T]) -> usize { + let len = slice.len(); + let mid = len / 2; + // choose indices 0, mid, len-1 -> median-of-three + let (a, b, c) = (0usize, mid, len - 1); + // reorder such that slice[a] <= slice[b] <= slice[c] + if slice[a] > slice[b] { slice.swap(a, b); } + if slice[b] > slice[c] { slice.swap(b, c); } + if slice[a] > slice[b] { slice.swap(a, b); } + + // move pivot to end-1 (so we'll partition excluding last element) + slice.swap(b, len - 1); + let pivot_idx = len - 1; + let mut i = 0usize; + for j in 0..(len - 1) { + if slice[j] <= slice[pivot_idx] { + slice.swap(i, j); + i += 1; + } + } + slice.swap(i, pivot_idx); + i +} + +fn heapsort(slice: &mut [T]) { + let len = slice.len(); + if len <= 1 { return; } + + // build max heap + for start in (0..=(len/2)).rev() { + sift_down(slice, start, len); + } + + // sortdown + for end in (1..len).rev() { + slice.swap(0, end); + sift_down(slice, 0, end); + } + + fn sift_down(slice: &mut [T], start: usize, end: usize) { + let mut root = start; + loop { + let left = 2 * root + 1; + if left >= end { break; } + let mut swap = root; + if slice[swap] < slice[left] { + swap = left; + } + let right = left + 1; + if right < end && slice[swap] < slice[right] { + swap = right; + } + if swap == root { break; } + slice.swap(root, swap); + root = swap; + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_introsort_simple() { + let mut v = vec![3, 1, 4, 1, 5, 9, 2, 6, 5]; + introsort(&mut v); + assert_eq!(v, { + let mut t = vec![1,1,2,3,4,5,5,6,9]; + t + }); + } + + #[test] + fn test_introsort_sorted() { + let mut v: Vec = (0..100).collect(); + introsort(&mut v); + assert_eq!(v, (0..100).collect::>()); + } + + #[test] + fn test_introsort_reverse() { + let mut v: Vec = (0..100).rev().collect(); + introsort(&mut v); + assert_eq!(v, (0..100).collect::>()); + } +} diff --git a/rust/merge_sort.rs b/rust/merge_sort.rs new file mode 100644 index 00000000..0902110c --- /dev/null +++ b/rust/merge_sort.rs @@ -0,0 +1,57 @@ +fn merge_sort(arr: &mut [i32]) { + let len = arr.len(); + if len <= 1 { + return; // base case + } + + let mid = len / 2; + let mut left = arr[..mid].to_vec(); + let mut right = arr[mid..].to_vec(); + + // Recursively sort both halves + merge_sort(&mut left); + merge_sort(&mut right); + + // Merge the sorted halves + merge(arr, &left, &right); +} + +fn merge(arr: &mut [i32], left: &[i32], right: &[i32]) { + let mut i = 0; // index for left + let mut j = 0; // index for right + let mut k = 0; // index for arr + + while i < left.len() && j < right.len() { + if left[i] <= right[j] { + arr[k] = left[i]; + i += 1; + } else { + arr[k] = right[j]; + j += 1; + } + k += 1; + } + + // Copy remaining elements from left + while i < left.len() { + arr[k] = left[i]; + i += 1; + k += 1; + } + + // Copy remaining elements from right + while j < right.len() { + arr[k] = right[j]; + j += 1; + k += 1; + } +} + +fn main() { + let mut arr = [38, 27, 43, 3, 9, 82, 10]; + println!("Before sorting: {:?}", arr); + + merge_sort(&mut arr); + + println!("After sorting: {:?}", arr); +} diff --git a/rust/min_max_array.rs b/rust/min_max_array.rs new file mode 100644 index 00000000..d32c980a --- /dev/null +++ b/rust/min_max_array.rs @@ -0,0 +1,12 @@ +fn main() { + let arr = [45, 12, 67, 23, 89, 34]; + let mut max = arr[0]; + let mut min = arr[0]; + + for &val in arr.iter() { + if val > max { max = val; } + if val < min { min = val; } + } + + println!("Max = {}, Min = {}", max, min); +} diff --git a/rust/priority_queue.rs b/rust/priority_queue.rs new file mode 100644 index 00000000..1c0e3886 --- /dev/null +++ b/rust/priority_queue.rs @@ -0,0 +1,17 @@ +use std::collections::BinaryHeap; + +fn main() { + let mut pq = BinaryHeap::new(); + + // Push elements + pq.push(10); + pq.push(5); + pq.push(20); + pq.push(15); + + println!("Priority Queue (Max-Heap):"); + + while let Some(val) = pq.pop() { + println!("{}", val); // Elements come in descending order + } +} diff --git a/rust/quick_sort.rs b/rust/quick_sort.rs new file mode 100644 index 00000000..906b5595 --- /dev/null +++ b/rust/quick_sort.rs @@ -0,0 +1,38 @@ +fn quick_sort(arr: &mut [i32]) { + if arr.len() <= 1 { + return; // base case + } + + let pivot_index = partition(arr); + + // Recursively sort left and right partitions + let (left, right) = arr.split_at_mut(pivot_index); + quick_sort(left); + quick_sort(&mut right[1..]); // skip pivot +} + +fn partition(arr: &mut [i32]) -> usize { + let len = arr.len(); + let pivot_index = len - 1; // choose last element as pivot + let pivot = arr[pivot_index]; + let mut i = 0; + + for j in 0..pivot_index { + if arr[j] <= pivot { + arr.swap(i, j); + i += 1; + } + } + + arr.swap(i, pivot_index); + i +} + +fn main() { + let mut arr = [34, 7, 23, 32, 5, 62]; + println!("Before sorting: {:?}", arr); + + quick_sort(&mut arr); + + println!("After sorting: {:?}", arr); +} diff --git a/rust/rabin_karp.rs b/rust/rabin_karp.rs new file mode 100644 index 00000000..d3c558e9 --- /dev/null +++ b/rust/rabin_karp.rs @@ -0,0 +1,52 @@ +fn rabin_karp(text: &str, pattern: &str) { + let d: u64 = 256; // Number of characters in input alphabet + let q: u64 = 101; // A prime number for modulo + let m = pattern.len(); + let n = text.len(); + + if m > n { + println!("Pattern is longer than text — no match."); + return; + } + + let text_bytes = text.as_bytes(); + let pattern_bytes = pattern.as_bytes(); + + let mut p: u64 = 0; // hash for pattern + let mut t: u64 = 0; // hash for text window + let mut h: u64 = 1; // d^(m-1) % q + + // Precompute h = pow(d, m-1) % q + for _ in 0..m - 1 { + h = (h * d) % q; + } + + // Compute initial hash values for pattern and first window + for i in 0..m { + p = (d * p + pattern_bytes[i] as u64) % q; + t = (d * t + text_bytes[i] as u64) % q; + } + + // Slide the pattern over the text + for i in 0..=(n - m) { + // Check if hashes match + if p == t { + // Double-check characters + if &text[i..i + m] == pattern { + println!("Pattern found at index {}", i); + } + } + + // Compute hash for next window + if i < n - m { + t = (d * (t + q - (text_bytes[i] as u64 * h) % q) + text_bytes[i + m] as u64) % q; + } + } +} + +fn main() { + let text = "ABCCDDAEFG"; + let pattern = "CDD"; + + rabin_karp(text, pattern); +} diff --git a/rust/reverse_array.rs b/rust/reverse_array.rs new file mode 100644 index 00000000..30c5cc64 --- /dev/null +++ b/rust/reverse_array.rs @@ -0,0 +1,10 @@ +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + let n = arr.len(); + + for i in 0..n / 2 { + arr.swap(i, n - i - 1); + } + + println!("Reversed Array: {:?}", arr); +} diff --git a/rust/rotate_array.rs b/rust/rotate_array.rs new file mode 100644 index 00000000..999b1238 --- /dev/null +++ b/rust/rotate_array.rs @@ -0,0 +1,10 @@ +fn rotate_right(arr: &mut [i32], k: usize) { + let n = arr.len(); + arr.rotate_right(k % n); +} + +fn main() { + let mut arr = [1, 2, 3, 4, 5]; + rotate_right(&mut arr, 2); + println!("After Rotation: {:?}", arr); +} diff --git a/rust/ship.rs b/rust/ship.rs new file mode 100644 index 00000000..a1f94478 --- /dev/null +++ b/rust/ship.rs @@ -0,0 +1,37 @@ +impl Solution { + fn can_ship_within_days(weights: &Vec, capacity: i32, days: i32) -> bool { + let mut current_weight = 0; + let mut days_needed = 1; + + for &weight in weights.iter() { + if current_weight + weight > capacity { + days_needed += 1; + current_weight = weight; + if days_needed > days { + return false; + } + } else { + current_weight += weight; + } + } + true + } + + pub fn ship_within_days(weights: Vec, days: i32) -> i32 { + let mut left = *weights.iter().max().unwrap(); + let mut right: i32 = weights.iter().sum(); + + while left < right { + let mid = left + (right - left) / 2; + if Solution::can_ship_within_days(&weights, mid, days) { + right = mid; + } else { + left = mid + 1; + } + } + + left + } +} + +struct Solution; diff --git a/rust/ternary_search.rs b/rust/ternary_search.rs new file mode 100644 index 00000000..0e5c82b7 --- /dev/null +++ b/rust/ternary_search.rs @@ -0,0 +1,40 @@ +fn ternary_search(arr: &[i32], target: i32) -> Option { + let mut left = 0; + let mut right = arr.len() - 1; + + while left <= right { + let mid1 = left + (right - left) / 3; + let mid2 = right - (right - left) / 3; + + if arr[mid1] == target { + return Some(mid1); + } + if arr[mid2] == target { + return Some(mid2); + } + + if target < arr[mid1] { + // Search in left one-third + if mid1 == 0 { break; } // prevent underflow + right = mid1 - 1; + } else if target > arr[mid2] { + // Search in right one-third + left = mid2 + 1; + } else { + // Search in middle one-third + left = mid1 + 1; + right = mid2 - 1; + } + } + None +} + +fn main() { + let arr = [2, 4, 6, 8, 10, 12, 14, 16, 18]; + let target = 14; + + match ternary_search(&arr, target) { + Some(index) => println!("Found {} at index {}", target, index), + None => println!("{} not found in array", target), + } +} diff --git a/swift/z_algorithm b/swift/z_algorithm new file mode 100644 index 00000000..d7fcf840 Binary files /dev/null and b/swift/z_algorithm differ diff --git a/swift/z_algorithm.swift b/swift/z_algorithm.swift new file mode 100644 index 00000000..fe3cfa75 --- /dev/null +++ b/swift/z_algorithm.swift @@ -0,0 +1,38 @@ +// Z-Algorithm Implementation in Swift +// The Z-algorithm computes the Z-array for a string, where Z[i] is the length of the longest substring +// starting at position i that matches the prefix of the string. +// This is useful for string pattern matching and other string algorithms. + +import Foundation + +func zAlgorithm(for string: String) -> [Int] { + let chars = Array(string) + let n = chars.count + var z = [Int](repeating: 0, count: n) + var l = 0 + var r = 0 + + for i in 1.. r { + l = i + r = i + z[i] + } + } + return z +} + +// Example usage +let inputString = "aabcaabxaaz" +let zArray = zAlgorithm(for: inputString) +print("Z-array for '\(inputString)': \(zArray)") + +// Explanation: +// For string "aabcaabxaaz", the Z-array would be [0, 1, 0, 0, 3, 1, 0, 0, 2, 1, 0] +// Z[4] = 3 because "aab" matches the prefix "aab" +// Z[8] = 2 because "aa" matches the prefix "aa" diff --git a/swimInWater.cpp b/swimInWater.cpp new file mode 100644 index 00000000..7d92ca60 --- /dev/null +++ b/swimInWater.cpp @@ -0,0 +1,28 @@ + + int swimInWater(vector>& grid) { + int m = grid.size(), n = grid[0].size(); + priority_queue, vector>, greater<>> pq; + vector> directions = {{0,1}, {1,0}, {0,-1}, {-1,0}}; + set> seen; + + pq.push({grid[0][0], 0, 0}); + + while (!pq.empty()) { + auto [max_d, r, c] = pq.top(); + pq.pop(); + + if (seen.count({r, c})) continue; + seen.insert({r, c}); + + if (r == m-1 && c == n-1) return max_d; + + for (auto [dr, dc] : directions) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && !seen.count({nr, nc})) { + int new_d = max(max_d, grid[nr][nc]); + pq.push({new_d, nr, nc}); + } + } + } + return -1; + } diff --git a/tests/JAVA/CycleSortTest.java b/tests/JAVA/CycleSortTest.java new file mode 100644 index 00000000..4e4c0787 --- /dev/null +++ b/tests/JAVA/CycleSortTest.java @@ -0,0 +1,48 @@ +package tests.JAVA; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; + +class CycleSortTest { + + @Test + void testBasicSorting() { + int[] arr = {3, 1, 5, 4, 2}; + int[] sorted = {1, 2, 3, 4, 5}; + assertArrayEquals(sorted, CycleSort.sortArray(arr)); + } + + @Test + void testAlreadySorted() { + int[] arr = {1, 2, 3, 4, 5}; + assertArrayEquals(arr, CycleSort.sortArray(arr)); + } + + @Test + void testReverseSorted() { + int[] arr = {5, 4, 3, 2, 1}; + int[] sorted = {1, 2, 3, 4, 5}; + assertArrayEquals(sorted, CycleSort.sortArray(arr)); + } + + @Test + void testSingleElement() { + int[] arr = {1}; + assertArrayEquals(new int[]{1}, CycleSort.sortArray(arr)); + } + + @Test + void testEmptyArray() { + int[] arr = {}; + assertArrayEquals(new int[]{}, CycleSort.sortArray(arr)); + } + + @Test + void testLargeArray() { + int n = 1000; + int[] arr = new int[n]; + for (int i = 0; i < n; i++) arr[i] = n - i; + int[] expected = new int[n]; + for (int i = 0; i < n; i++) expected[i] = i + 1; + assertArrayEquals(expected, CycleSort.sortArray(arr)); + } +} diff --git a/tests/JAVA/Test.java b/tests/JAVA/Test.java new file mode 100644 index 00000000..a38cbabf --- /dev/null +++ b/tests/JAVA/Test.java @@ -0,0 +1,5 @@ +package tests.JAVA; + +public @interface Test { + +} diff --git a/typescript/add.ts b/typescript/add.ts new file mode 100644 index 00000000..48f2fe3a --- /dev/null +++ b/typescript/add.ts @@ -0,0 +1,10 @@ +// Add two number +function addNumbers(a: number, b: number): number { + return a + b; +} + +const num1: number = 10; +const num2: number = 20; + +const sum: number = addNumbers(num1, num2); +console.log(`The sum of ${num1} and ${num2} is: ${sum}`); diff --git a/typscript/apiResponseHandler.ts b/typescript/apiResponseHandler.ts similarity index 62% rename from typscript/apiResponseHandler.ts rename to typescript/apiResponseHandler.ts index 90690ab2..faf0df59 100644 --- a/typscript/apiResponseHandler.ts +++ b/typescript/apiResponseHandler.ts @@ -1,5 +1,5 @@ type ApiResponse = { - status: 'success' | 'error'; + status: "success" | "error"; data: T; message?: string; }; @@ -25,33 +25,33 @@ type ProductApiResponseHandler = ApiResponseHandler; const userHandler: UserApiResponseHandler = { handleResponse: (response) => { - if (response.status === 'success') { - console.log('User data:', response.data); + if (response.status === "success") { + console.log("User data:", response.data); } else { - console.error('Error:', response.message); + console.error("Error:", response.message); } }, }; const productHandler: ProductApiResponseHandler = { handleResponse: (response) => { - if (response.status === 'success') { - console.log('Product data:', response.data); + if (response.status === "success") { + console.log("Product data:", response.data); } else { - console.error('Error:', response.message); + console.error("Error:", response.message); } }, }; const userResponse: ApiResponse = { - status: 'success', - data: { id: 1, name: 'John Doe', email: 'john.doe@example.com' }, + status: "success", + data: { id: 1, name: "John Doe", email: "john.doe@example.com" }, }; const productResponse: ApiResponse = { - status: 'error', - data: { id: 1, name: 'Laptop', price: 999 }, - message: 'Product not found', + status: "error", + data: { id: 1, name: "Laptop", price: 999 }, + message: "Product not found", }; userHandler.handleResponse(userResponse); diff --git a/typescript/bfs.ts b/typescript/bfs.ts new file mode 100644 index 00000000..3f8f6581 --- /dev/null +++ b/typescript/bfs.ts @@ -0,0 +1,60 @@ +// Define the graph structure using an adjacency list. +// Key is the vertex index (number), value is an array of neighbors. +type AdjacencyList = { [key: number]: number[] }; + +/** + * Performs a Breadth-First Search (BFS) traversal starting from a source node. + * @param graph The graph represented as an adjacency list. + * @param startNode The starting vertex for the traversal. + * @returns An array of nodes in the order they were visited. + */ +function breadthFirstSearch(graph: AdjacencyList, startNode: number): number[] { + // Check if the start node exists + if (!graph[startNode]) { + return []; + } + + const visited: Set = new Set(); + const queue: number[] = [startNode]; + const result: number[] = []; + + visited.add(startNode); + + // Continue as long as there are nodes to process + while (queue.length > 0) { + // Dequeue the first node + const node = queue.shift()!; + result.push(node); + + // Get all neighbors of the current node + const neighbors = graph[node]; + + // Process each neighbor + for (const neighbor of neighbors) { + if (!visited.has(neighbor)) { + visited.add(neighbor); + queue.push(neighbor); // Enqueue the unvisited neighbor + } + } + } + + return result; +} + +// --- Usage Example --- +const V_BFS = 6; // Vertices 0 to 5 +const graphBFS: AdjacencyList = { + 0: [1, 2], + 1: [3], + 2: [4, 5], + 3: [0], + 4: [], + 5: [2], +}; + +const traversalOrder = breadthFirstSearch(graphBFS, 0); +console.log("\n--- Breadth-First Search (BFS) Traversal ---"); +console.log( + `Traversal Order (starting from 0): [${traversalOrder.join(", ")}]`, +); +// Expected Output: [0, 1, 2, 3, 4, 5] diff --git a/typescript/binarySearch.ts b/typescript/binarySearch.ts new file mode 100644 index 00000000..9139ccf4 --- /dev/null +++ b/typescript/binarySearch.ts @@ -0,0 +1,19 @@ +function binarySearch(arr: number[], target: number): number { + let left = 0; + let right = arr.length - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const midValue = arr[mid]; + + if (midValue === target) { + return mid; // Target found, return index + } else if (midValue < target) { + left = mid + 1; // Search in the right half + } else { + right = mid - 1; // Search in the left half + } + } + + return -1; // Target not found +} diff --git a/typescript/deep_object.ts b/typescript/deep_object.ts new file mode 100644 index 00000000..95d3aebd --- /dev/null +++ b/typescript/deep_object.ts @@ -0,0 +1,18 @@ +type AnyObject = Record; + +function flattenObject(obj: AnyObject, parentKey = '', result: AnyObject = {}): AnyObject { + for (const key in obj) { + if (!obj.hasOwnProperty(key)) continue; + const newKey = parentKey ? `${parentKey}.${key}` : key; + if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) { + flattenObject(obj[key], newKey, result); + } else { + result[newKey] = obj[key]; + } + } + return result; +} + +// Usage +const input = { a: { b: { c: 1 } }, d: 2 }; +console.log(flattenObject(input)); // { 'a.b.c': 1, d: 2 } diff --git a/typescript/dfss.ts b/typescript/dfss.ts new file mode 100644 index 00000000..296e4840 --- /dev/null +++ b/typescript/dfss.ts @@ -0,0 +1,26 @@ +function topologicalSort(nodes: string[], edges: [string,string][]): string[] { + const graph = new Map(); + nodes.forEach(n => graph.set(n, [])); + edges.forEach(([u,v]) => graph.get(u)!.push(v)); + + const visited = new Set(); + const stack: string[] = []; + + function dfs(node: string) { + visited.add(node); + for(const nei of graph.get(node)!) { + if(!visited.has(nei)) dfs(nei); + } + stack.push(node); + } + + for(const node of nodes) { + if(!visited.has(node)) dfs(node); + } + + return stack.reverse(); +} + +// Usage +console.log(topologicalSort(['A','B','C','D'], [['A','B'],['B','C'],['A','C'],['C','D']])); +// ['A','B','C','D'] diff --git a/typescript/djikstraAlgorithm.ts b/typescript/djikstraAlgorithm.ts new file mode 100644 index 00000000..45fe269a --- /dev/null +++ b/typescript/djikstraAlgorithm.ts @@ -0,0 +1,40 @@ +type Graph = Map; + +function dijkstra(graph: Graph, start: string): Map { + const distances = new Map(); + const visited = new Set(); + + // Initialize distances to Infinity + for (const node of graph.keys()) { + distances.set(node, Infinity); + } + + distances.set(start, 0); + + while (visited.size < graph.size) { + // Find unvisited node with the smallest distance + let currentNode: string | null = null; + let smallestDistance = Infinity; + + for (const [node, distance] of distances) { + if (!visited.has(node) && distance < smallestDistance) { + smallestDistance = distance; + currentNode = node; + } + } + + if (currentNode === null) break; + + visited.add(currentNode); + + const neighbors = graph.get(currentNode) || []; + for (const [neighbor, weight] of neighbors) { + const currentDistance = distances.get(currentNode)! + weight; + if (currentDistance < distances.get(neighbor)!) { + distances.set(neighbor, currentDistance); + } + } + } + + return distances; +} diff --git a/typescript/heap.ts b/typescript/heap.ts new file mode 100644 index 00000000..a0eaf317 --- /dev/null +++ b/typescript/heap.ts @@ -0,0 +1,23 @@ +function wordLadder(beginWord: string, endWord: string, wordList: string[]): number { + const wordSet = new Set(wordList); + if (!wordSet.has(endWord)) return 0; + + const queue: [string, number][] = [[beginWord, 1]]; + + while(queue.length) { + const [word, level] = queue.shift()!; + if(word === endWord) return level; + + for(let i = 0; i < word.length; i++) { + for(let c = 97; c <= 122; c++) { + const newWord = word.slice(0,i) + String.fromCharCode(c) + word.slice(i+1); + if(wordSet.has(newWord)) { + queue.push([newWord, level+1]); + wordSet.delete(newWord); + } + } + } + } + + return 0; +} diff --git a/typscript/helloworld.ts b/typescript/helloWorld.ts similarity index 80% rename from typscript/helloworld.ts rename to typescript/helloWorld.ts index 3ba1ebf0..7cd2dee6 100644 --- a/typscript/helloworld.ts +++ b/typescript/helloWorld.ts @@ -1,2 +1,2 @@ console.log("Hello, TypeScript!"); -// This is a simple TypeScript program that prints "Hello, TypeScript!" to the console. \ No newline at end of file +// This is a simple TypeScript program that prints "Hello, TypeScript!" to the console. diff --git a/typescript/kadane_algori.ts b/typescript/kadane_algori.ts new file mode 100644 index 00000000..49e6bab0 --- /dev/null +++ b/typescript/kadane_algori.ts @@ -0,0 +1,11 @@ +function maxSubArray(nums: number[]): number { + let maxSum = nums[0], currSum = nums[0]; + for (let i = 1; i < nums.length; i++) { + currSum = Math.max(nums[i], currSum + nums[i]); + maxSum = Math.max(maxSum, currSum); + } + return maxSum; +} + +// Usage +console.log(maxSubArray([-2,1,-3,4,-1,2,1,-5,4])); // 6 diff --git a/typescript/linearSearch.ts b/typescript/linearSearch.ts new file mode 100644 index 00000000..ee154d09 --- /dev/null +++ b/typescript/linearSearch.ts @@ -0,0 +1,45 @@ +/** + * Performs a linear search on an array to find the index of a target element. + * + * @param arr The array to search through. + * @param target The element to search for. + * @returns The index of the target element if found; otherwise, returns -1. + */ +function linearSearch(arr: T[], target: T): number { + // Iterate through the array from the start (index 0) to the end. + for (let i = 0; i < arr.length; i++) { + // Check if the current element is equal to the target. + if (arr[i] === target) { + // If a match is found, return its index immediately. + return i; + } + } + + // If the loop completes without finding the target, return -1. + return -1; +} + +// --- Usage Example --- + +const numbers: number[] = [10, 5, 20, 8, 15]; +const targetNumber: number = 20; + +const resultIndexNumber: number = linearSearch(numbers, targetNumber); + +if (resultIndexNumber !== -1) { + console.log(`Target ${targetNumber} found at index: ${resultIndexNumber}`); // Output: Target 20 found at index: 2 +} else { + console.log(`Target ${targetNumber} not found in the array.`); +} + +// Example with a string array +const names: string[] = ["Alice", "Bob", "Charlie", "David"]; +const targetName: string = "Bob"; + +const resultIndexString: number = linearSearch(names, targetName); + +if (resultIndexString !== -1) { + console.log(`Target ${targetName} found at index: ${resultIndexString}`); // Output: Target Bob found at index: 1 +} else { + console.log(`Target ${targetName} not found in the array.`); +} diff --git a/typescript/mergeSort.ts b/typescript/mergeSort.ts new file mode 100644 index 00000000..524f2f7c --- /dev/null +++ b/typescript/mergeSort.ts @@ -0,0 +1,57 @@ +/** + * Merges two sorted subarrays into one sorted array. + * @param left The left sorted array. + * @param right The right sorted array. + * @returns The merged and sorted array. + */ +function merge(left: T[], right: T[]): T[] { + const result: T[] = []; + let i = 0; // Index for the left array + let j = 0; // Index for the right array + + // Compare elements from both arrays and push the smaller one to the result + while (i < left.length && j < right.length) { + if (left[i] < right[j]) { + result.push(left[i]); + i++; + } else { + result.push(right[j]); + j++; + } + } + + // Append any remaining elements (one of these loops will run) + return result.concat(left.slice(i)).concat(right.slice(j)); +} + +/** + * Sorts an array using the Merge Sort algorithm. + * @param arr The array to sort. + * @returns The fully sorted array. + */ +function mergeSort(arr: T[]): T[] { + // Base case: arrays with 0 or 1 element are already sorted + if (arr.length <= 1) { + return arr; + } + + // 1. Divide the array into two halves (left and right) + const mid = Math.floor(arr.length / 2); + const left = arr.slice(0, mid); + const right = arr.slice(mid); + + // 2. Recursively sort both halves + const sortedLeft = mergeSort(left); + const sortedRight = mergeSort(right); + + // 3. Merge the sorted halves + return merge(sortedLeft, sortedRight); +} + +// --- Usage Example --- +const unsortedArray = [38, 27, 43, 3, 9, 82, 10]; +const sortedArray = mergeSort(unsortedArray); +console.log("\n--- Merge Sort ---"); +console.log(`Unsorted: [${unsortedArray.join(", ")}]`); +console.log(`Sorted: [${sortedArray.join(", ")}]`); +// Expected Output: [3, 9, 10, 27, 38, 43, 82] diff --git a/typescript/mst.ts b/typescript/mst.ts new file mode 100644 index 00000000..da80bfa5 --- /dev/null +++ b/typescript/mst.ts @@ -0,0 +1,42 @@ +/** + * Edge definition: [u, v, weight] + */ +type Edge = [number, number, number]; + +/** + * Computes the Minimum Spanning Tree of a weighted, connected, undirected graph + * using Kruskal's Algorithm. + * + * @param numVertices The total number of vertices (0 to numVertices - 1). + * @param edges An array of edges, where each edge is [u, v, weight]. + * @returns An array of edges that form the MST. + */ +function kruskalMST(numVertices: number, edges: Edge[]): Edge[] { + const mst: Edge[] = []; + + // 1. Sort all edges by weight in non-decreasing order. + edges.sort((a, b) => a[2] - b[2]); + + // 2. Initialize the Union-Find structure. + const uf = new UnionFind(numVertices); + + // 3. Iterate through the sorted edges. + for (const [u, v, weight] of edges) { + // 4. Check if adding the edge (u, v) creates a cycle. + // If the roots of u and v are different, they are in different components (no cycle). + if (uf.find(u) !== uf.find(v)) { + // Add the edge to the MST. + mst.push([u, v, weight]); + + // Merge the two components. + uf.union(u, v); + + // Optimization: The MST must have V-1 edges. Stop when this is reached. + if (mst.length === numVertices - 1) { + break; + } + } + } + + return mst; +} diff --git a/typescript/safe_event.ts b/typescript/safe_event.ts new file mode 100644 index 00000000..bcb867f2 --- /dev/null +++ b/typescript/safe_event.ts @@ -0,0 +1,32 @@ +type EventCallback = (data: T) => void; + +class TypedEventEmitter> { + private events: Partial<{ [K in keyof Events]: EventCallback[] }> = {}; + + on(eventName: K, callback: EventCallback) { + if (!this.events[eventName]) this.events[eventName] = []; + this.events[eventName]!.push(callback); + } + + emit(eventName: K, data: Events[K]) { + const listeners = this.events[eventName]; + if (!listeners) return; + listeners.forEach(cb => cb(data)); + } + + off(eventName: K, callback: EventCallback) { + const listeners = this.events[eventName]; + if (!listeners) return; + this.events[eventName] = listeners.filter(cb => cb !== callback); + } +} + +// Usage +interface Events { + login: { userId: string }; + logout: void; +} + +const emitter = new TypedEventEmitter(); +emitter.on("login", data => console.log(data.userId)); +emitter.emit("login", { userId: "abc123" }); diff --git a/typescript/slidingwindow.ts b/typescript/slidingwindow.ts new file mode 100644 index 00000000..5547e565 --- /dev/null +++ b/typescript/slidingwindow.ts @@ -0,0 +1,15 @@ +function maxSlidingWindow(nums: number[], k: number): number[] { + const deque: number[] = []; + const res: number[] = []; + + for(let i=0;i=k-1) res.push(nums[deque[0]]); + } + return res; +} + +// Usage +console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7],3)); // [3,3,5,5,6,7] diff --git a/typescript/twoosum.ts b/typescript/twoosum.ts new file mode 100644 index 00000000..0f2d2612 --- /dev/null +++ b/typescript/twoosum.ts @@ -0,0 +1,12 @@ +function twoSum(nums: number[], target: number): number[] { + const map = new Map(); + for (let i = 0; i < nums.length; i++) { + const complement = target - nums[i]; + if (map.has(complement)) return [map.get(complement)!, i]; + map.set(nums[i], i); + } + return []; +} + +// Usage +console.log(twoSum([2,7,11,15], 9)); // [0,1] diff --git a/visual-algorithm/README.md b/visual-algorithm/README.md new file mode 100644 index 00000000..e69de29b diff --git a/visual-algorithm/graph/bfs_visual.cpp b/visual-algorithm/graph/bfs_visual.cpp new file mode 100644 index 00000000..e69de29b diff --git a/visual-algorithm/sorting/quicksort_visual.cpp b/visual-algorithm/sorting/quicksort_visual.cpp new file mode 100644 index 00000000..e69de29b