diff --git a/Exercise_1.java b/Exercise_1.java index c3ff1141..39fd96ec 100644 --- a/Exercise_1.java +++ b/Exercise_1.java @@ -1,8 +1,28 @@ -class BinarySearch { +// Time Complexity : O(log n) +// Space Complexity : O(n) just for the array +// Your code here along with comments explaining your approach +/* +* I try to find the mid element iteratively until my left value gets less than or equal to right index +* If I find my target element dorectly at mid index, I return it, if not, I compare the value of target +* with value of mid to see and move my left, right indices to narrow the search criteria. Return -1 if +* target not found. +* */ + +class BinarySearch { // Returns index of x if it is present in arr[l.. r], else return -1 int binarySearch(int arr[], int l, int r, int x) { //Write your code here + while(l <= r) { + int mid = l + (r - l) / 2; + if(x == arr[mid]) + return mid; + else if(arr[mid] < x) + l = mid + 1; + else + r = mid - 1; + } + return -1; } // Driver method to test above @@ -11,7 +31,7 @@ public static void main(String args[]) BinarySearch ob = new BinarySearch(); int arr[] = { 2, 3, 4, 10, 40 }; int n = arr.length; - int x = 10; + int x = 10; int result = ob.binarySearch(arr, 0, n - 1, x); if (result == -1) System.out.println("Element not present"); diff --git a/Exercise_2.java b/Exercise_2.java index d0b5fa5f..56832e75 100644 --- a/Exercise_2.java +++ b/Exercise_2.java @@ -1,4 +1,14 @@ -class QuickSort +// Time Complexity : O(nlog n) best and average case , O(n^2) worst case +// Space Complexity : O(n) worst case +// Your code here along with comments explaining your approach +/* + * The idea is to find a specific partition index and sort using it for first and second halfs recursively + * But, to choose this partition, I need to understand the order of the elements. So, I assume a pivot + * element first, then try to compare iteratively each element of the array with pivot and make sure to + * place/swap all those smaller elements to left side of the array in comparison with pivot. then, I return + * that least index element which acts as a partition of smaller sorted elements till now and the rest. + * */ +class QuickSort { /* This function takes last element as pivot, places the pivot element at its correct @@ -7,12 +17,26 @@ class QuickSort pivot and all greater elements to right of pivot */ void swap(int arr[],int i,int j){ - //Your code here + //Your code here + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; } int partition(int arr[], int low, int high) { - //Write code here for Partition and Swap + //Write code here for Partition and Swap + int i = low - 1; + int pivot = arr[high]; + + for(int j = low ; j <= high - 1 ; j++) { + if(arr[j] < pivot) { + i++; + swap(arr, i, j); + } + } + swap(arr, i + 1, high); + return i + 1; } /* The main function that implements QuickSort() arr[] --> Array to be sorted, @@ -21,7 +45,12 @@ int partition(int arr[], int low, int high) void sort(int arr[], int low, int high) { // Recursively sort elements before - // partition and after partition + // partition and after partition + if(low < high) { + int pi = partition(arr, low, high); + sort(arr, low, pi - 1); + sort(arr, pi + 1, high); + } } /* A utility function to print array of size n */ diff --git a/Exercise_3.java b/Exercise_3.java index 1f9b752a..1fe480a0 100644 --- a/Exercise_3.java +++ b/Exercise_3.java @@ -1,4 +1,12 @@ -class LinkedList +// Time Complexity : O(n) +// Space Complexity : O(1) + +// Your code here along with comments explaining your approach +/* +I take 2 pointers fast and slow and make sure to move fast pointer quickly and slow pointer just behind +it to fetch the exact middle element. + */ +class LinkedList { Node head; // head of linked list @@ -20,6 +28,16 @@ void printMiddle() { //Write your code here //Implement using Fast and slow pointers + if(head == null) { + System.out.println("List is empty"); + } + Node slow = head; + Node fast = head; + while(fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + System.out.println("Middle elmement is " + slow.data); } public void push(int new_data) diff --git a/Exercise_4.java b/Exercise_4.java index 81afd3c2..c9475cd4 100644 --- a/Exercise_4.java +++ b/Exercise_4.java @@ -1,11 +1,42 @@ -class MergeSort +// Time Complexity : O(nlog n) +// Space Complexity : O(n) worst case +// Your code here along with comments explaining your approach +/* + * The idea is to split and sort left and right sub arrays recursively first and then eventually merge + * using 2 pointers making sure to pick smaller element each time, placing it in main array. + * */ +class MergeSort { // Merges two subarrays of arr[]. // First subarray is arr[l..m] // Second subarray is arr[m+1..r] void merge(int arr[], int l, int m, int r) { - //Your code here + //Your code here + int n1 = m - l + 1; + int n2 = r - m; + + int[] N1 = new int[n1]; + int[] N2 = new int[n2]; + + for(int i = 0 ; i < n1 ; i++) + N1[i] = arr[l + i]; + for(int j = 0 ; j < n2 ; j++) + N2[j] = arr[m + 1 + j]; + + int i = 0, j = 0 , k = l; + + while(i < n1 && j < n2) { + if(N1[i] < N2[j]) { + arr[k++] = N1[i++]; + } + else + arr[k++] = N2[j++]; + } + while(i < n1) + arr[k++] = N1[i++]; + while(j < n2) + arr[k++] = N2[j++]; } // Main function that sorts arr[l..r] using @@ -13,7 +44,14 @@ void merge(int arr[], int l, int m, int r) void sort(int arr[], int l, int r) { //Write your code here - //Call mergeSort from here + //Call mergeSort from here + if(l < r) { + int m = l + (r - l) / 2; + sort(arr, l, m); + sort(arr, m + 1, r); + + merge(arr, l , m , r); + } } /* A utility function to print array of size n */ diff --git a/Exercise_5.java b/Exercise_5.java index 30e82675..21e40955 100644 --- a/Exercise_5.java +++ b/Exercise_5.java @@ -1,7 +1,20 @@ -class IterativeQuickSort { +// Time Complexity : O(nlog n) +// Space Complexity : O(n) +// Your code here along with comments explaining your approach +/* + * The idea is to use the same partition logic, but instead of recursion, use a stack logic to store (l,h) pairs of + * subarrays.Each iteration pops a subarray, partitions it and pushes left/right subarrays + * Instead of extra variable, I used XOR logic to swap + * */ +class IterativeQuickSort { void swap(int arr[], int i, int j) { - //Try swapping without extra variable + //Try swapping without extra variable + if(i != j) { + arr[i] = arr[i] ^ arr[j]; + arr[j] = arr[i] ^ arr[j]; + arr[i] = arr[i] ^ arr[j]; + } } /* This function is same in both iterative and @@ -9,12 +22,45 @@ void swap(int arr[], int i, int j) int partition(int arr[], int l, int h) { //Compare elements and swap. + int i = l - 1; + int pivot = arr[h]; + + for(int j = l ; j < h ; j++) { + if(arr[j] <= pivot) { + i++; + swap(arr, i , j); + } + } + swap(arr, i + 1, h); + return i + 1; } // Sorts arr[l..h] using iterative QuickSort void QuickSort(int arr[], int l, int h) { //Try using Stack Data Structure to remove recursion. + int[] stack = new int[h - l + 1]; + int top = -1; + + stack[++top] = l; + stack[++top] = h; + + while(top >= 0) { + h = stack[top--]; + l = stack[top--]; + + int p = partition(arr, l, h); + if(l < p - 1) { + stack[++top] = l; + stack[++top] = p - 1; + } + if(p + 1 < h) { + stack[++top] = p + 1; + stack[++top] = h; + } + } + + } // A utility function to print contents of arr