Sei sulla pagina 1di 19

MOST FREQUENTLY ASKED DATA STRUCTURE BASED QUESTIONS IN INTERVIEWS

REFFERED FROM

GeeksforGeeks
(http://www.geeksforgeeks.org/)

Prepared by: Vignesh Lakshmi Ganthan

1) Level Order Tree Traversal


/*Function to print level order traversal of tree*/ printLevelorder(tree) for d = 1 to height(tree) printGivenLevel(tree, d); /*Function to print all nodes at a given level*/ printGivenLevel(tree, level) if tree is NULL then return; if level is 1, then print(tree->data); else if level greater than 1, then printGivenLevel(tree->left, level-1); printGivenLevel(tree->right, level-1);
OR

printLevelorder(tree) 1) Create an empty queue q 2) temp_node = root /*start from root*/ 3) Loop while temp_node is not NULL a) print temp_node->data. b) Enqueue temp_nodes children (first left then right children) to q c) Dequeue a node from q and assign its value to temp_node

2)Level order traversal in spiral form


printLevelorder(tree) bool ltr = 0; for d = 1 to height(tree) printGivenLevel(tree, d, ltr); ltr ~= ltr /*flip ltr*/
Function to print all nodes at a given level

printGivenLevel(tree, level, ltr) if tree is NULL then return; if level is 1, then print(tree->data); else if level greater than 1, then if(rtl) printGivenLevel(tree->right, level-1, ltr); printGivenLevel(tree->left, level-1, ltr); else printGivenLevel(tree->left, level-1, ltr); printGivenLevel(tree->right, level-1, ltr);

3)Print a given matrix in spiral form


void spiralPrint(int m, int n, int a[R][C]) { int i, k = 0, l = 0; /* k m l n i starting row index ending row index starting column index ending column index iterator

*/ while (k < m && l < n) { /* Print the first row from the remaining rows */ for (i = l; i < n; ++i) { printf("%d ", a[k][i]); } k++; /* Print the last column from the remaining columns */ for (i = k; i < m; ++i) { printf("%d ", a[i][n-1]); } n--; /* Print the last row from the remaining rows */ if ( k < m) { for (i = n-1; i >= l; --i) { printf("%d ", a[m-1][i]); } m--; } /* Print the first column from the remaining columns */ if (l < n) { for (i = m-1; i >= k; --i) { printf("%d ", a[i][l]); }

l++; } } }

4)Write a function to get the intersection point of two Linked Lists.


Method 1(Simply use two loops) Use 2 nested for loops. Outer loop will be for each node of the 1st list and inner loop will be for 2nd list. In the inner loop, check if any of nodes of 2nd list is same as the current node of first linked list. Time complexity of this method will be O(mn) where m and n are the number of nodes in two lists. Method 2 (Mark Visited Nodes) This solution requires modifications to basic linked list data structure. Have a visited flag with each node. Traverse the first linked list and keep marking visited nodes. Now traverse second linked list, If you see a visited node again then there is an intersection point, return the intersecting node. This solution works in O(m+n) but requires additional information with each node. A variation of this solution that doesnt require modification to basic data structure can be implemented using hash. Traverse the first linked list and store the addresses of visited nodes in a hash. Now traverse the second linked list and if you see an address that already exists in hash then return the intersecting node. Method 3(Using difference of node counts) 1) Get count of the nodes in first list, let count be c1. 2) Get count of the nodes in second list, let count be c2. 3) Get the difference of counts d = abs(c1 c2) 4) Now traverse the bigger list from the first node till d nodes so that from here onwards both the lists have equal no of nodes. 5) Then we can traverse both the lists in parallel till we come across a common node. (Note that getting a common node is done by comparing the address of the nodes)

5)Detect and Remove Loop in a Linked List


1) Detect Loop using Floyds Cycle detection algo and get the pointer to a loop node. 2) Count the number of nodes in loop. Let the count be k. 3) Fix one pointer to the head and another to kth node from head. 4) Move both pointers at the same pace, they will meet at loop starting node. 5) Get pointer to the last node of loop and make next of it as NULL.

6)Lowest Common Ancestor in a Binary Search Tree.


The main idea of the solution is While traversing Binary Search Tree from top to bottom, the first node n we encounter with value between n1 and n2, i.e., n1 < n < n2 is the Lowest or Least Common Ancestor(LCA) of n1 and n2 (where n1 < n2). So just traverse the BST in pre-order, if you find a node with value in between n1 and n2 then n is the LCA, if it's value is greater than both n1 and n2 then our LCA lies on left side of the node, if it's value is smaller than both n1 and n2 then LCA lies on right side. Implementation:

/* A binary tree and a pointer struct node { int data; struct node* struct node* };

node has data, pointer to left child to right child */

left; right;

struct node* newNode(int ); /* Function to find least comman ancestor of n1 and n2 */ int leastCommanAncestor(struct node* root, int n1, int n2) { /* If we have reached a leaf node then LCA doesn't exist If root->data is equal to any of the inputs then input is not valid. For example 20, 22 in the given figure */ if(root == NULL || root->data == n1 || root->data == n2) return -1; /* If any of the input nodes is child of the current node we have reached the LCA. For example, in the above figure if we want to calculate LCA of 12 and 14, recursion should terminate when we reach 8*/ if((root->right != NULL) && (root->right->data == n1 || root->right->data == n2)) return root->data; if((root->left != NULL) && (root->left->data == n1 || root->left->data == n2)) return root->data;

if(root->data > n1 && root->data < n2) return root->data; if(root->data > n1 && root->data > n2) return leastCommanAncestor(root->left, n1, n2); if(root->data < n1 && root->data < n2) return leastCommanAncestor(root->right, n1, n2); }

7)Write a function to reverse a linked list


Iterative Method Iterate trough the linked list. In loop, change next to prev, prev to current and current to next.

/* Function to reverse the linked list */ static void reverse(struct node** head_ref) { struct node* prev = NULL; struct node* current = *head_ref; struct node* next; while (current != NULL) { next = current->next; current->next = prev; prev = current; current = next; } *head_ref = prev; }
Recursive Method: 1) Divide the list in two parts - first node and rest of the linked list. 2) Call reverse for the rest of the linked list. 3) Link rest to first. 4) Fix head pointer

void recursiveReverse(struct node** head_ref) { struct node* first; struct node* rest; /* empty list */ if (*head_ref == NULL) return; /* suppose first = {1, 2, 3}, rest = {2, 3} */ first = *head_ref; rest = first->next;

/* List has only one node */ if (rest == NULL) return; /* reverse the rest list and put the first element at the end */ recursiveReverse(&rest); first->next->next = first; /* tricky step -- see the diagram */ first->next = NULL; /* fix the head pointer */ *head_ref = rest; }

8)Implement Queue using Stacks


Method 1 (By making enQueue operation costly) This method makes sure that newly entered element is always at the top of stack 1, so that deQueue operation just pops from stack1. To put the element at top of stack1, stack2 is used.

enQueue(q, x) 1) While stack1 is not empty, push everything from satck1 to stack2. 2) Push x to stack1 (assuming size of stacks is unlimited). 3) Push everything back to stack1. dnQueue(q) 1) If stack1 is empty then error 2) Pop an item from stack1 and return it
Method 2 (By making deQueue operation costly) In this method, in en-queue operation, the new element is entered at the top of stack1. In de-queue operation, if stack2 is empty then all the elements are moved to stack2 and finally top of stack2 is returned.

enQueue(q, x) 1) Push x to stack1 (assuming size of stacks is unlimited). deQueue(q) 1) If both stacks are empty then error. 2) If stack2 is empty
9

While stack1 is not empty, push everything from satck1 to stack2. 3) Pop the element from stack2 and return it.
Method 2 is definitely better than method 1. Method 1 moves all the elements twice in enQueue operation, while method 2 (in deQueue operation) moves the elements once and moves elements only if stack2 empty

9)Reverse a stack using recursion


The idea of the solution is to hold all values in Function Call Stack until the stack becomes empty. When the stack becomes empty, insert all held items one by one at the bottom of the stack. //Below is a recursive function that inserts an element at the bottom of a stack.

void insertAtBottom(struct sNode** top_ref, int item) { int temp; if(isEmpty(*top_ref)) { push(top_ref, item); } else { /* Hold all items in Function Call Stack until we reach end of the stack. When the stack becomes empty, the isEmpty(*top_ref) becomes true, the above if part is executed and the item is inserted at the bottom */ temp = pop(top_ref); insertAtBottom(top_ref, item); /* Once the item is inserted at the bottom, push all the items held in Function Call Stack */ push(top_ref, temp); } }
//Below is the function that reverses the given stack using insertAtBottom()

10

void reverse(struct sNode** top_ref) { int temp; if(!isEmpty(*top_ref)) { /* Hold all items in Function Call Stack until we reach end of the stack */ temp = pop(top_ref); reverse(top_ref); /* Insert all the items (held in Function Call Stack) one by one from the bottom to top. Every item is inserted at the bottom */ insertAtBottom(top_ref, temp); }

10)In-place conversion of Sorted DLL to Balanced BST


Method 1 (Simple) Following is a simple algorithm where we first find the middle node of list and make it root of the tree to be constructed.

1) Get the Middle of the linked list and make it root. 2) Recursively do same for left half and right half. a) Get the middle of left half and make it left child of the root created in step 1. b) Get the middle of right half and make it right child of the root created in step 1.

Time complexity: O(nLogn) where n is the number of nodes in Linked List. Method 2 (Tricky) The method 1 constructs the tree from root to leaves. In this method, we construct from leaves to root. The idea is to insert nodes in BST in the same order as the appear in Doubly Linked List, so that the tree can be

11

constructed in O(n) time complexity. We first count the number of nodes in the given Linked List. Let the count be n. After counting nodes, we take left n/2 nodes and recursively construct the left subtree. After left subtree is constructed, we assign middle node to root and link the left subtree with root. Finally, we recursively construct the right subtree and link it with root. While constructing the BST, we also keep moving the list head pointer to next so that we have the appropriate pointer in each recursive call.

11)Find the two numbers with odd occurrences in an unsorted array


A naive method to solve this problem is to run two nested loops. The outer loop picks an element and the inner loop counts the number of occurrences of the picked element. If the count of occurrences is odd then print the number. The time complexity of this method is O(n^2). We can use sorting to get the odd occurring numbers in O(nLogn) time. First sort the numbers using an O(nLogn) sorting algorithm like Merge Sort, Heap Sort.. etc. Once the array is sorted, all we need to do is a linear scan of the array and print the odd occurring number. We can also use hashing. Create an empty hash table which will have elements and their counts. Pick all elements of input array one by one. Look for the picked element in hash table. If the element is found in hash table, increment its count in table. If the element is not found, then enter it in hash table with count as 1. After all elements are entered in hash table, scan the hash table and print elements with odd count. This approach may take O(n) time on average, but it requires O(n) extra space.

A O(n) time and O(1) extra space solution: The idea is similar to method 2 of this post. Let the two odd occurring numbers be x and y. We use bitwise XOR to get x and y. The first step is to do XOR of all elements present in array. XOR of all elements gives us XOR of x and y because of the following properties of XOR operation. 1) XOR of any number n with itself gives us 0, i.e., n ^ n = 0 2) XOR of any number n with 0 gives us n, i.e., n ^ 0 = n

12

3) XOR is cumulative and associative. So we have XOR of x and y after the first step. Let the value of XOR be xor2. Every set bit in xor2 indicates that the corresponding bits in x and y have values different from each other. For example, if x = 6 (0110) and y is 15 (1111), then xor2 will be (1001), the two set bits in xor2 indicate that the corresponding bits in x and y are different. In the second step, we pick a set bit of xor2 and divide array elements in two groups. Both x and y will go to different groups. In the following code, the rightmost set bit of xor2 is picked as it is easy to get rightmost set bit of a number. If we do XOR of all those elements of array which have the corresponding bit set (or 1), then we get the first odd number. And if we do XOR of all those elements which have the corresponding bit 0, then we get the other odd occurring number. This step works because of the same properties of XOR. All the occurrences of a number will go in same set. XOR of all occurrences of a number which occur even number number of times will result in 0 in its set. And the xor of a set will be one of the odd occurring elements

12)Find a pair with the given difference


bool findPair(int arr[], int size, int n) { // Initialize positions of two elements int i = 0; int j = 1; // Search for a pair while (i<size && j<size) { if (i != j && arr[j]-arr[i] == n) { printf("Pair Found: (%d, %d)", arr[i], arr[j]); return true; } else if (arr[j]-arr[i] < n) j++; else i++; } printf("No such pair"); return false; }

13

Hashing can also be used to solve this problem. Create an empty hash table HT. Traverse the array, use array elements as hash keys and enter them in HT. Traverse the array again look for value n + arr[i] in HT. Please write comments if you find any of the above codes/algorithms incorrect, or find other ways to solve the same problem.

13)Maximum Product Subarray


// Utility functions to get minimum of two integers int min (int x, int y) {return x < y? x : y; } // Utility functions to get maximum of two integers int max (int x, int y) {return x > y? x : y; } /* Returns the product of max product subarray. Assumes that the given array always has a subarray with product more than 1 */ int maxSubarrayProduct(int arr[], int n) { // max positive product ending at the current position int max_ending_here = 1; // min negative product ending at the current position int min_ending_here = 1; // Initialize overall max product int max_so_far = 1; /* Traverse throught the array. Following values are maintained after the ith iteration: max_ending_here is always 1 or some positive product ending with arr[i]

14

min_ending_here is always 1 or some negative product ending with arr[i] */ for (int i = 0; i < n; i++) { /* If this element is positive, update max_ending_here. Update min_ending_here only if min_ending_here is negative */ if (arr[i] > 0) { max_ending_here = max_ending_here*arr[i]; min_ending_here = min (min_ending_here * arr[i],1); } /* If this element is 0, then the maximum product cannot end here, make both max_ending_here and min_ending_here 0 Assumption: Output is alway greater than or equal to 1. */ else if (arr[i] == 0) { max_ending_here = 1; min_ending_here = 1; }

/* If element is negative. This is tricky max_ending_here can either be 1 or positive. min_ending_here can either be 1 or negative. next min_ending_here will always be prev. max_ending_here * arr[i] next max_ending_here will be 1 if prev min_ending_here is 1, otherwise next max_ending_here will be prev min_ending_here * arr[i] */ else { int temp = max_ending_here; max_ending_here = max (min_ending_here * arr[i],1); min_ending_here = temp * arr[i]; } // update max_so_far, if needed if (max_so_far < max_ending_here) max_so_far = max_ending_here; } return max_so_far; }

15

14)Largest Sum Contiguous Subarray


Kadanes Algorithm:

Initialize: max_so_far = 0 max_ending_here = 0 Loop for each element of the array (a) max_ending_here = max_ending_here + a[i] (b) if(max_ending_here < 0) max_ending_here = 0 (c) if(max_so_far < max_ending_here) max_so_far = max_ending_here return max_so_far
Lets take the example: {-2, -3, 4, -1, -2, 1, 5, -3} max_so_far = max_ending_here = 0

16

for i=0, a[0] = -2 max_ending_here = max_ending_here + (-2) Set max_ending_here = 0 because max_ending_here < 0 for i=1, a[1] = -3 max_ending_here = max_ending_here + (-3) Set max_ending_here = 0 because max_ending_here < 0 for i=2, a[2] = 4 max_ending_here = max_ending_here + (4) max_ending_here = 4 max_so_far is updated to 4 because max_ending_here greater than max_so_far which was 0 till now for i=3, a[3] = -1 max_ending_here = max_ending_here + (-1) max_ending_here = 3 for i=4, a[4] = -2 max_ending_here = max_ending_here + (-2) max_ending_here = 1 for i=5, a[5] = 1 max_ending_here = max_ending_here + (1) max_ending_here = 2 for i=6, a[6] = 5 max_ending_here = max_ending_here + (5) max_ending_here = 7 max_so_far is updated to 7 because max_ending_here is greater than max_so_far for i=7, a[7] = -3 max_ending_here = max_ending_here + (-3) max_ending_here = 4

17

15)Find the maximum element in an array which is first increasing and then decreasing
Method 1 (Linear Search) We can traverse the array and keep track of maximum and element. And finally return the maximum element.

#include <stdio.h> int findMaximum(int arr[], int low, int high) { int max = arr[low]; int i; for (i = low; i <= high; i++)

18

{ if (arr[i] > max) max = arr[i]; } return max; } /* Driver program to check above functions */ int main() { int arr[] = {1, 30, 40, 50, 60, 70, 23, 20}; int n = sizeof(arr)/sizeof(arr[0]); printf("The maximum element is %d", findMaximum(arr, 0, n1)); getchar(); return 0; }
Time Complexity: O(n) Method 2 (Binary Search) We can modify the standard Binary Search algorithm for the given type of arrays. i) If the mid element is greater than both of its adjacent elements, then mid is the maximum. ii) If mid element is greater than its next element and smaller than the previous element then maximum lies on left side of mid. Example array: {3, 50, 10, 9, 7, 6} iii) If mid element is smaller than its next element and greater than the previous element then maximum lies on right side of mid. Example array: {2, 4, 6, 8, 10, 3, 1}

19

Potrebbero piacerti anche