├── .gitignore ├── Algorithms ├── Graph.java ├── MergeSort.java └── QuickSort.java ├── DataStructures ├── BST.java └── LinkedList.java └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /Algorithms/Graph.java: -------------------------------------------------------------------------------- 1 | // Java program to print BFS traversal from a given source vertex. 2 | // BFS(int s) traverses vertices reachable from s. 3 | import java.io.*; 4 | import java.util.*; 5 | 6 | // This class represents a directed graph using adjacency list 7 | // representation 8 | class Graph 9 | { 10 | private int V; // No. of vertices 11 | private LinkedList adj[]; //Adjacency Lists 12 | 13 | // Constructor 14 | Graph(int v) 15 | { 16 | V = v; 17 | adj = new LinkedList[v]; 18 | for (int i=0; i queue = new LinkedList(); 37 | 38 | // Mark the current node as visited and enqueue it 39 | visited[s]=true; 40 | queue.add(s); 41 | 42 | while (queue.size() != 0) 43 | { 44 | // Dequeue a vertex from queue and print it 45 | s = queue.poll(); 46 | System.out.print(s+" "); 47 | 48 | // Get all adjacent vertices of the dequeued vertex s 49 | // If a adjacent has not been visited, then mark it 50 | // visited and enqueue it 51 | Iterator i = adj[s].listIterator(); 52 | while (i.hasNext()) 53 | { 54 | int n = i.next(); 55 | if (!visited[n]) 56 | { 57 | visited[n] = true; 58 | queue.add(n); 59 | } 60 | } 61 | } 62 | } 63 | 64 | // prints BFS traversal from a given source s 65 | void BFS(int s) 66 | { 67 | // Mark all the vertices as not visited(By default 68 | // set as false) 69 | boolean visited[] = new boolean[V]; 70 | 71 | // Create a queue for BFS 72 | LinkedList queue = new LinkedList(); 73 | 74 | // Mark the current node as visited and enqueue it 75 | visited[s]=true; 76 | queue.add(s); 77 | 78 | while (queue.size() != 0) 79 | { 80 | // Dequeue a vertex from queue and print it 81 | s = queue.poll(); 82 | System.out.print(s+" "); 83 | 84 | // Get all adjacent vertices of the dequeued vertex s 85 | // If a adjacent has not been visited, then mark it 86 | // visited and enqueue it 87 | Iterator i = adj[s].listIterator(); 88 | while (i.hasNext()) 89 | { 90 | int n = i.next(); 91 | if (!visited[n]) 92 | { 93 | visited[n] = true; 94 | queue.add(n); 95 | } 96 | } 97 | } 98 | } 99 | 100 | // Driver method to 101 | public static void main(String args[]) 102 | { 103 | Graph g = new Graph(4); 104 | 105 | g.addEdge(0, 1); 106 | g.addEdge(0, 2); 107 | g.addEdge(1, 2); 108 | g.addEdge(2, 0); 109 | g.addEdge(2, 3); 110 | g.addEdge(3, 3); 111 | 112 | System.out.println("Following is Breadth First Traversal "+ 113 | "(starting from vertex 2)"); 114 | 115 | g.BFS(2); 116 | } 117 | } 118 | // This code is contributed by Aakash Hasija 119 | -------------------------------------------------------------------------------- /Algorithms/MergeSort.java: -------------------------------------------------------------------------------- 1 | class MergeSort { 2 | 3 | /** 4 | * Takes a ArrayList, it's starting index and the index of the last element 5 | * and sorts it by recursively splitting it (it doesn't actually create two 6 | * different arrays when splitting it just determines where each array 7 | * starts and ends) and then merging them together in the correct order 8 | * 9 | * @param list 10 | * the MyArrayList object that the sorting will be performed on 11 | * @param start 12 | * an integer that specifies the index of the first element in 13 | * the MyArrayList object 14 | * @param finish 15 | * an integer that specifies the index of the last element in the 16 | * MyArraylist object 17 | */ 18 | void mergeSort(ArrayList list, int start, int finish) { 19 | // if the index of the first element and the index of the last element 20 | // are the same 21 | // or if the list is empty then return 22 | if (start == finish || list.size() == 0) { 23 | return; 24 | } 25 | // find the midpoint of the list in order to split the list into two 26 | // parts 27 | int mid = (start + finish) / 2; 28 | // call mergeSort on the left sublist 29 | mergeSort(list, start, mid, c); 30 | // call mergeSort on the right sublist 31 | mergeSort(list, mid + 1, finish, c); 32 | // merge the left and right sublists 33 | merge(list, start, mid, mid + 1, finish, c); 34 | } 35 | 36 | /** 37 | * Takes an ArrayList that's conceptually split into two lists, the starting 38 | * index and the index of the last element of the first Array and the 39 | * starting index and the index of the last element of the second Array and 40 | * merge them together into one array that is sorted in ascending order 41 | * 42 | * @param list 43 | * the MyArrayList object that the merging will be performed on 44 | * @param leftFirst 45 | * an integer that specifies the index of the first element in 46 | * the first MyArrayList object 47 | * @param leftLast 48 | * an integer that specifies the index of the last element in the 49 | * first MyArraylist object 50 | * @param rightFirst 51 | * an integer that specifies the index of the first element in 52 | * the second MyArrayList object 53 | * @param righttLast 54 | * an integer that specifies the index of the last element in the 55 | * second MyArraylist object 56 | * @param c 57 | * a comparator that determines which data field of the Record 58 | * objects should be taken in consideration when sorting 59 | */ 60 | void merge(ArrayList list, int leftFirst, int leftLast, int rightFirst, int rightLast) { 61 | // create a temporary array to store the elements in ascending order 62 | ArrayList temp = new ArrayList(); 63 | // Create two variables to keep track of the index we're at in the left 64 | // and right sublists 65 | int indexLeft = leftFirst; 66 | int indexRight = rightFirst; 67 | // While we're not at the end of the left or right sublist keep on going 68 | while (indexLeft <= leftLast && indexRight <= rightLast) { 69 | // find the smallest element between the two sublists and add it to 70 | // the temporary list 71 | // so that it contains the elements in ascending order 72 | if (list.get(indexLeft) < list.get(indexRight)) { 73 | temp.add(list.get(indexLeft)); 74 | indexLeft++; 75 | } else { 76 | temp.add(list.get(indexRight)); 77 | indexRight++; 78 | } 79 | } 80 | // Check if there is anything left in the left sublist and add it to the 81 | // temporary list 82 | while (indexLeft <= leftLast) { 83 | temp.add(list.get(indexLeft)); 84 | indexLeft++; 85 | } 86 | // Check if there is anything right in the left sublist and add it to 87 | // the temporary list 88 | while (indexRight <= rightLast) { 89 | temp.add(list.get(indexRight)); 90 | indexRight++; 91 | } 92 | // Copy the contents of the temporary list to the actual list so that it 93 | // contains all elements in a sorted order 94 | int i = 0; 95 | int j = leftFirst; 96 | while (i < temp.size()) { 97 | list.set(j, temp.get(i++)); 98 | j++; 99 | } 100 | 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Algorithms/QuickSort.java: -------------------------------------------------------------------------------- 1 | // Java program for implementation of QuickSort 2 | // Credit to: https://www.geeksforgeeks.org/quick-sort/ 3 | class QuickSort 4 | { 5 | /* This function takes last element as pivot, 6 | places the pivot element at its correct 7 | position in sorted array, and places all 8 | smaller (smaller than pivot) to left of 9 | pivot and all greater elements to right 10 | of pivot */ 11 | int partition(int arr[], int low, int high) 12 | { 13 | int pivot = arr[high]; 14 | int i = (low-1); // index of smaller element 15 | for (int j=low; j Array to be sorted, 41 | low --> Starting index, 42 | high --> Ending index */ 43 | void sort(int arr[], int low, int high) 44 | { 45 | if (low < high) 46 | { 47 | /* pi is partitioning index, arr[pi] is 48 | now at right place */ 49 | int pi = partition(arr, low, high); 50 | 51 | // Recursively sort elements before 52 | // partition and after partition 53 | sort(arr, low, pi-1); 54 | sort(arr, pi+1, high); 55 | } 56 | } 57 | 58 | /* A utility function to print array of size n */ 59 | static void printArray(int arr[]) 60 | { 61 | int n = arr.length; 62 | for (int i=0; i current.value) { 30 | current.right = addRecursive(current.right, value); 31 | } else { 32 | // value already exists 33 | return current; 34 | } 35 | 36 | return current; 37 | } 38 | 39 | public void add(int value) { 40 | root = addRecursive(root, value); 41 | } 42 | 43 | private boolean containsNodeRecursive(Node current, int value) { 44 | if (current == null) { 45 | return false; 46 | } 47 | if (value == current.value) { 48 | return true; 49 | } 50 | return value < current.value 51 | ? containsNodeRecursive(current.left, value) 52 | : containsNodeRecursive(current.right, value); 53 | } 54 | 55 | public boolean containsNode(int value) { 56 | return containsNodeRecursive(root, value); 57 | } 58 | 59 | private Node deleteRecursive(Node current, int value) { 60 | if (current == null) { 61 | return null; 62 | } 63 | 64 | if (value == current.value) { 65 | if (current.left == null && current.right == null) { 66 | return null; 67 | } 68 | if (current.right == null) { 69 | return current.left; 70 | } 71 | 72 | if (current.left == null) { 73 | return current.right; 74 | } 75 | int smallestValue = findSmallestValue(current.right); 76 | current.value = smallestValue; 77 | current.right = deleteRecursive(current.right, smallestValue); 78 | return current; 79 | 80 | } 81 | if (value < current.value) { 82 | current.left = deleteRecursive(current.left, value); 83 | return current; 84 | } 85 | current.right = deleteRecursive(current.right, value); 86 | return current; 87 | } 88 | 89 | private int findSmallestValue(Node root) { 90 | return root.left == null ? root.value : findSmallestValue(root.left); 91 | } 92 | 93 | public void delete(int value) { 94 | root = deleteRecursive(root, value); 95 | } 96 | 97 | public void traverseInOrder(Node node) { 98 | if (node != null) { 99 | traverseInOrder(node.left); 100 | System.out.print(" " + node.value); 101 | traverseInOrder(node.right); 102 | } 103 | } 104 | 105 | public void traversePreOrder(Node node) { 106 | if (node != null) { 107 | System.out.print(" " + node.value); 108 | traversePreOrder(node.left); 109 | traversePreOrder(node.right); 110 | } 111 | } 112 | 113 | public void traversePostOrder(Node node) { 114 | if (node != null) { 115 | traversePostOrder(node.left); 116 | traversePostOrder(node.right); 117 | System.out.print(" " + node.value); 118 | } 119 | } 120 | 121 | public void traverseLevelOrder() { 122 | if (root == null) { 123 | return; 124 | } 125 | 126 | Queue nodes = new LinkedList<>(); 127 | nodes.add(root); 128 | 129 | while (!nodes.isEmpty()) { 130 | 131 | Node node = nodes.remove(); 132 | 133 | System.out.print(" " + node.value); 134 | 135 | if (node.left != null) { 136 | nodes.add(node.left); 137 | } 138 | 139 | if (node.right!= null) { 140 | nodes.add(node.right); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /DataStructures/LinkedList.java: -------------------------------------------------------------------------------- 1 | class LinkedList { 2 | Node head; 3 | int size; 4 | 5 | public LinkedList(Node head) { 6 | this.head = head; 7 | } 8 | 9 | public inserAtBeggining(E element){ 10 | // create new node 11 | Node newNode = new Node(); 12 | //make the new node point to the current first node 13 | newNode.setNext(head); 14 | //make the head reference point to the new first node 15 | head = newNode; 16 | //update the size variable (if it exists) 17 | size++; 18 | } 19 | public insertAtEnd(E element){ 20 | // create new node 21 | Node newNode = new Node ( ); 22 | //create the current reference and point it to the last node 23 | Node current = head; 24 | while (current.next != null ) 25 | current = current.next; 26 | //make the new node point to null 27 | newNode.next = null; 28 | //make the last node point to the new last node 29 | current.next = newNode; 30 | //update the size variable (if it exists) size++; 31 | } 32 | public insertInMiddle(E element){ 33 | // create new node 34 | Node newNode = new Node ( ); 35 | //create the current reference and advance it to //the node after which we want to insert 36 | Node current = head; 37 | ... //depends on specifics of the problem 38 | //make the new node point to its successor 39 | newNode.next = current.next; 40 | //make the current node point to the new node 41 | current.next = newNode; 42 | } 43 | 44 | public removeFromBeginning() { 45 | //point the head reference to the second node if ( head != null ) 46 | head = head.next; 47 | size--; 48 | } 49 | 50 | public removeFromEnd() { 51 | //create a current reference and advance it to the one // before the last node 52 | Node current; 53 | current = head; 54 | //assume that there are at least two nodes in the list 55 | //(otherwise we are deleting the first node) while ( current.next.next != null ) 56 | current = current.next; 57 | //disconnect the last node by pointing the one // before it to null 58 | current.setNext(null); size--; 59 | } 60 | 61 | public removeFromMiddle() { 62 | //create a current reference and advance it to the one // before the node to be deleted 63 | Node current; 64 | current = head; 65 | ... //depends on specifics of the problem 66 | //connect the node pointed to by current with the node 67 | //pointed to be the node being deleted current.setNext(current.getNext().getNext() ); 68 | size--; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InterviewGuide 2 | 3 | ## Concepts 4 | 5 | This is my review of Algorithms and Data Structures for interview prep. 6 | Credit to [Kevin](https://github.com/kdn251/interviews) for a lot of the inspiration. 7 | 8 | ### Arrays 9 | 10 | An array is a data structure that holds a fixed number of values (data points) of the same type. Each item, or value, in an array is called an element, and each element is accessed by its integer index. When we initialize an array, we get to choose what type of data it can hold and how many elements it can hold. 11 | 12 | Declaration: `Type[] = new Type[length];` 13 | 14 | ### HashMaps 15 | 16 | HashMaps are arrays of fixed size containing data items with unique keys, together with a function called a hash function that maps keys to indexes in the table/arrays. When the java Map interface is used we need to ensure a good hash function is used for the objects that are used as keys in the hash table. 17 | 18 | A good hash function is: 19 | 1. Easy to compute `O(1)`: it has to be independent of the input and the hashtable size. 20 | 2. Repeatable: 2 calls with the same argument should produce the same results. 21 | 3. randomly disperses keys evenly throughout table, making sure no two keys map to the same index. 22 | 23 | If a key already maps to a value and we try to use the same key to map to another value a collision occurs. Collisions can be resolved in two ways: 24 | - Open addressing: find alternative location for (key, value) pair through linear or quadratic probing. 25 | - Closed addressing: allow multiple (key, value) pairs to be stored in the same location through a linked list. 26 | 27 | Declaration: `HashMap map = new HashMap();` 28 | Methods: 29 | - `V put(K key, V value)` maps key to value in this map, returns previous value of key or null. 30 | - `V get(Object key)` returns value to which the key is mapped or null. 31 | - `V remove(Object key)` removes mapping of key and returns the value of that key or null. 32 | - `Set keySet()` returns the set view of keys contained in the map. 33 | 34 | You can easily implement a Counter in java with the following: 35 | 36 | ```java 37 | class Counter extends HashMap { 38 | public int get(int k) { 39 | return containsKey(k) ? super.get(k) : 0; 40 | } 41 | 42 | public void add(int k, int v) { 43 | put(k, get(k) + v); 44 | } 45 | } 46 | ``` 47 | 48 | ### Stacks 49 | Stacks are structures in which elements are always added and removed from the same end. Stacks are last in first out (LIFO) structures. 50 | 51 | Declaration: `Stack stack = new Stack();` 52 | Methods: 53 | - `boolean empty()` returns true if the stack is empty. 54 | - `E peek()` retrieves but does not remove head, returns null if empty. 55 | - `E push(E element)` inserts element into the top of the stack. 56 | - `E pop()` retrieves and removes the top of the stack. 57 | - `int search(E element)` Returns the 1-based position where an object is on this stack.. 58 | 59 | ### Linked Lists 60 | 61 | In Java when a variable of a primitive data type is allocated the memory location associated with that variable contains the value assigned to that variable. 62 | For example `int x = 5;` results in a 32-bit block of memory associated with the variable x. The bits are used to represent the value of 5. 63 | On the other hand, with reference type variables the memory allocation is different, they do not have room for storing data, they only contain enough memory to store a reference or an address of memory location at which the actual data is stored. 64 | The idea of creating linked structures is based on the reference variables. Linked structures are composed of individual objects that are linked to one another in some way. 65 | Therefore, a linked list can be simply thought of as a reference to the first node of a linked structure: from there we can follow the ”links” to get to every other node. 66 | 67 | Declaration: `LinkedList linkedList = new LinkedList();` 68 | 69 | A sample implementation of Linked List can be found [here](DataStructures/LinkedList.java) 70 | 71 | ### Queues 72 | 73 | Queues are structures in which elements are added to one end and removed from the other end following the first in first out structure. 74 | An array based implementation of queues needs to keep track of both the front and end of the queue. 75 | A reference based (Linked List) implementation needs to keep a tail-like reference. Adding new elements at the tail and removing elements from the head. 76 | 77 | Declaration: `Queue queue = new Queue();` 78 | Methods: 79 | - `boolean add(E elemet)` inserts element into queue. 80 | - `E peek()` retrieves but does not remove head, returns null if empty. 81 | - `boolean offer(E element)` inserts element into queue. 82 | - `E remove()` retrieves and removes head. 83 | 84 | ### Trees 85 | 86 | Trees are structures in which each node can have multiple successors such that there is a unique path from the root to every other node in the tree. Any node can be viewed as the root of its own subtree. 87 | 88 | Definitions: 89 | - Children / Descendants: successors of a node. 90 | - Parent / Ascendants: predecessors of a node. 91 | - Siblings: node that share same parent nodes. 92 | - Leaf / External nodes: Nodes that don't have any children. 93 | - Non-leaf / Internal nodes: Nodes that do have one or more children. 94 | - Path: An edge formed by a pair of nodes. 95 | - Level: Distance from the root to a node, root being at 0. 96 | - Depth of tree: Level of deepest node. 97 | - Depth of node: number of ascendants of that node in a tree. 98 | - Height: Calculated from leaves up to root with leaf height being 0. 99 | - Binary Tree: Tree where each node can have at most 2 children. The shortest Binary Tree has log2(N+1) and the tallest has N-1 levels. 100 | - Full: Each node has exactly 0 or 2 children. OR Each level has maximal possible number of nodes (depends on definition used). 101 | - Complete: a binary tree with L levels such that the levels 0 <= l <= L have the max number of nodes (2^l) and the nodes at level L are placed as far left as poossible. 102 | 103 | Java does not come with a Binary Tree data structure, you must implement your own as can be found [here](DataStructures/BST.java) 104 | 105 | #### [Traversals](https://www.geeksforgeeks.org/tree-traversals-inorder-preorder-and-postorder/): 106 | 107 | **Preorder Traversal:** 108 | ```Java 109 | void printPreorder(Node node) 110 | { 111 | if (node == null) 112 | return; 113 | 114 | /* first print data of node */ 115 | System.out.print(node.key + " "); 116 | 117 | /* then recur on left sutree */ 118 | printPreorder(node.left); 119 | 120 | /* now recur on right subtree */ 121 | printPreorder(node.right); 122 | } 123 | ``` 124 | 125 | **Postorder Traversal:** 126 | ```Java 127 | void printPostorder(Node node) 128 | { 129 | if (node == null) 130 | return; 131 | 132 | // first recur on left subtree 133 | printPostorder(node.left); 134 | 135 | // then recur on right subtree 136 | printPostorder(node.right); 137 | 138 | // now deal with the node 139 | System.out.print(node.key + " "); 140 | } 141 | ``` 142 | 143 | **Inorder Traversal:** 144 | ```Java 145 | void printInorder(Node node) 146 | { 147 | if (node == null) 148 | return; 149 | 150 | /* first recur on left child */ 151 | printInorder(node.left); 152 | 153 | /* then print the data of node */ 154 | System.out.print(node.key + " "); 155 | 156 | /* now recur on right child */ 157 | printInorder(node.right); 158 | } 159 | ``` 160 | 161 | ### Priority Queues and Heaps 162 | 163 | A Max/Min heap maintains: 164 | 1. Shape property: the heap has to be a complete binary tree. 165 | 2. Order property: each node has a value greater/smaller than or equal to the values of both of its children. 166 | 167 | Enqueue: Add elements in bottom row of tree then heapify. 168 | Dequeue: Remove root, pick right most bottom node place at top, heapify by moving it down. 169 | 170 | Heaps are usually implemented as arrays: 171 | - Root of a tree is at index 0. 172 | - If an element is not root, its parent is at position (index - 1) / 2 173 | - If an element has a left child the child is at position index * 2 + 1 174 | - If an element has a right child the child is at position index * 2 + 2 175 | 176 | Declaration: 177 | - MinHeap: 178 | ```Java 179 | PriorityQueue minHeap = new PriorityQueue<>(); 180 | ``` 181 | - MaxHeap: 182 | ```Java 183 | PriorityQueue maxHeap = new PriorityQueue<>(new Comparator() { 184 | @Override 185 | public int compare(Integer o1, Integer o2) { 186 | return o2.compareTo(o1); 187 | } 188 | }); 189 | ``` 190 | 191 | Methods: 192 | - `boolean offer(E e)` Inserts the specified element into this priority queue. 193 | - `E peek()` Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty. 194 | - `E poll()` Retrieves and removes the head of this queue, or returns null if this queue is empty. 195 | - `boolean contains(Object o)` Returns true if this queue contains the specified element. 196 | 197 | 198 | ### Graphs: 199 | 200 | ```Java 201 | public void dfsORbfs(Node start){ 202 | //Choose the data structure 203 | Stack stack = new Stack(); //For DFS 204 | Queue queue = new LinkedList(); For BFS 205 | Set seen = new HashSet(); 206 | 207 | stack.push(start); 208 | queue.add(start); 209 | 210 | //change stack to queue for bfs 211 | while(!stack.isEmpty()) { 212 | // Pull a node to process 213 | Node curr = stack.pop(); 214 | //Node curr = queu.poll(); 215 | // Process if not seen 216 | if (!seen.contains(cur)) { 217 | seen.add(curr); 218 | System.out.println(curr); 219 | } 220 | // Add unseen children 221 | for (Node adjacent: curr.adjacents){ 222 | if (!seen.contains(adjacent)) { 223 | stack.push(adjacent); 224 | //queue.add(adjacent); 225 | } 226 | } 227 | } 228 | } 229 | ``` 230 | 231 | #### Topological Sort: 232 | 233 | ```Java 234 | public int[] findOrder(int numNodes, int[][] edges) { 235 | int[][] matrix = new int[numNodes][numNodes]; // i -> j 236 | int[] indegree = new int[numNodes]; 237 | 238 | for (int i = 0; i < edges.length; i++) { 239 | int cur = edges[i][0]; 240 | int pre = edges[i][1]; 241 | if (matrix[pre][cur] == 0){ 242 | indegree[cur]++; 243 | } 244 | matrix[pre][cur] = 1; 245 | } 246 | 247 | Queue order = new LinkedList(); 248 | Queue processNext = new LinkedList(); 249 | for (int i=0; i> graph = new HashMap(); 287 | for (int[] edge: matrix) { 288 | if (!graph.containsKey(edge[0])) 289 | graph.put(edge[0], new ArrayList()); 290 | graph.get(edge[0]).add(new int[]{edge[1], edge[2]}); 291 | } 292 | PriorityQueue heap = new PriorityQueue( 293 | (info1, info2) -> info1[0] - info2[0]); 294 | heap.offer(new int[]{0, S}); 295 | 296 | Map dist = new HashMap(); 297 | 298 | while (!heap.isEmpty()) { 299 | int[] info = heap.poll(); 300 | int d = info[0], node = info[1]; 301 | if (dist.containsKey(node)) continue; 302 | dist.put(node, d); 303 | if (graph.containsKey(node)) 304 | for (int[] edge: graph.get(node)) { 305 | int nei = edge[0], d2 = edge[1]; 306 | if (!dist.containsKey(nei)) 307 | heap.offer(new int[]{d+d2, nei}); 308 | } 309 | } 310 | 311 | // Let's return the value of the longest path 312 | if (dist.size() != N) return -1; 313 | int ans = 0; 314 | for (int cand: dist.values()) 315 | ans = Math.max(ans, cand); 316 | return ans; 317 | } 318 | ``` 319 | 320 | ### Binary Search: 321 | 322 | If you need to return index during search: 323 | ```java 324 | while lo <= hi: 325 | mid = (lo+hi)/2 326 | if nums[mid] == target: 327 | return mid 328 | if nums[mid] > target: 329 | hi = mid-1 330 | else: 331 | lo = mid+1 332 | return -1 333 | ``` 334 | 335 | Searching lowest element satisfy function(i) == True (the array should satisfy function(x) == False for 0 to i-1, and function(x) == True for i to n-1, and it is up to the question to define the function, like in the find peak element problem, function(x) can be nums[x] < nums[x+1]) 336 | ```java 337 | while lo <= hi: 338 | mid = (lo+hi)/2 339 | if function(mid): 340 | hi = mid-1 341 | else: 342 | lo = mid+1 343 | return lo 344 | ``` 345 | 346 | 347 | ### Merge Sort: 348 | 349 | The algorithm for merge sort is as follows: 350 | 1. split the array in half 351 | 2. sort the left half 352 | 3. sort the right half 353 | 4. merge two sorted half-arrays into a single sorted array 354 | 355 | An implementation can be found [here](Algorithms/MergeSort.java) 356 | 357 | ### Quick Sort: 358 | 359 | The algorithm for quick sort is as follows: 360 | 1. pick a pivot 361 | 2. partition the array into two parts: 362 | - left - containing all values less than the pivot 363 | - right - containing all values grater than the pivot 364 | 3. apply quick sort to the left part 365 | 4. apply quick sort to the right part 366 | 367 | Selecting a good pivot is necessary for guaranteeing a good performance. Imagine that we always pick the smallest or the largest element to be the pivot. In this scenario we end up with one of the parts containing all but one element from the original array and the other part empty. You may guess that this is not very desirable. 368 | Picking the pivot also has to be quick. 369 | 370 | There are several ways pivots are picked. All of them have their advantages and disadvanteges. Here are just a few ideas of how we can select a pivot: 371 | 1. always pick the first element from the given array (or sub-array) 372 | 2. pick a middle element in the array 373 | 3. pick a random element from the array 374 | 4. select three elements from the array and use their median as the pivot; the three elements could be 375 | - first three elements in the array 376 | - first, middle and last elements in the array 377 | - random three elements in the array 378 | 379 | An implementation can be found [here](Algorithms/QuickSort.java) 380 | 381 | ## Tips and tricks 382 | 383 | ### Time: 384 | 385 | In java given a string representing the time such as "23:11", the natural way ti represent the time is an integer t in the range 0 <= t < 24 * 60. Then the hours are t / 60, the mintues are t % 60, and each digit of the hours and minutes can be found by hours / 10, hours % 10 etc... 386 | This yields the following format: 387 | `int[] digits = new int[]{t / 60 / 10, t / 60 % 10, t % 60 / 10, t % 60 % 10}` 388 | --------------------------------------------------------------------------------