Array.pdf
Short Description
Download Array.pdf...
Description
P age |1
Given an array A[] and a number x, check for pair in A[] with sum as x May 30, 2009
Write a C program that, given an array A[] of n numbers and another number x, determines whether or not there exist two elements in S whose sum is exactly x. METHOD 1 (Use Sorting) Algorithm:
hasArrayTwoCandidates (A[], ar_size, sum) 1) Sort the array in non-decreasing order. 2) Initialize two index variables to find the candidate elements in the sorted array. (a) Initialize first to the leftmost index: l = 0 (b) Initialize second the rightmost index: r = ar_size-1 3) Loop while l < r. (a) If (A[l] + A[r] == sum) then return 1 (b) Else if( A[l] + A[r] < sum ) then l++ (c) Else r-4) No candidates in whole array - return 0 Time Complexity: Depends on what sorting algorithm we use. If we use Merge Sort or Heap Sort then (-)(nlogn) in worst case. If we use Quick Sort then O(n^2) in worst case. Auxiliary Space : Again, depends on sorting algorithm. For example auxiliary space is O(n) for merge sort and O(1) for Heap Sort. Example: Let Array be {1, 4, 45, 6, 10, -8} and sum to find be 16 Sort the array A = {-8, 1, 4, 6, 10, 45} Initialize l = 0, r = 5 A[l] + A[r] ( -8 + 45) > 16 => decrement r. Now r = 10 A[l] + A[r] ( -8 + 10) < 2 => increment l. Now l = 1 A[l] + A[r] ( 1 + 10) < 16 => increment l. Now l = 2
P age |2
A[l] + A[r] ( 4 + 10) < 14 => increment l. Now l = 3 A[l] + A[r] ( 6 + 10) == 16 => Found candidates (return 1) Note: If there are more than one pair having the given sum then this algorithm reports only one. Can be easily extended for this though. Implementation: # include # define bool int void quickSort(int
*, int
, int
bool hasArrayTwoCandidates(int { int l, r;
);
A[], int
arr_size, int
sum)
/* Sort the elements */ quickSort(A, 0, arr_size-1); /* Now look for the two candidates in the sorted array*/ l = 0; r = arr_size-1; while(l < r) { if(A[l] + A[r] == sum) return 1; elseif(A[l] + A[r] < sum) l++; else// A[i] + A[j] > sum r--; } return 0; } /* Driver program to test above function */ int main() { int A[] = {1, 4, 45, 6, 10, -8}; int n = 16; int arr_size = 6; if( hasArrayTwoCandidates(A, arr_size, n)) printf("Array has two elements with sum 16"); else printf("Array doesn't have two elements with sum 16 "); getchar(); return 0; } /* FOLLOWING FUNCTIONS ARE ONLY FOR SORTING PURPOSE */
P age |3 void exchange(int { int temp; temp = *a; *a = *b; *b = temp; }
*a, int *b)
int partition(int A[], int si, int ei) { int x = A[ei]; int i = (si - 1); int j; for(j = si; j Starting index ei --> Ending index */ void quickSort(int A[], int si, int ei) { int pi; /* Partitioning index */ if(si < ei) { pi = partition(A, si, ei); quickSort(A, si, pi - 1); quickSort(A, pi + 1, ei); } }
METHOD 2 (Use Hash Map) Thanks to Bindu for suggesting this method and thanks to Shekhu for providing code. This method works in O(n) time if range of numbers is known. Let sum be the given sum and A[] be the array in which we need to find pair.
1) Initialize Binary Hash Map M[] = {0, 0, …} 2) Do following for each element A[i] in A[]
P age |4
(a) If M[x - A[i]] is set then print the pair (A[i], x – A[i]) (b) Set M[A[i]] Implementation: #include #define MAX 100000 void printPairs(int arr[], int arr_size, int sum) { int i, temp; bool binMap[MAX] = {0}; /*initialize hash map as 0*/ for(i = 0; i < arr_size; i++) { temp = sum - arr[i]; if(temp >= 0 && binMap[temp] == 1) { printf("Pair with given sum %d is (%d, %d) \n", sum, arr[i], temp); } binMap[arr[i]] = 1; } } /* Driver program to test above function */ int main() { int A[] = {1, 4, 45, 6, 10, 8}; int n = 16; int arr_size = 6; printPairs(A, arr_size, n); getchar(); return 0; }
Time Complexity: O(n) Auxiliary Space: O(R) where R is range of integers. If range of numbers include negative numbers then also it works. All we have to do for negative numbers is to make everything positive by adding the absolute value of smallest negative integer to all numbers.
Majority Element May 30, 2009
P age |5
Majority Element: A majority element in an array A[] of size n is an element that appears more than n/2 times (and hence there is at most one such element). Write a function which takes an array and emits the majority element (if it exists), otherwise prints NONE as follows:
I/P : 3 3 4 2 4 4 2 4 4 O/P : 4 I/P : 3 3 4 2 4 4 2 4 O/P : NONE METHOD 1 (Basic) The basic solution is to have two loops and keep track of maximum count for all different elements. If maximum count becomes greater than n/2 then break the loops and return the element having maximum count. If maximum count doesn‟t become more than n/2 then majority element doesn‟t exist. Time Complexity: O(n*n). Auxiliary Space : O(1).
METHOD 2 (Using Binary Search Tree) Thanks to Sachin Midha for suggesting this solution. Node of the Binary Search Tree (used in this approach) will be as follows. structtree { int element; int count; }BST;
Insert elements in BST one by one and if an element is already present then increment the count of the node. At any stage, if count of a node becomes more than n/2 then return. The method works well for the cases where n/2+1 occurrences of the majority element is present in the starting of the array, for example {1, 1, 1, 1, 1, 2, 3, 4}. Time Complexity: If a binary search tree is used then time complexity will be
P age |6
O(n^2). If a self-balancing-binary-search tree is used then O(nlogn) Auxiliary Space: O(n)
METHOD 3 (Using Moore’s Voting Algorithm) This is a two step process. 1. Get an element occurring most of the time in the array. This phase will make sure that if there is a majority element then it will return that only. 2. Check if the element obtained from above step is majority element. 1. Finding a Candidate: The algorithm for first phase that works in O(n) is known as Moore‟s Voting Algorithm. Basic idea of the algorithm is if we cancel out each occurrence of an element e with all the other elements that are different from e then e will exist till end if it is a majority element.
findCandidate(a[], size) 1. Initialize index and count of majority element maj_index = 0, count = 1 2. Loop for i = 1 to size – 1 (a)If a[maj_index] == a[i] count++ (b)Else count--; (c)If count == 0 maj_index = i; count = 1 3. Return a[maj_index] Above algorithm loops through each element and maintains a count of a[maj_index], If next element is same then increments the count, if next element is not same then decrements the count, and if the count reaches 0 then changes the maj_index to the current element and sets count to 1. First Phase algorithm gives us a candidate element. In second phase we need to check if the candidate is really a majority element. Second phase is simple and can
P age |7
be easily done in O(n). We just need to check if count of the candidate element is greater than n/2. Example: A[] = 2, 2, 3, 5, 2, 2, 6 Initialize: maj_index = 0, count = 1 –> candidate „2? 2, 2, 3, 5, 2, 2, 6 Same as a[maj_index] => count = 2 2, 2, 3, 5, 2, 2, 6 Different from a[maj_index] => count = 1 2, 2, 3, 5, 2, 2, 6 Different from a[maj_index] => count = 0 Since count = 0, change candidate for majority element to 5 => maj_index = 3, count = 1 2, 2, 3, 5, 2, 2, 6 Different from a[maj_index] => count = 0 Since count = 0, change candidate for majority element to 2 => maj_index = 4 2, 2, 3, 5, 2, 2, 6 Same as a[maj_index] => count = 2 2, 2, 3, 5, 2, 2, 6 Different from a[maj_index] => count = 1 Finally candidate for majority element is 2. First step uses Moore‟s Voting Algorithm to get a candidate for majority element. 2. Check if the element obtained in step 1 is majority
printMajority (a[], size) 1. Find the candidate for majority 2. If candidate is majority. i.e., appears more than n/2 times. Print the candidate
P age |8
3.
Else Print "NONE"
Implementation of method 3: /* Program for finding out majority element in an array */ # include # define bool int int findCandidate(int *, int ); bool isMajority(int *, int , int ); /* Function to print Majority Element */ void printMajority(int a[], int size) { /* Find the candidate for Majority*/ int cand = findCandidate(a, size); /* Print the candidate if it is Majority*/ if(isMajority(a, size, cand)) printf(" %d ", cand); else printf("NO Majority Element"); } /* Function to find the candidate for Majority */ int findCandidate(int a[], int size) { int maj_index = 0, count = 1; int i; for(i = 1; i < size; i++) { if(a[maj_index] == a[i]) count++; else count--; if(count == 0) { maj_index = i; count = 1; } } return a[maj_index]; } /* Function to check if the candidate occurs more than n/2 times */ bool isMajority(int a[], int size, int cand) { int i, count = 0; for(i = 0; i < size; i++) if(a[i] == cand) count++; if(count > size/2) return 1; else return 0;
P age |9 } /* Driver function to test above functions */ int main() { int a[] = {1, 3, 3, 1, 2}; printMajority(a, 5); getchar(); return 0; }
Time Complexity: O(n) Auxiliary Space : O(1) Now give a try to below question Given an array of 2n elements of which n elements are same and the remaining n elements are all different. Write a C program to find out the value which is present n times in the array. There is no restriction on the elements in the array. They are random (In particular they not sequential).
Find the Number Occurring Odd Number of Times June 22, 2009
Given an array of positive integers. All numbers occur even number of times except one number which occurs odd number of times. Find the number in O(n) time & constant space. Example: I/P = [1, 2, 3, 2, 3, 1, 3] O/P = 3 Algorithm: Do bitwise XOR of all the elements. Finally we get the number which has odd occurrences.
Program: #include int getOddOccurrence(int ar[], int ar_size) { int i; int res = 0; for(i=0; i < ar_size; i++)
P a g e | 10 res = res ^ ar[i]; return res; } /* Diver function to test above function */ int main() { int ar[] = {2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2}; int n = sizeof(ar)/sizeof(ar[0]); printf("%d", getOddOccurrence(ar, n)); return 0; }
Time Complexity: O(n)
Largest Sum Contiguous Subarray June 22, 2009
Write an efficient C program to find the sum of contiguous subarray within a one dimensional array of numbers which has the largest sum. Kadane’s 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 Explanation: Simple idea of the Kadane's algorithm is to look for all positive contiguous segments of the array (max_ending_here is used for this). And keep track of maximum sum contiguous segment among all positive segments (max_so_far is used for this).
P a g e | 11
Each time we get a positive sum compare it with max_so_far and update max_so_far if it is greater than max_so_far Lets take the example: {-2, -3, 4, -1, -2, 1, 5, -3} max_so_far = max_ending_here = 0 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
P a g e | 12
for i=7, a[7] = -3 max_ending_here = max_ending_here + (-3) max_ending_here = 4 Program: #include int maxSubArraySum(int a[], int size) { int max_so_far = 0, max_ending_here = 0; int i; for(i = 0; i < size; i++) { max_ending_here = max_ending_here + a[i]; if(max_ending_here < 0) max_ending_here = 0; if(max_so_far < max_ending_here) max_so_far = max_ending_here; } return max_so_far; } /*Driver program to test maxSubArraySum*/ int main() { int a[] = {-2, -3, 4, -1, -2, 1, 5, -3}; int n = sizeof(a)/sizeof(a[0]); int max_sum = maxSubArraySum(a, n); printf("Maximum contiguous sum is %d\n", max_sum); getchar(); return 0; }
Notes: Algorithm doesn't work for all negative numbers. It simply returns 0 if all numbers are negative. For handling this we can add an extra phase before actual implementation. The phase will look if all numbers are negative, if they are it will return maximum of them (or smallest in terms of absolute value). There may be other ways to handle it though. Above program can be optimized further, if we compare max_so_far with max_ending_here only if max_ending_here is greater than 0. int maxSubArraySum(int a[], int size) { int max_so_far = 0, max_ending_here = 0; int i; for(i = 0; i < size; i++) { max_ending_here = max_ending_here + a[i]; if(max_ending_here < 0)
P a g e | 13 max_ending_here = 0; /* Do not compare for all elements. Compare only when max_ending_here > 0 */ elseif(max_so_far < max_ending_here) max_so_far = max_ending_here; } return max_so_far; }
Time Complexity: O(n) Algorithmic Paradigm: Dynamic Programming Following is another simple implementation suggested by Mohit Kumar. The implementation handles the case when all numbers in array are negative. #include int max(int x, int y) { return (y > x)? y : x; } int maxSubArraySum(int a[], int size) { int max_so_far = a[0], i; int curr_max = a[0]; for(i = 1; i < size; i++) { curr_max = max(a[i], curr_max+a[i]); max_so_far = max(max_so_far, curr_max); } return max_so_far; } /* Driver program to test maxSubArraySum */ int main() { int a[] = {-2, -3, 4, -1, -2, 1, 5, -3}; int n = sizeof(a)/sizeof(a[0]); int max_sum = maxSubArraySum(a, n); printf("Maximum contiguous sum is %d\n", max_sum); return 0; }
Now try below question Given an array of integers (possibly some of the elements negative), write a C program to find out the *maximum product* possible by adding 'n' cons ecutive integers in the array, n = ar2[j] and ar1[i] right) return getMedianRec(ar2, ar1, 0, n-1, n); i = (left + right)/2; j = n - i - 1; /* Index of ar2[] */ /* Recursion terminates here.*/ if(ar1[i] > ar2[j] && (j == n-1 || ar1[i] ar1[i-1]) return (ar1[i] + ar2[j])/2; else return (ar1[i] + ar1[i-1])/2; } /*Search in left half of ar1[]*/ elseif(ar1[i] > ar2[j] && j != n-1 && ar1[i] > ar2[j+1]) return getMedianRec(ar1, ar2, left, i-1, n); /*Search in right half of ar1[]*/ else/* ar1[i] is smaller than both ar2[j] and ar2[j+1]*/ return getMedianRec(ar1, ar2, i+1, right, n); } /* Driver program to test above function */ int main() { int ar1[] = {1, 12, 15, 26, 38}; int ar2[] = {2, 13, 17, 30, 45}; int n1 = sizeof(ar1)/sizeof(ar1[0]); int n2 = sizeof(ar2)/sizeof(ar2[0]); if(n1 == n2)
P a g e | 29 printf("Median is %d", getMedian(ar1, ar2, n1)); else printf("Doesn't work for arrays of unequal size"); getchar(); return 0; }
Time Complexity: O(logn) Algorithmic Paradigm: Divide and Conquer The above solutions can be optimized for the cases when all elements of one array are smaller than all elements of other array. For example, in method 3, we can change the getMedian() function to following so that these cases can be handled in O(1) time. Thanks to nutcracker for suggesting this optimization. /* This function return s median of ar1[] and ar2[]. Assumptions in this function: Both ar1[] and ar2[] are sorted arrays Both have n elements */ int getMedian(int ar1[], int ar2[], int n) { // If all elements of array 1 are smaller then // median is average of last element of ar1 and // first element of ar2 if(ar1[n-1] < ar2[0]) return (ar1[n-1]+ar2[0])/2; // If all elements of array 1 are smaller then // median is average of first element of ar1 and // last element of ar2 if(ar2[n-1] < ar1[0]) return (ar2[n-1]+ar1[0])/2; return getMedianRec(ar1, ar2, 0, n-1, n); }
Write a program to reverse an array October 30, 2009
Iterative way: 1) Initialize start and end indexes. start = 0, end = n-1 2) In a loop, swap arr[start] with arr[end] and change start and end as follows. start = start +1; end = end – 1 /* Function to reverse arr[] from start to end*/ void rvereseArray(int arr[], int start, int end) { int temp; while(start < end)
P a g e | 30 { temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; end--; } } /* Utility that prints out an array on a line */ void printArray(int arr[], int size) { int i; for(i=0; i < size; i++) printf("%d ", arr[i]); printf("\n"); } /* Driver function to test above functions */ int main() { int arr[] = {1, 2, 3, 4, 5, 6}; printArray(arr, 6); rvereseArray(arr, 0, 5); printf("Reversed array is \n"); printArray(arr, 6); getchar(); return 0; }
Time Complexity: O(n) Recursive Way: 1) Initialize start and end indexes start = 0, end = n-1 2) Swap arr[start] with arr[end] 3) Recursively call reverse for rest of the array. /* Function to reverse arr[] from start to end*/ void rvereseArray(int arr[], int start, int end) { int temp; if(start >= end) return ; temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; rvereseArray(arr, start+1, end-1); } /* Utility that prints out an array on a line */ void printArray(int arr[], int size) {
P a g e | 31 int i; for(i=0; i < size; i++) printf("%d ", arr[i]); printf("\n"); } /* Driver function to test above functions */ int main() { int arr[] = {1, 2, 3, 4, 5}; printArray(arr, 5); rvereseArray(arr, 0, 4); printf("Reversed array is \n"); printArray(arr, 5); getchar(); return 0; }
Time Complexity: O(n)
Program for array rotation November 10, 2009
Write a function rotate(ar[], d, n) that rotates arr[] of size n by d elements.
Rotation of the above array by 2 will make array
METHOD 1 (Use temp array)
Input arr[] = [1, 2, 3, 4, 5, 1) Store d elements in a temp temp[] = [1, 2] 2) Shift rest of the arr[] arr[] = [3, 4, 5, 6, 7, 6, 3) Store back the d elements arr[] = [3, 4, 5, 6, 7, 1,
6, 7], d = 2, n =7 array 7] 2]
P a g e | 32
Time complexity O(n) Auxiliary Space: O(d)
METHOD 2 (Rotate one by one)
leftRotate(arr[], d, n) start For i = 0 to i < d Left rotate all elements of arr[] by one end To rotate by one, store arr[0] in a temporary variable temp, move arr[1] to arr[0], arr[2] to arr[1] …and finally temp to arr[n-1] Let us take the same example arr[] = [1, 2, 3, 4, 5, 6, 7], d = 2 Rotate arr[] by one 2 times We get [2, 3, 4, 5, 6, 7, 1] after first rotation and [ 3, 4, 5, 6, 7, 1, 2] after second rotation. /*Function to left Rotate arr[] of size n by 1*/ void leftRotatebyOne(int arr[], int n); /*Function to left rotate arr[] of size n by d*/ void leftRotate(int arr[], int d, int n) { int i; for(i = 0; i < d; i++) leftRotatebyOne(arr, n); } void leftRotatebyOne(int arr[], int n) { int i, temp; temp = arr[0]; for(i = 0; i < n-1; i++) arr[i] = arr[i+1]; arr[i] = temp; } /* utility function to print an array */ void printArray(int arr[], int size) { int i; for(i = 0; i < size; i++) printf("%d ", arr[i]); }
P a g e | 33
/* Driver program to test above functions */ int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7}; leftRotate(arr, 2, 7); printArray(arr, 7); getchar(); return 0; }
Time complexity: O(n*d) Auxiliary Space: O(1)
METHOD 3 (A Juggling Algorithm) This is an extension of method 2. Instead of moving one by one, divide the array in different sets where number of sets is equal to GCD of n and d and move the elements within sets. If GCD is 1 as is for the above example array (n = 7 and d =2), then elements will be moved within one set only, we just start with temp = arr[0] and keep moving arr[I+d] to arr[I] and finally store temp at the right place. Here is an example for n =12 and d = 3. GCD is 3 and
Let arr[] be {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} a) Elements are first moved in first set – (See below diagram for this movement)
arr[] after this step --> {42 3 75 6 108 9 111 12}
P a g e | 34
b)
Then in second set. arr[] after this step --> {4 5 3 7 8 6 10 11 9 1 2 12} c)
Finally in third set. arr[] after this step --> {4 5 67 8 910 11 121
2 3} /* function to print an array */ void printArray(int arr[], int size); /*Fuction to get gcd of a and b*/ int gcd(int a,int b); /*Function to left rotate arr[] of siz n by d*/ void leftRotate(int arr[], int d, int n) { int i, j, k, temp; for(i = 0; i < gcd(d, n); i++) { /* move i-th values of blocks */ temp = arr[i]; j = i; while(1) { k = j + d; if(k >= n) k = k - n; if(k == i) break; arr[j] = arr[k]; j = k; } arr[j] = temp; } } /*UTILITY FUNCTIONS*/ /* function to print an array */ void printArray(int arr[], int size) { int i; for(i = 0; i < size; i++) printf("%d ", arr[i]); } /*Fuction to get gcd of a and b*/ int gcd(int a,int b) { if(b==0) return a; else return gcd(b, a%b); }
P a g e | 35
/* Driver program to test above functions */ int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7}; leftRotate(arr, 2, 7); printArray(arr, 7); getchar(); return 0; }
Time complexity: O(n) Auxiliary Space: O(1) Please see following posts for other methods of array rotation: Block swap algorithm for array rotation Reversal algorithm for array rotation
Reversal algorithm for array rotation November 10, 2009
Write a function rotate(arr[], d, n) that rotates arr[] of size n by d elements.
Rotation of the above array by 2 will make array
Method 4(The Reversal Algorithm) Please read this for first three methods of array rotation. Algorithm:
rotate(arr[], d, reverse(arr[], reverse(arr[], reverse(arr[],
n) 1, d) ; d + 1, n); l, n);
P a g e | 36
Let AB are the two parts of the input array where A = arr[0..d-1] and B = arr[d..n-1]. The idea of the algorithm is: Reverse A to get ArB. /* Ar is reverse of A */ Reverse B to get ArBr. /* Br is reverse of B */ Reverse all to get (ArBr) r = BA. For arr[] = [1, 2, 3, 4, 5, 6, 7], d =2 and n = 7 A = [1, 2] and B = [3, 4, 5, 6, 7] Reverse A, we get ArB = [2, 1, 3, 4, 5, 6, 7] Reverse B, we get ArBr = [2, 1, 7, 6, 5, 4, 3] Reverse all, we get (ArBr)r = [3, 4, 5, 6, 7, 1, 2] Implementation: /*Utility function to print an array */ void printArray(int arr[], int size); /* Utility function to reverse arr[] from start to end */ void rvereseArray(int arr[], int start, int end); /* Function to left void leftRotate(int { rvereseArray(arr, rvereseArray(arr, rvereseArray(arr, }
rotate arr[] of size n by d */ arr[], int d, int n) 0, d-1); d, n-1); 0, n-1);
/*UTILITY FUNCTIONS*/ /* function to print an array */ void printArray(int arr[], int size) { int i; for(i = 0; i < size; i++) printf("%d ", arr[i]); printf("%\n "); } /*Function to reverse arr[] from index start to end*/ void rvereseArray(int arr[], int start, int end) { int i; int temp; while(start < end) { temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; end--; }
P a g e | 37 } /* Driver program to test above functions */ int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7}; leftRotate(arr, 2, 7); printArray(arr, 7); getchar(); return 0; }
Time Complexity: O(n)
Block swap algorithm for array rotation November 14, 2009
Write a function rotate(ar[], d, n) that rotates arr[] of size n by d elements.
Rotation of the above array by 2 will make array
Algorithm:
Initialize A = arr[0..d-1] and B = arr[d..n-1] 1) Do following until size of A is equal to size of B a) If A is shorter, divide B into Bl and Br such that Br is of same length as A. Swap A and Br to change ABlBr into BrBlA. Now A is at its final place, so recur on pieces of B. b) If A is longer, divide A into Al and Ar such that Al is of same length as B Swap Al and B to change AlArB into BArAl. Now B
P a g e | 38
is at its final place, so recur on pieces of A. 2) Finally when A and B are of equal size, block swap them. Recursive Implementation: #include /*Prototype for utility functions */ void printArray(int arr[], int size); void swap(int arr[], int fi, int si, int d); void leftRotate(int arr[], int d, int n) { /* Return If number of elements to be rotated is zero or equal to array size */ if(d == 0 || d == n) return ; /*If number of elements to be rotated is exactly half of array size */ if(n-d == d) { swap(arr, 0, n-d, d); return ; } /* If A is shorter*/ if(d < n-d) { swap(arr, 0, n-d, d); leftRotate(arr, d, n-d); } else/* If B is shorter*/ { swap(arr, 0, d, n-d); leftRotate(arr+n-d, 2*d-n, d); /*This is tricky*/ } } /*UTILITY FUNCTIONS*/ /* function to print an array */ void printArray(int arr[], int size) { int i; for(i = 0; i < size; i++) printf("%d ", arr[i]); printf("%\n "); } /*This function swaps d elements starting at index fi with d elements starting at index si */ void swap(int arr[], int fi, int si, int d)
P a g e | 39 { int i, temp; for(i = 0; i excl)? incl: excl; /* current max including i */ incl = excl + arr[i]; excl = excl_new; } /* return max of incl and excl */ return ((incl > excl)? incl : excl); }
P a g e | 42
/* Driver program to test above function */ int main() { int arr[] = {5, 5, 10, 100, 10, 5}; printf("%d \n", FindMaxSum(arr, 6)); getchar(); return 0; } Time Complexity: O(n)
Leaders in an array December 7, 2009
Write a program to print all the LEADERS in the array. An element is leader if it is greater than all the elements to its right side. And the rightmost element is always a leader. For example int the array {16, 17, 4, 3, 5, 2}, leaders are 17, 5 and 2. Let the input array be arr[] and size of the array be size. Method 1 (Simple) Use two loops. The outer loop runs from 0 to size – 1 and one by one picks all elements from left to right. The inner loop compares the picked element to all the elements to its right side. If the picked element is greater than all the elements to its right side, then the picked element is the leader. /*Function to print leaders in an array */ void printLeaders(int arr[], int size) { int i, j; for(i = 0; i < size; i++) { for(j = i+1; j < size; j++) { if(arr[i] arr[mid-1]) && (arr[mid] == x) ) return mid; elseif(x > arr[mid]) return _binarySearch(arr, (mid + 1), high, x); else return _binarySearch(arr, low, (mid -1), x); } return -1; } /* Driver program to check above functions */ int main() { int arr[] = {1, 2, 3, 3, 3, 3, 10}; int n = sizeof(arr)/sizeof(arr[0]); int x = 3; if(isMajority(arr, n, x)) printf("%d appears more than %d times in arr[]", x, n/2); else printf("%d does not appear more than %d times in arr[]", x, n/2); return 0; }
Time Complexity: O(Logn) Algorithmic Paradigm: Divide and Conquer
Maximum and minimum of an array using minimum number of comparisons February 15, 2010
Write a C function to return minimum and maximum in an array. You program should make minimum number of comparisons. First of all, how do we return multiple values from a C function? We can do it either using structures or pointers. We have created a structure named pair (which contains min and max) to return multiple values. structpair { int min;
P a g e | 59 int max; };
And the function declaration becomes: struct pair getMinMax(int arr[], int n) where arr[] is the array of size n whose minimum and maximum are needed. METHOD 1 (Simple Linear Search) Initialize values of min and max as minimum and maximum of the first two elements respectively. Starting from 3rd, compare each element with max and min, and change max and min accordingly (i.e., if the element is smaller than min then change min, else if the element is greater than max then change max, else ignore the element) /* structure is used to return #include structpair { int min; int max; };
two values from minMax() */
structpair getMinMax(int arr[], int n) { structpair minmax; int i; /*If there is only one element then return if(n == 1) { minmax.max = arr[0]; minmax.min = arr[0]; return minmax; }
it as min and max both*/
/* If there are more than one elements, then initialize min and max*/ if(arr[0] > arr[1]) { minmax.max = arr[0]; minmax.min = arr[1]; } else { minmax.max = arr[0]; minmax.min = arr[1]; } for(i = 2; i minmax.max) minmax.max = arr[i]; elseif(arr[i] <
minmax.min)
P a g e | 60 minmax.min = arr[i]; } return minmax; } /* Driver program to test above function */ int main() { int arr[] = {1000, 11, 445, 1, 330, 3000}; int arr_size = 6; structpair minmax = getMinMax (arr, arr_size); printf("\nMinimum element is %d", minmax.min); printf("\nMaximum element is %d", minmax.max); getchar(); }
Time Complexity: O(n) In this method, total number of comparisons is 1 + 2(n-2) in worst case and 1 + n – 2 in best case. In the above implementation, worst case occurs when elements are sorted in descending order and best case occurs when elements are sorted in ascending order.
METHOD 2 (Tournament Method) Divide the array into two parts and compare the maximums and minimums of the the two parts to get the maximum and the minimum of the the whole array.
Pair MaxMin(array, array_size) if array_size = 1 return element as both max and min else if arry_size = 2 one comparison to determine max and min return that pair else /* array_size > 2 */ recur for max and min of left half recur for max and min of right half one comparison determines true max of the two candidates one comparison determines true min of the two candidates
P a g e | 61
return the pair of max and min Implementation /* structure is used to return #include structpair { int min; int max; };
two values from minMax() */
structpair getMinMax(int arr[], int low, int high) { structpair minmax, mml, mmr; int mid; /* If there is only on element */ if(low == high) { minmax.max = arr[low]; minmax.min = arr[low]; return minmax; } /* If there are two elements */ if(high == low + 1) { if(arr[low] > arr[high]) { minmax.max = arr[low]; minmax.min = arr[high]; } else { minmax.max = arr[high]; minmax.min = arr[low]; } return minmax; } /* If mid = mml = mmr =
there are more than 2 elements */ (low + high)/2; getMinMax(arr, low, mid); getMinMax(arr, mid+1, high);
/* compare minimums of two parts*/ if(mml.min < mmr.min) minmax.min = mml.min; else minmax.min = mmr.min; /* compare maximums of two parts*/ if(mml.max > mmr.max) minmax.max = mml.max; else
P a g e | 62 minmax.max = mmr.max; return minmax; } /* Driver program to test above function */ int main() { int arr[] = {1000, 11, 445, 1, 330, 3000}; int arr_size = 6; structpair minmax = getMinMax(arr, 0, arr_size-1); printf("\nMinimum element is %d", minmax.min); printf("\nMaximum element is %d", minmax.max); getchar(); }
Time Complexity: O(n) Total number of comparisons: let number of comparisons be T(n). T(n) can be written as follows: Algorithmic Paradigm: Divide and Conquer
T(n) = T(floor(n/2)) + T(ceil(n/2)) + 2 T(2) = 1 T(1) = 0 If n is a power of 2, then we can write T(n) as:
T(n) = 2T(n/2) + 2 After solving above recursion, we get
T(n)
= 3/2n -2
Thus, the approach does 3/2n -2 comparisons if n is a power of 2. And it does more than 3/2n -2 comparisons if n is not a power of 2.
METHOD 3 (Compare in Pairs) If n is odd then initialize min and max as first element. If n is even then initialize min and max as minimum and maximum of the first two elements respectively.
P a g e | 63
For rest of the elements, pick them in pairs and compare their maximum and minimum with max and min respectively. #include /* structure is used to return structpair { int min; int max; };
two values from minMax() */
structpair getMinMax(int arr[], int n) { structpair minmax; int i; /* If array has even number of elements then initialize the first two elements as minimum and maximum */ if(n%2 == 0) { if(arr[0] > arr[1]) { minmax.max = arr[0]; minmax.min = arr[1]; } else { minmax.min = arr[0]; minmax.max = arr[1]; } i = 2; /* set the startung index for loop */ } /* If array initialize maximum */ else { minmax.min minmax.max i = 1; /* }
has odd number of elements then the first element as minimum and
= arr[0]; = arr[0]; set the startung index for loop */
/* In the while loop, pick elements in pair and compare the pair with max and min so far */ while(i < n-1) { if(arr[i] > arr[i+1]) { if(arr[i] > minmax.max) minmax.max = arr[i]; if(arr[i+1] < minmax.min) minmax.min = arr[i+1]; }
P a g e | 64 else { if(arr[i+1] > minmax.max) minmax.max = arr[i+1]; if(arr[i] < minmax.min) minmax.min = arr[i]; } i += 2; /* Increment the index by 2 as two elements are processed in loop */ } return minmax; } /* Driver program to test above function */ int main() { int arr[] = {1000, 11, 445, 1, 330, 3000}; int arr_size = 6; structpair minmax = getMinMax (arr, arr_size); printf("\nMinimum element is %d", minmax.min); printf("\nMaximum element is %d", minmax.max); getchar(); }
Time Complexity: O(n) Total number of comparisons: Different for even and odd n, see below:
If n is odd: 3*(n-1)/2 If n is even: 1 Initial comparison for initializing min and max, and 3(n-2)/2 comparisons for rest of the elements = 1 + 3*(n-2)/2 = 3n/2 -2 Second and third approaches make equal number of comparisons when n is a power of 2. In general, method 3 seems to be the best.
Segregate 0s and 1s in an array February 28, 2010
Asked by kapil. You are given an array of 0s and 1s in random order. Segregate 0s on left side and 1s on right side of the array. Traverse array only once.
P a g e | 65
Input array = [0, 1, 0, 1, 0, 0, 1, 1, 1, 0] Output array = [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] Method 1 (Count 0s or 1s) Thanks to Naveen for suggesting this method. 1) Count the number of 0s. Let count be C. 2) Once we have count, we can put C 0s at the beginning and 1s at the remaining n – C positions in array. Time Complexity: O(n) The method 1 traverses the array two times. Method 2 does the same in a single pass.
Method 2 (Use two indexes to traverse) Maintain two indexes. Initialize first index left as 0 and second index right as n-1. Do following while left < right a) Keep incrementing index left while there are 0s at it b) Keep decrementing index right while there are 1s at it c) If left < right then exchange arr[left] and arr[right] Implementation: #include /*Function to put all 0s on left and all 1s on right*/ void segregate0and1(int arr[], int size) { /* Initialize left and right indexes */ int left = 0, right = size-1; while(left < right) { /* Increment left index while we see 0 at left */ while(arr[left] == 0 && left < right) left++; /* Decrement right index while we see 1 at right */ while(arr[right] == 1 && left < right) right–; /* If left is smaller than right then there is a 1 at left and a 0 at right. Exchange arr[left] and arr[right]*/
P a g e | 66 if(left < right) { arr[left] = 0; arr[right] = 1; left++; right–; } } } /* driver program to test */ int main() { int arr[] = {0, 1, 0, 1, 1, 1}; int arr_size = 6, i = 0; segregate0and1(arr, arr_size); printf("array after segregation "); for(i = 0; i < 6; i++) printf("%d ", arr[i]); getchar(); return 0; }
Time Complexity: O(n)
k largest(or smallest) elements in an array | added Min Heap method March 1, 2010
Question: Write an efficient program for printing k largest elements in an array. Elements in array can be in any order. For example, if given array is [1, 23, 12, 9, 30, 2, 50] and you are asked for the largest 3 elements i.e., k = 3 then your program should print 50, 30 and 23.
Method 1 (Use Bubble k times) Thanks to Shailendra for suggesting this approach. 1) Modify Bubble Sort to run the outer loop at most k times. 2) Print the last k elements of the array obtained in step 1. Time Complexity: O(nk) Like Bubble sort, other sorting algorithms like Selection Sort can also be modified to get the k largest elements.
P a g e | 67
Method 2 (Use temporary array) K largest elements from arr[0..n-1] 1) Store the first k elements in a temporary array temp[0..k-1]. 2) Find the smallest element in temp[], let the smallest element be min. 3) For each element x in arr[k] to arr[n-1] If x is greater than the min then remove min from temp[] and insert x. 4) Print final k elements of temp[] Time Complexity: O((n-k)*k). If we want the output sorted then O((n-k)*k + klogk) Thanks to nesamani1822 for suggesting this method. Method 3(Use Sorting) 1) Sort the elements in descending order in O(nLogn) 2) Print the first k numbers of the sorted array O(k). Time complexity: O(nlogn) Method 4 (Use Max Heap) 1) Build a Max Heap tree in O(n) 2) Use Extract Max k times to get k maximum elements from the Max Heap O(klogn) Time complexity: O(n + klogn) Method 5(Use Oder Statistics) 1) Use order statistic algorithm to find the kth largest element. Please see the topic selection in worst-case linear time O(n) 2) Use QuickSort Partition algorithm to partition around the kth largest number O(n). 3) Sort the k-1 elements (elements greater than the kth largest element) O(kLogk). This step is needed only if sorted output is required. Time complexity: O(n) if we don‟t need the sorted output, otherwise O(n+kLogk) Thanks to Shilpi for suggesting the first two approaches. Method 6 (Use Min Heap) This method is mainly an optimization of method 1. Instead of using temp[] array, use Min Heap.
P a g e | 68
Thanks to geek4u for suggesting this method. 1) Build a Min Heap MH of the first k elements (arr[0] to arr[k-1]) of the given array. O(k) 2) For each element, after the kth element (arr[k] to arr[n-1]), compare it with root of MH. ……a) If the element is greater than the root then make it root and call heapify for MH ……b) Else ignore it. // The step 2 is O((n-k)*logk) 3) Finally, MH has k largest elements and root of the MH is the kth largest element. Time Complexity: O(k + (n-k)Logk) without sorted output. If sorted output is needed then O(k + (n-k)Logk + kLogk) All of the above methods can also be used to find the kth largest (or smallest) element.
Maximum size square sub-matrix with all 1s April 4, 2010
Given a binary matrix, find out the maximum size square sub-matrix with all 1s. For example, consider the below binary matrix.
0 1 0 1 1 0
1 1 1 1 1 0
1 0 1 1 1 0
0 1 1 1 1 0
1 0 0 0 1 0
The maximum square sub-matrix with all set bits is
1 1 1
1 1 1
1 1 1
P a g e | 69
Algorithm: Let the given binary matrix be M[R][C]. The idea of the algorithm is to construct an auxiliary size matrix S[][] in which each entry S[i][j] represents size of the square sub-matrix with all 1s including M[i][j] where M[i][j] is the rightmost and bottommost entry in sub-matrix.
1) Construct a sum matrix S[R][C] for the given M[R][C]. a) Copy first row and first columns as it is from M[][] to S[][] b) For other entries, use following expressions to construct S[][] If M[i][j] is 1 then S[i][j] = min(S[i][j-1], S[i-1][j], S[i1][j-1]) + 1 Else /*If M[i][j] is 0*/ S[i][j] = 0 2) Find the maximum entry in S[R][C] 3) Using the value and coordinates of maximum entry in S[i], print sub-matrix of M[][] For the given M[R][C] in above example, constructed S[R][C] would be:
0 1 0 1 1 0
1 1 1 1 2 0
1 0 1 2 2 0
0 1 1 2 3 0
1 0 0 0 1 0
The value of maximum entry in above matrix is 3 and coordinates of the entry are (4, 3). Using the maximum value and its coordinates, we can find out the required sub-matrix. #include #define bool int #define R 6 #define C 5 void printMaxSubSquare(bool M[R][C]) {
P a g e | 70 int i,j; int S[R][C]; int max_of_s, max_i, max_j; /* Set first column of S[][]*/ for(i = 0; i < R; i++) S[i][0] = M[i][0]; /* Set first row of S[][]*/ for(j = 0; j < C; j++) S[0][j] = M[0][j]; /* Construct other entries of S[][]*/ for(i = 1; i < R; i++) { for(j = 1; j < C; j++) { if(M[i][j] == 1) S[i][j] = min(S[i][j-1], S[i-1][j], S[i-1][j-1]) + 1; else S[i][j] = 0; } } /* Find the maximum entry, and indexes of maximum entry in S[][] */ max_of_s = S[0][0]; max_i = 0; max_j = 0; for(i = 0; i < R; i++) { for(j = 0; j < C; j++) { if(max_of_s < S[i][j]) { max_of_s = S[i][j]; max_i = i; max_j = j; } } } printf("\n Maximum size sub-matrix is: \n"); for(i = max_i; i > max_i - max_of_s; i--) { for(j = max_j; j > max_j - max_of_s; j--) { printf("%d ", M[i][j]); } printf("\n"); } } /* UTILITY FUNCTIONS */ /* Function to get minimum of three values */ int min(int a, int b, int c) { int m = a; if(m > b) m = b;
P a g e | 71 if(m > c) m = c; return m; } /* Driver function to test above functions */ int main() { bool M[R][C] = {{0, 1, 1, 0, 1}, {1, 1, 0, 1, 0}, {0, 1, 1, 1, 0}, {1, 1, 1, 1, 0}, {1, 1, 1, 1, 1}, {0, 0, 0, 0, 0}}; printMaxSubSquare(M); getchar(); }
Time Complexity: O(m*n) where m is number of rows and n is number of columns in the given matrix. Auxiliary Space: O(m*n) where m is number of rows and n is number of columns in the given matrix. Algorithmic Paradigm: Dynamic Programming
Maximum difference between two elements April 10, 2010
Given an array arr[] of integers, find out the difference between any two elements such that larger element appears after the smaller number in arr[]. Examples: If array is [2, 3, 10, 6, 4, 8, 1] then returned value should be 8 (Diff between 10 and 2). If array is [ 7, 9, 5, 6, 3, 2 ] then returned value should be 2 (Diff between 7 and 9) Method 1 (Simple) Use two loops. In the outer loop, pick elements one by one and in the inner loop calculate the difference of the picked element with every other element in the array and compare the difference with the maximum difference calculated so far. #include /* The function assumes that there are at least two elements in array. The function return s a negative value if the array is sorted in decreasing order. Returns 0 if elements are equal */ int maxDiff(int arr[], int arr_size)
P a g e | 72 { int max_diff = arr[1] - arr[0]; int i, j; for(i = 0; i < arr_size; i++) { for(j = i+1; j < arr_size; j++) { if(arr[j] - arr[i] > max_diff) max_diff = arr[j] - arr[i]; } } return max_diff; } /* Driver program to test above function */ int main() { int arr[] = {1, 2, 90, 10, 110}; printf("Maximum difference is %d", maxDiff(arr, 5)); getchar(); return 0; }
Time Complexity: O(n^2) Auxiliary Space: O(1) Method 2 (Tricky and Efficient) In this method, instead of taking difference of the picked element with every other element, we take the difference with the minimum element found so far. So we need to keep track of 2 things: 1) Maximum difference found so far (max_diff). 2) Minimum number visited so far (min_element). #include /* The function assumes that there are at least two elements in array. The function return s a negative value if the array is sorted in decreasing order. Returns 0 if elements are equal */ int maxDiff(int arr[], int arr_size) { int max_diff = arr[1] - arr[0]; int min_element = arr[0]; int i; for(i = 1; i < arr_size; i++) { if(arr[i] - min_element > max_diff) max_diff = arr[i] - min_element; if(arr[i] < min_element) min_element = arr[i]; } return max_diff; }
P a g e | 73
/* Driver program to test above function */ int main() { int arr[] = {1, 2, 6, 80, 100}; int size = sizeof(arr)/sizeof(arr[0]); printf("Maximum difference is %d", maxDiff(arr, size)); getchar(); return 0; }
Time Complexity: O(n) Auxiliary Space: O(1) Method 3 (Another Tricky Solution) First find the difference between the adjacent elements of the array and store all differences in an auxiliary array diff[] of size n-1. Now this problems turns into finding the maximum sum subarray of this difference array. Thanks to Shubham Mittal for suggesting this solution. #include int maxDiff(int arr[], int n) { // Create a diff array of size n-1. The array will hold // the difference of adjacent elements int diff[n-1]; for(int i=0; i < n-1; i++) diff[i] = arr[i+1] - arr[i]; // Now find the maximum sum subarray in diff array int max_diff = diff[0]; for(int i=1; i 0) diff[i] += diff[i-1]; if(max_diff < diff[i]) max_diff = diff[i]; } return max_diff; } /* Driver program to test above function */ int main() { int arr[] = {80, 2, 6, 3, 100}; int size = sizeof(arr)/sizeof(arr[0]); printf("Maximum difference is %d", maxDiff(arr, size)); return 0; }
Output:
P a g e | 74
98 This method is also O(n) time complexity solution, but it requires O(n) extra space Time Complexity: O(n) Auxiliary Space: O(n) We can modify the above method to work in O(1) extra space. Instead of creating an auxiliary array, we can calculate diff and max sum in same loop. Following is the space optimized version. int maxDiff (int arr[], int n) { // Initialize diff, current sum and max sum int diff = arr[1]-arr[0]; int curr_sum = diff; int max_sum = curr_sum; for(int i=1; i 0) curr_sum += diff; else curr_sum = diff; // Update max sum, if needed if(curr_sum > max_sum) max_sum = curr_sum; } return max_sum; }
Time Complexity: O(n) Auxiliary Space: O(1)
Union and Intersection of two sorted arrays April 27, 2010
For example, if the input arrays are: arr1[] = {1, 3, 4, 5, 7} arr2[] = {2, 3, 5, 6} Then your program should print Union as {1, 2, 3, 4, 5, 6, 7} and Intersection as {3, 5}.
P a g e | 75
Algorithm Union(arr1[], arr2[]): For union of two arrays, follow the following merge procedure. 1) Use two index variables i and j, initial values i = 0, j = 0 2) If arr1[i] is smaller than arr2[j] then print arr1[i] and increment i. 3) If arr1[i] is greater than arr2[j] then print arr2[j] and increment j. 4) If both are same then print any of them and increment both i and j. 5) Print remaining elements of the larger array. #include /* Function prints union of arr1[] and arr2[] m is the number of elements in arr1[] n is the number of elements in arr2[] */ int printUnion(int arr1[], int arr2[], int m, int n) { int i = 0, j = 0; while(i < m && j < n) { if(arr1[i] < arr2[j]) printf(" %d ", arr1[i++]); elseif(arr2[j] < arr1[i]) printf(" %d ", arr2[j++]); else { printf(" %d ", arr2[j++]); i++; } } /* Print remaining elements of the larger array */ while(i < m) printf(" %d ", arr1[i++]); while(j < n) printf(" %d ", arr2[j++]); } /* Driver program to test above function */ int main() { int arr1[] = {1, 2, 4, 5, 6}; int arr2[] = {2, 3, 5, 7}; int m = sizeof(arr1)/sizeof(arr1[0]); int n = sizeof(arr2)/sizeof(arr2[0]); printUnion(arr1, arr2, m, n); getchar(); return 0; }
Time Complexity: O(m+n) Algorithm Intersection(arr1[], arr2[]): For Intersection of two arrays, print the element only if the element is present in both
P a g e | 76
arrays. 1) Use two index variables i and j, initial values i = 0, j = 0 2) If arr1[i] is smaller than arr2[j] then increment i. 3) If arr1[i] is greater than arr2[j] then increment j. 4) If both are same then print any of them and increment both i and j. #include /* Function prints Intersection of arr1[] and arr2[] m is the number of elements in arr1[] n is the number of elements in arr2[] */ int printIntersection(int arr1[], int arr2[], int m, int n) { int i = 0, j = 0; while(i < m && j < n) { if(arr1[i] < arr2[j]) i++; elseif(arr2[j] < arr1[i]) j++; else/* if arr1[i] == arr2[j] */ { printf(" %d ", arr2[j++]); i++; } } } /* Driver program to test above function */ int main() { int arr1[] = {1, 2, 4, 5, 6}; int arr2[] = {2, 3, 5, 7}; int m = sizeof(arr1)/sizeof(arr1[0]); int n = sizeof(arr2)/sizeof(arr2[0]); printIntersection(arr1, arr2, m, n); getchar(); return 0; }
Time Complexity: O(m+n)
Floor and Ceiling in a sorted array May 11, 2010
Given a sorted array and a value x, the ceiling of x is the smallest element in array greater than or equal to x, and the floor is the greatest element smaller than or equal to x. Assume than the array is sorted in non-decreasing order. Write efficient functions to find floor and ceiling of x.
P a g e | 77
For 12, For For For For
example, let the input array be {1, 2, 8, 10, 10, 19} x = 0: floor doesn't exist in array, ceil = 1 x = 1: floor = 1, ceil = 1 x = 5: floor = 2, ceil = 8 x = 20: floor = 19, ceil doesn't exist in array
In below methods, we have implemented only ceiling search functions. Floor search can be implemented in the same way. Method 1 (Linear Search) Algorithm to search ceiling of x: 1) If x is smaller than or equal to the first element in array then return 0(index of first element) 2) Else Linearly search for an index i such that x lies between arr[i] and arr[i+1]. 3) If we do not find an index i in step 2, then return -1 #include /* Function to get index of ceiling of x in arr[low..high] */ int ceilSearch(int arr[], int low, int high, int x) { int i; /* If x is smaller than or equal to first element, then return the first element */ if(x = x) return i+1; } /* If we reach here then x is greater than the last element of the array, return -1 in this case */ return -1; }
/* Driver program to check above functions */ int main()
P a g e | 78 { int arr[] = {1, 2, 8, 10, 10, 12, 19}; int n = sizeof(arr)/sizeof(arr[0]); int x = 3; int index = ceilSearch(arr, 0, n-1, x); if(index == -1) printf("Ceiling of %d doesn't exist in array ", x); else printf("ceiling of %d is %d", x, arr[index]); getchar(); return 0; }
Time Complexity: O(n) Method 2 (Binary Search) Instead of using linear search, binary search is used here to find out the index. Binary search reduces time complexity to O(Logn). #include /* Function to get index of ceiling of x in arr[low..high]*/ int ceilSearch(int arr[], int low, int high, int x) { int mid; /* If x is smaller than or equal to the first element, then return the first element */ if(x arr[high]) return -1;
-1 */
/* get the index of middle element of arr[low..high]*/ mid = (low + high)/2; /* low + (high - low)/2 */ /* If x is same as middle element, then return if(arr[mid] == x) return mid;
mid */
/* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x or ceiling lies in arr[mid+1...high] */ elseif(arr[mid] < x) { if(mid + 1 arr[mid-1]) return mid; else return ceilSearch(arr, low, mid - 1, x); } } /* Driver program to check above functions */ int main() { int arr[] = {1, 2, 8, 10, 10, 12, 19}; int n = sizeof(arr)/sizeof(arr[0]); int x = 20; int index = ceilSearch(arr, 0, n-1, x); if(index == -1) printf("Ceiling of %d doesn't exist in array ", x); else printf("ceiling of %d is %d", x, arr[index]); getchar(); return 0; }
Time Complexity: O(Logn)
A Product Array Puzzle May 18, 2010
Given an array arr[] of n integers, construct a Product Array prod[] (of same size) such that prod[i] is equal to the product of all the elements of arr[] except arr[i]. Solve it without division operator and in O(n). Example: arr[] = {10, 3, 5, 6, 2} prod[] = {180, 600, 360, 300, 900} Algorithm: 1) Construct a temporary array left[] such that left[i] contains product of all elements on left of arr[i] excluding arr[i]. 2) Construct another temporary array right[] such that right[i] contains product of all elements on on right of arr[i] excluding arr[i]. 3) To get prod[], multiply left[] and right[]. Implementation: #include #include
P a g e | 80
/* Function to print product array for a given array arr[] of size n */ void productArray(int arr[], int n) { /* Allocate memory for temporary arrays left[] and right[] */ int *left = (int *)malloc(sizeof(int )*n); int *right = (int *)malloc(sizeof(int )*n); /* Allocate memory for the product array */ int *prod = (int *)malloc(sizeof(int )*n); int i, j; /* Left most element of left array is always 1 */ left[0] = 1; /* Rightmost most element of right array is always 1 */ right[n-1] = 1; /* Construct the left array */ for(i = 1; i < n; i++) left[i] = arr[i-1]*left[i-1]; /* Construct the right array */ for(j = n-2; j >=0; j--) right[j] = arr[j+1]*right[j+1]; /* Construct the product array using left[] and right[] */ for(i=0; i= n - i - 1) jumps[i] = 1;
// Otherwise, to find out the minimum number of jumps needed // to reach arr[n-1], check all the points reachable from here // and jumps[] value for those points else
P a g e | 204 { min = INT_MAX;
// initialize min value
// following loop checks with all reachable points and // takes the minimum for(j = i+1; j < n && j jumps[j]) min = jumps[j]; }
// Handle overflow if(min != INT_MAX) jumps[i] = min + 1; else jumps[i] = min; // or INT_MAX } }
return jumps[0]; }
Time Complexity: O(n^2) in worst case.
Implement two stacks in an array April 9, 2012
Create a data structure twoStacks that represents two stacks. Implementation of twoStacks should use only one array, i.e., both stacks should use the same array for storing elements. Following functions must be supported by twoStacks.
P a g e | 205
push1(int x) –> pushes x to first stack push2(int x) –> pushes x to second stack pop1() –> pops an element from first stack and return the popped element pop2() –> pops an element from second stack and return the popped element Implementation of twoStack should be space efficient. Method 1 (Divide the space in two halves) A simple way to implement two stacks is two divide the array in two halves and assign the half half space to two stacks, i.e., use arr[0] to arr[n/2] for stack1, and arr[n/2+1] to arr[n-1] for stack2 where arr[] is the array to be used to implement two stacks and size of array be n. The problem with this method is inefficient use of array space. A stack push operation may result in stack overflow even if there is space available in arr[]. For example, say the array size is 6 and we push 3 elements to stack1 and do not push anything to second stack2. When we push 4th element to stack1, there will be overflow even if we have space for 3 more elements in array. Method 2 (A space efficient implementation) This method efficiently utilizes the available space. It doesn‟t cause an overflow if there is space available in arr[]. The idea is to start two stacks from two extreme corners of arr[]. stack1 starts from the leftmost element, the first element in stack1 is pushed at index 0. The stack2 starts from the rightmost corner, the first element in stack2 is pushed at index (n-1). Both stacks grow (or shrink) in opposite direction. To check for overflow, all we need to check is for space between top elements of both stacks. This check is highlighted in the below code. #include #include
usingnamespacestd;
classtwoStacks {
P a g e | 206 int *arr; int size; int top1, top2; public: twoStacks(int n)
// constructor
{ size = n; arr = newint[n]; top1 = -1; top2 = size; }
// Method to push an element x to stack1 void push1(int x) { // There is at least one empty space for new element if(top1 < top2 - 1) { top1++; arr[top1] = x; } else { cout Ending index
*/ void quickSort(int A[], int si, int ei) { int pi;
/* Partitioning index */
if(si < ei) { pi = partition(A, si, ei); quickSort(A, si, pi - 1); quickSort(A, pi + 1, ei); } }
/* Driver program to test above function */ int main() { int A[] = {1, 4, 45, 6, 10, 8}; int sum = 22;
P a g e | 230 int arr_size = sizeof(A)/sizeof(A[0]);
find3Numbers(A, arr_size, sum);
getchar(); return 0; }
Output:
Triplet is 4, 8, 10 Time Complexity: O(n^2) Note that there can be more than one triplet with the given sum. We can easily modify the above methods to print all triplets.
Find the smallest positive number missing from an unsorted array May 22, 2012
You are given an unsorted array with both positive and negative elements. You have to find the smallest positive number missing from the array in O(n) time using constant extra space. You can modify the original array. Examples
Input: {2, 3, 7, 6, 8, -1, -10, 15} Output: 1 Input: { 2, 3, -7, 6, 8, 1, -10, 15 } Output: 4 Input: {1, 1, 0, -1, -2} Output: 2 Source: To find the smallest positive no missing from an unsorted array
P a g e | 231
A naive method to solve this problem is to search all positive integers, starting from 1 in the given array. We may have to search at most n+1 numbers in the given array. So this solution takes O(n^2) in worst case. We can use sorting to solve it in lesser time complexity. We can sort the array in O(nLogn) time. Once the array is sorted, then all we need to do is a linear scan of the array. So this approach takes O(nLogn + n) time which is O(nLogn). We can also use hashing. We can build a hash table of all positive elements in the given array. Once the hash table is built. We can look in the hash table for all positive integers, starting from 1. As soon as we find a number which is not there in hash table, we return it. 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 this post. We use array elements as index. To mark presence of an element x, we change the value at the index x to negative. But this approach doesn‟t work if there are non-positive (-ve and 0) numbers. So we segregate positive from negative numbers as first step and then apply the approach. Following is the two step algorithm. 1) Segregate positive numbers from others i.e., move all non-positive numbers to left side. In the following code, segregate() function does this part. 2) Now we can ignore non-positive elements and consider only the part of array which contains all positive elements. We traverse the array containing all positive numbers and to mark presence of an element x, we change the sign of value at index x to negative. We traverse the array again and print the first index which has positive value. In the following code, findMissingPositive() function does this part. Note that in findMissingPositive, we have subtracted 1 from the values as indexes start from 0 in C. /* Program to find the smallest positive missing number */ #include #include
/* Utility to swap to int egers */
P a g e | 232 void swap(int *a, int *b) { int temp; temp = *a; *a
= *b;
*b
= temp;
}
/* Utility function that puts all non-positive (0 and negative) numbers on left side of arr[] and return
count of such numbers */
int segregate (int arr[], int size) { int j = 0, i; for(i = 0; i < size; i++) { if(arr[i] 0) arr[abs(arr[i]) - 1] = -arr[abs(arr[i]) - 1]; }
// Return the first index value at which is positive for(i = 0; i < size; i++) if(arr[i] > 0) return i+1;
// 1 is added becuase indexes start from 0
return size+1; }
/* Find the smallest positive missing number in an array that contains both positive and negative int egers */ int findMissing(int arr[], int size) { // First separate positive and negative numbers int shift = segregate (arr, size);
// Shift the array and call findMissingPositive for // positive part
P a g e | 234 return findMissingPositive(arr+shift, size-shift); }
int main() { int arr[] = {0, 10, 2, -10, -20}; int arr_size = sizeof(arr)/sizeof(arr[0]); int missing = findMissing(arr, arr_size); printf("The smallest positive missing number is %d ", missing); getchar(); return 0; }
Output:
The smallest positive missing number is 1 Note that this method modifies the original array. We can change the sign of elements in the segregated array to get the same set of elements back. But we still loose the order of elements. If we want to keep the original array as it was, then we can create a copy of the array and run this approach on the temp array.
Find the two numbers with odd occurrences in an unsorted array May 24, 2012
Given an unsorted array that contains even number of occurrences for all numbers except two numbers. Find the two numbers which have odd occurrences in O(n) time complexity and O(1) extra space. Examples:
Input: {12, 23, 34, 12, 12, 23, 12, 45} Output: 34 and 45 Input: {4, 4, 100, 5000, 4, 4, 4, 4, 100, 100}
P a g e | 235
Output: 100 and 5000 Input: {10, 20} Output: 10 and 20 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 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
P a g e | 236
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. // Program to find the two odd occurring elements #include
/* Prints two numbers that occur odd number of times. The function assumes that the array size is at least 2 and there are exactly two numbers occurring odd number of times. */ void printTwoOdd(int arr[], int size) { int xor2 = arr[0]; /* Will hold XOR of two odd occurring elements */ int set_bit_no;
/* Will have only single set bit of xor2 */
int i; int n = size - 2; int x = 0, y = 0;
/* Get the xor of all elements in arr[]. The xor will basically be xor of two odd occurring elements */ for(i = 1; i < size; i++) xor2 = xor2 ^ arr[i];
/* Get one set bit in the xor2. We get rightmost set bit
P a g e | 237 in the following line as it is easy to get */ set_bit_no = xor2 & ~(xor2-1);
/* Now divide elements in two sets: 1) The elements having the corresponding bit as 1. 2) The elements having the corresponding bit as 0.
*/
for(i = 0; i < size; i++) { /* XOR of first set is finally going to hold one odd occurring number x */ if(arr[i] & set_bit_no) x = x ^ arr[i];
/* XOR of second set is finally going to hold the other odd occurring number y */ else y = y ^ arr[i]; }
printf("\n The two ODD elements are %d & %d ", x, y); }
/* Driver program to test above function */ int main() { int arr[] = {4, 2, 4, 5, 2, 3, 3, 1}; int arr_size = sizeof(arr)/sizeof(arr[0]); printTwoOdd(arr, arr_size); getchar();
P a g e | 238 return 0; }
Output:
The two ODD elements are 5 & 1 Time Complexity: O(n) Auxiliary Space: O(1)
The Celebrity Problem June 3, 2012
Another classical problem. In a party of N people, only one person is known to everyone. Such a person may be present in the party, if yes, (s)he doesn’t know anyone in the party. We can only ask questions like “does A know B? “. Find the stranger (celebrity) in minimum number of questions. We can describe the problem input as an array of numbers/characters representing persons in the party. We also have a hypothetical function HaveAcquaintance(A, B) which returns true if A knows B, falseotherwise. How can we solve the problem, try yourself first. We measure the complexity in terms of calls made to HaveAcquaintance(). Graph: We can model the solution using graphs. Initialize indegree and outdegree of every vertex as 0. If A knows B, draw a directed edge from A to B, increase indegree of B and outdegree of A by 1. Construct all possible edges of the graph for every possible pair [i, j]. We have NC2 pairs. If celebrity is present in the party, we will have one sink node in the graph with outdegree of zero, and indegree of N-1. We can find the sink node in (N) time, but the overall complexity is O(N2) as we need to construct the graph first. Recursion:
P a g e | 239
We can decompose the problem into combination of smaller instances. Say, if we know celebrity of N-1 persons, can we extend the solution to N? We have two possibilities, Celebrity(N-1) may know N, or N already knew Celebrity(N-1). In the former case, N will be celebrity if N doesn‟t know anyone else. In the later case we need to check that Celebrity(N-1) doesn‟t know N. Solve the problem of smaller instance during divide step. On the way back, we may find a celebrity from the smaller instance. During combine stage, check whether the returned celebrity is known to everyone and he doesn‟t know anyone. The recurrence of the recursive decomposition is, T(N) = T(N-1) + O(N) T(N) = O(N2). You may try Writing pseudo code to check your recursion skills. Using Stack: The graph construction takes O(N2) time, it is similar to brute force search. In case of recursion, we reduce the problem instance by not more than one, and also combine step may examine M-1 persons (M – instance size). We have following observation based on elimination technique (Refer Polya’s How to Solve It book).
If A knows B, then A can‟t be celebrity. Discard A, and B may be celebrity. If A doesn‟t know B, then B can‟t be celebrity. Discard B, and A may be celebrity. Repeat above two steps till we left with only one person. Ensure the remained person is celebrity. (Why do we need this step?)
We can use stack to verity celebrity. 1. Push all the celebrities into a stack. 2. Pop off top two persons from the stack, discard one person based on return status ofHaveAcquaintance(A, B). 3. Push the remained person onto stack. 4. Repeat step 2 and 3 until only one person remains in the stack. 5. Check the remained person in stack doesn‟t have acquaintance with anyone else.
P a g e | 240
We will discard N elements utmost (Why?). If the celebrity is present in the party, we will callHaveAcquaintance() 3(N-1) times. Here is code using stack. #include #include usingnamespacestd; // Max # of persons in the party #define N 8 // Celebrities identified with numbers from 0 through size-1 int size = 4; // Person with 2 is celebrity bool MATRIX[N][N] = {{0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}, {0, 0, 1, 0}}; bool HaveAcquiantance(int a, int b) { return MATRIX[a][b]; } int CelebrityUsingStack(int size) { // Handle trivial case of size = 2 list stack; // Careful about naming int i; int C; // Celebrity i = 0; while( i < size ) { stack.push_back(i); i = i + 1; } int A = stack.back(); stack.pop_back(); int B = stack.back(); stack.pop_back(); while( stack.size() != 1 ) { if( HaveAcquiantance(A, B) ) { A = stack.back(); stack.pop_back(); } else { B = stack.back(); stack.pop_back(); } } // Potential candidate? C = stack.back(); stack.pop_back();
P a g e | 241 // Last candidate was not examined, it leads one excess comparison (optimise) if( HaveAcquiantance(C, B) ) C = B; if( HaveAcquiantance(C, A) ) C = A; // I know these are redundant, // we can simply check i against C i = 0; while( i < size ) { if( C != i ) stack.push_back(i); i = i + 1; } while( !stack.empty() ) { i = stack.back(); stack.pop_back(); // C must not know i if( HaveAcquiantance(C, i) ) return -1; // i must know C if( !HaveAcquiantance(i, C) ) return -1; } return C; } int main() { int id = CelebrityUsingStack(size); id == -1 ? cout 0 | L1 0->0->1->0 | L2 0->0->1->0 | L3 0->0->1->0 The function HaveAcquanintance(i, j) will search in the list for j-th node in the ith level. Out goal is to minimize calls to HaveAcquanintance function. Exercises: 1. Write code to find celebrity. Don‟t use any data structures like graphs, stack, etc… you have access to Nand HaveAcquaintance(int, int) only. 2. Implement the algorithm using Queues. What is your observation? Compare your solution with Finding Maximum and Minimum in an array and Tournament Tree. What are minimum number of comparisons do we need (optimal number of calls to HaveAcquaintance())?
Dynamic Programming | Set 15 (Longest Bitonic Subsequence) June 6, 2012
Given an array arr[0 ... n-1] containing n positive integers, a subsequence of arr[] is called Bitonic if it is first increasing, then decreasing. Write a function that takes an array as argument and returns the length of the longest bitonic subsequence.
P a g e | 243
A sequence, sorted in increasing order is considered Bitonic with the decreasing part as empty. Similarly, decreasing order sequence is considered Bitonic with the increasing part as empty. Examples:
Input arr[] = {1, 11, 2, 10, 4, 5, 2, 1}; Output: 6 (A Longest Bitonic Subsequence of length 6 is 1, 2, 10, 4, 2, 1) Input arr[] = {12, 11, 40, 5, 3, 1} Output: 5 (A Longest Bitonic Subsequence of length 5 is 12, 11, 5, 3, 1) Input arr[] = {80, 60, 30, 40, 20, 10} Output: 5 (A Longest Bitonic Subsequence of length 5 is 80, 60, 30, 20, 10) Source: Microsoft Interview Question Solution This problem is a variation of standard Longest Increasing Subsequence (LIS) problem. Let the input array be arr[] of length n. We need to construct two arrays lis[] and lds[] using Dynamic Programming solution ofLIS problem. lis[i] stores the length of the Longest Increasing subsequence ending with arr[i]. lds[i] stores the length of the longest Decreasing subsequence starting from arr[i]. Finally, we need to return the max value of lis[i] + lds[i] – 1 where i is from 0 to n-1. Following is C++ implementation of the above Dynamic Programming solution. /* Dynamic Programming implementation of longest bitonic subsequence problem */ #include #include
/* lbs() return s the length of the Longest Bitonic Subsequence in arr[] of size n. The function mainly creates two temporary arrays
P a g e | 244 lis[] and lds[] and return s the maximum lis[i] + lds[i] - 1.
lis[i] ==> Longest Increasing subsequence ending with arr[i] lds[i] ==> Longest decreasing subsequence starting with arr[i] */ int lbs( int arr[], int n ) { int i, j;
/* Allocate memory for LIS[] and initialize LIS values as 1 for all indexes */ int *lis = newint[n]; for( i = 0; i < n; i++ ) lis[i] = 1;
/* Compute LIS values from left to right */ for( i = 1; i < n; i++ ) for( j = 0; j < i; j++ ) if( arr[i] > arr[j] && lis[i] < lis[j] + 1) lis[i] = lis[j] + 1;
/* Allocate memory for lds and initialize LDS values for all indexes */ int *lds = newint[n]; for( i = 0; i < n; i++ ) lds[i] = 1;
/* Compute LDS values from right to left */
P a g e | 245 for( i = n-2; i >= 0; i-- ) for( j = n-1; j > i; j-- ) if( arr[i] > arr[j] && lds[i] < lds[j] + 1) lds[i] = lds[j] + 1;
/* Return the maximum value of lis[i] + lds[i] - 1*/ int max = lis[0] + lds[0] - 1; for(i = 1; i < n; i++) if(lis[i] + lds[i] - 1 > max) max = lis[i] + lds[i] - 1; return max; }
/* Driver program to test above function */ int main() { int arr[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}; int n = sizeof(arr)/sizeof(arr[0]); printf("Length of LBS is %d\n", lbs( arr, n ) );
getchar(); return 0; }
Output:
Length of LBS is 7 Time Complexity: O(n^2) Auxiliary Space: O(n)
P a g e | 246
Find a sorted subsequence of size 3 in linear time June 8, 2012
Given an array of n integers, find the 3 elements such that a[i] < a[j] < a[k] and i < j < k in 0(n) time. If there are multiple such triplets, then print any one of them. Examples:
Input: arr[] = {12, 11, 10, 5, 6, 2, 30} Output: 5, 6, 30 Input: arr[] = {1, 2, 3, 4} Output: 1, 2, 3 OR 1, 2, 4 OR 2, 3, 4 Input: arr[] = {4, 3, 2, 1} Output: No such triplet Source: Amazon Interview Question Hint: Use Auxiliary Space Solution: 1) Create an auxiliary array smaller[0..n-1]. smaller[i] should store the index of a number which is smaller than arr[i] and is on left side of arr[i]. smaller[i] should contain -1 if there is no such element. 2) Create another auxiliary array greater[0..n-1]. greater[i] should store the index of a number which is greater than arr[i] and is on right side of arr[i]. greater[i] should contain -1 if there is no such element. 3) Finally traverse both smaller[] and greater[] and find the index i for which both smaller[i] and greater[i] are not -1.
#include // A function to fund a sorted subsequence of size 3 void find3Numbers(int arr[], int n) { int max = n-1; //Index of maximum element from right side
P a g e | 247
int min = 0; //Index of minimum element from left side int i; // Create an array that will store index of a smaller // element on left side. If there is no smaller element // on left side, then smaller[i] will be -1. int *smaller = new int[n]; smaller[0] = -1; // first entry will always be -1 for (i = 1; i < n; i++) { if (arr[i] = 0; i--) { if (arr[i] >= arr[max]) { max = i; greater[i] = -1; } else greater[i] = max; }
P a g e | 248
// Now find a number which has both a greater number on // right side and smaller number on left side for (i = 0; i < n; i++) { if (smaller[i] != -1 && greater[i] != -1) { printf("%d %d %d", arr[smaller[i]], arr[i], arr[greater[i]]); return; } } // If we reach number, then there are no such 3 numbers printf("No such triplet found"); // Free the dynamically alloced memory to avoid memory leak delete [] smaller; delete [] greater; return; } // Driver program to test above function int main() { int arr[] = {12, 11, 10, 5, 6, 2, 30}; int n = sizeof(arr)/sizeof(arr[0]); find3Numbers(arr, n); return 0; } Output:
P a g e | 249
5 6 30 Time Complexity: O(n) Auxliary Space: O(n) Source: How to find 3 numbers in increasing order and increasing indices in an array in linear time Exercise: 1. Find a subsequence of size 3 such that arr[i] < arr[j] > arr[k]. 2. Find a sorted subsequence of size 4 in linear time
Largest subarray with equal number of 0s and 1s June 26, 2012
Given an array containing only 0s and 1s, find the largest subarray which contain equal no of 0s and 1s. Expected time complexity is O(n). Examples:
Input: arr[] = {1, 0, 1, 1, 1, 0, 0} Output: 1 to 6 (Starting and Ending indexes of output subarray) Input: arr[] = {1, 1, 1, 1} Output: No such subarray Input: arr[] = {0, 0, 1, 1, 0} Output: 0 to 3 Or 1 to 4 Source: Largest subarray with equal number of 0s and 1s Method 1 (Simple) A simple method is to use two nested loops. The outer loop picks a starting point i. The inner loop considers all subarrays starting from i. If size of a subarray is greater than maximum size so far, then update the maximum size. In the below code, 0s are considered as -1 and sum of all values from i to j is calculated. If sum becomes 0, then size of this subarray is compared with largest size so far.
P a g e | 250 // A simple program to find the largest subarray with equal number of 0s and 1s #include
// This function Prints the starting and ending indexes of the largest subarray // with equal number of 0s and 1s. Also return s the size of such subarray. int findSubArray(int arr[], int n) { int sum = 0; int maxsize = -1, startindex;
// Pick a starting point as i for(int i = 0; i < n-1; i++) { sum = (arr[i] == 0)? -1 : 1;
// Consider all subarrays starting from i for(int j = i+1; j < n; j++) { (arr[j] == 0)? sum += -1: sum += 1;
// If this is a 0 sum subarray, then compare it with // maximum size subarray calculated so far if(sum == 0 && maxsize < j-i+1) { maxsize = j - i + 1; startindex = i; }
P a g e | 251 } } if( maxsize == -1 ) printf("No such subarray"); else printf("%d to %d", startindex, startindex+maxsize-1);
return maxsize; }
/* Driver program to test above functions*/ int main() { int arr[] =
{1, 0, 0, 1, 0, 1, 1};
int size = sizeof(arr)/sizeof(arr[0]);
findSubArray(arr, size); return 0; }
Output:
0 to 5 Time Complexity: O(n^2) Auxiliary Space: O(1)
Method 2 (Tricky) Following is a solution that uses O(n) extra space and solves the problem in O(n) time complexity.
P a g e | 252
Let input array be arr[] of size n and maxsize be the size of output subarray. 1) Consider all 0 values as -1. The problem now reduces to find out the maximum length subarray with sum = 0. 2) Create a temporary array sumleft[] of size n. Store the sum of all elements from arr[0] to arr[i] in sumleft[i]. This can be done in O(n) time. 3) There are two cases, the output subarray may start from 0th index or may start from some other index. We will return the max of the values obtained by two cases. 4) To find the maximum length subarray starting from 0th index, scan the sumleft[] and find the maximum i where sumleft[i] = 0. 5) Now, we need to find the subarray where subarray sum is 0 and start index is not 0. This problem is equivalent to finding two indexes i & j in sumleft[] such that sumleft[i] = sumleft[j] and j-i is maximum. To solve this, we can create a hash table with size = max-min+1 where min is the minimum value in the sumleft[] and max is the maximum value in the sumleft[]. The idea is to hash the leftmost occurrences of all different values in sumleft[]. The size of hash is chosen as max-min+1 because there can be these many different possible values in sumleft[]. Initialize all values in hash as -1 6) To fill and use hash[], traverse sumleft[] from 0 to n-1. If a value is not present in hash[], then store its index in hash. If the value is present, then calculate the difference of current index of sumleft[] and previously stored value in hash[]. If this difference is more than maxsize, then update the maxsize. 7) To handle corner cases (all 1s and all 0s), we initialize maxsize as -1. If the maxsize remains -1, then print there is no such subarray. // A O(n) program to find the largest subarray with equal number of 0s and 1s #include #include
// A utility function to get maximum of two int egers int max(int a, int b) { return a>b? a: b; }
// This function Prints the starting and ending indexes of the largest subarray // with equal number of 0s and 1s. Also return s the size of such subarray. int findSubArray(int arr[], int n)
P a g e | 253 { int maxsize = -1, startindex;
// variables to store result values
// Create an auxiliary array sunmleft[]. sumleft[i] will be sum of array // elements from arr[0] to arr[i] int sumleft[n]; int min, max; // For min and max values in sumleft[] int i;
// Fill sumleft array and get min and max values in it. // Consider 0 values in arr[] as -1 sumleft[0] = ((arr[0] == 0)? -1: 1); min = arr[0]; max = arr[0]; for(i=1; i max) max = sumleft[i]; }
// Now calculate the max value of j - i such that sumleft[i] = sumleft[j]. // The idea is to create a hash table to store indexes of all visited values. // If you see a value again, that it is a case of sumleft[i] = sumleft[j]. Check // if this j-i is more than maxsize. // The optimum size of hash will be max-min+1 as these many different
P a g e | 254 values // of sumleft[i] are possible. Since we use optimum size, we need to shift // all values in sumleft[] by min before using them as an index in hash[]. int hash[max-min+1];
// Initialize hash table for(i=0; i sum) return isSubsetSum (arr, n-1, sum);
/* else, check if sum can be obtained by any of the following (a) including the last element (b) excluding the last element */ return isSubsetSum (arr, n-1, sum) || isSubsetSum (arr, n-1, sum-arr[n-1]); }
// Returns true if arr[] can be partitioned in two subsets of // equal sum, otherwise false bool findPartiion (int arr[], int n) { // Calculate sum of the elements in array int sum = 0;
P a g e | 258 for(int i = 0; i < n; i++) sum += arr[i];
// If sum is odd, there cannot be two subsets with equal sum if(sum%2 != 0) return false;
// Find if there is subset with sum equal to half of total sum return isSubsetSum (arr, n, sum/2); }
// Driver program to test above function int main() { int arr[] = {3, 1, 5, 9, 12}; int n = sizeof(arr)/sizeof(arr[0]); if(findPartiion(arr, n) == true) printf("Can be divided int o two subsets of equal sum"); else printf("Can not be divided int o two subsets of equal sum"); getchar(); return 0; }
Output:
Can be divided into two subsets of equal sum Time Complexity: O(2^n) In worst case, this solution tries two possibilities (whether to include or exclude) for every element.
P a g e | 259
Dynamic Programming Solution The problem can be solved using dynamic programming when the sum of the elements is not too big. We can create a 2D array part[][] of size (sum/2)*(n+1). And we can construct the solution in bottom up manner such that every filled entry has following property
part[i][j] = true if a subset of {arr[0], arr[1], ..arr[j-1]} has sum equal to i, otherwise false // A Dynamic Programming solution to partition problem #include
// Returns true if arr[] can be partitioned in two subsets of // equal sum, otherwise false bool findPartiion (int arr[], int n) { int sum = 0; int i, j;
// Caculcate sun of all elements for(i = 0; i < n; i++) sum += arr[i];
if(sum%2 != 0) return false;
bool part[sum/2+1][n+1];
// initialize top row as true
P a g e | 260 for(i = 0; i = 0 && A[j] > key) { A[j+1] = A[j]; j = j-1; } A[j+1] = key; } }
The inner loop will run at most k times. To move every element to its correct place, at most k elements need to be moved. So overall complexity will be O(nk) We can sort such arrays more efficiently with the help of Heap data structure. Following is the detailed process that uses Heap. 1) Create a Min Heap of size k+1 with first k+1 elements. This will take O(k) time (See this GFact) 2) One by one remove min element from heap, put it in result array, and add a new element to heap from remaining elements. Removing an element and adding a new element to min heap will take Logk time. So overall complexity will be O(k) + O((n-k)*logK)
P a g e | 283 #include usingnamespacestd;
// Prototype of a utility function to swap two int egers void swap(int *x, int *y);
// A class for Min Heap classMinHeap { int *harr; // pointer to array of elements in heap int heap_size; // size of min heap public: // Constructor MinHeap(int a[], int size);
// to heapify a subtree with root at given index void MinHeapify(int );
// to get index of left child of node at index i int left(int i) { return (2*i + 1); }
// to get index of right child of node at index i int right(int i) { return (2*i + 2); }
// to remove min (or root), add a new value x, and return int replaceMin(int x);
// to extract the root which is the minimum element
old root
P a g e | 284 int extractMin(); };
// Given an array of size n, where every element is k away from its target // position, sorts the array in O(nLogk) time. int sortK(int arr[], int n, int k) { // Create a Min Heap of first (k+1) elements from // input array int *harr = newint[k+1]; for(int i = 0; i= 0) { MinHeapify(i); i--; } }
// Method to remove minimum element (or root) from min heap int MinHeap::extractMin() { int root = harr[0]; if(heap_size > 1) { harr[0] = harr[heap_size-1]; heap_size--; MinHeapify(0); } return root; }
P a g e | 286
// Method to change root with given value x, and return
the old root
int MinHeap::replaceMin(int x) { int root = harr[0]; harr[0] = x; if(root < x) MinHeapify(0); return root; }
// A recursive method to heapify a subtree with root at given index // This method assumes that the subtrees are already heapified void MinHeap::MinHeapify(int i) { int l = left(i); int r = right(i); int smallest = i; if(l < heap_size && harr[l] < harr[i]) smallest = l; if(r < heap_size && harr[r] < harr[smallest]) smallest = r; if(smallest != i) { swap(&harr[i], &harr[smallest]); MinHeapify(smallest); } }
P a g e | 287 // A utility function to swap two elements void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; }
// A utility function to print array elements void printArray(int arr[], int size) { for(int i=0; i < size; i++) cout 0 for(int i = n-1; i > 0; i--) { // Pick a random index from 0 to i int j = rand() % (i+1);
// Swap arr[i] with the element at random index swap(&arr[i], &arr[j]);
P a g e | 310 } }
// Driver program to test above function. int main() { int arr[] = {1, 2, 3, 4, 5, 6, 7, 8}; int n = sizeof(arr)/ sizeof(arr[0]); randomize (arr, n); printArray(arr, n);
return 0; }
Output:
7 8 4 6 3 1 2 5 The above function assumes that rand() generates a random number. Time Complexity: O(n), assuming that the function rand() takes O(1) time. How does this work? The probability that ith element (including the last one) goes to last position is 1/n, because we randomly pick an element in first iteration. The probability that ith element goes to second last position can be proved to be 1/n by dividing it in two cases. Case 1: i = n-1 (index of last element): The probability of last element going to second last position is = (probability that last element doesn't stay at its original position) x (probability that the index picked in previous step is picked again so that the last element is swapped) So the probability = ((n-1)/n) x (1/(n-1)) = 1/n Case 2: 0 < i < n-1 (index of non-last): The probability of ith element going to second position = (probability that ith element
P a g e | 311
is not picked in previous iteration) x (probability that ith element is picked in this iteration) So the probability = ((n-1)/n) x (1/(n-1)) = 1/n We can easily generalize above proof for any other position.
Count the number of possible triangles October 11, 2012
Given an unsorted array of positive integers. Find the number of triangles that can be formed with three different array elements as three sides of triangles. For a triangle to be possible from 3 values, the sum of any two values (or sides) must be greater than the third value (or third side). For example, if the input array is {4, 6, 3, 7}, the output should be 3. There are three triangles possible {3, 4, 6}, {4, 6, 7} and {3, 6, 7}. Note that {3, 4, 7} is not a possible triangle. As another example, consider the array {10, 21, 22, 100, 101, 200, 300}. There can be 6 possible triangles: {10, 21, 22}, {21, 100, 101}, {22, 100, 101}, {10, 100, 101}, {100, 101, 200} and {101, 200, 300} Method 1 (Brute force) The brute force method is to run three loops and keep track of the number of triangles possible so far. The three loops select three different values from array, the innermost loop checks for the triangle property ( the sum of any two sides must be greater than the value of third side). Time Complexity: O(N^3) where N is the size of input array. Method 2 (Tricky and Efficient) Let a, b and c be three sides. The below condition must hold for a triangle (Sum of two sides is greater than the third side) i) a + b > c ii) b + c > a iii) a + c > b Following are steps to count triangle. 1. Sort the array in non-decreasing order.
P a g e | 312
2. Initialize two pointers „i‟ and „j‟ to first and second elements respectively, and initialize count of triangles as 0. 3. Fix „i‟ and „j‟ and find the rightmost index „k‟ (or largest „arr[k]„) such that „arr[i] + arr[j] > arr[k]„. The number of triangles that can be formed with „arr[i]„ and „arr[j]„ as two sides is „k – j‟. Add „k – j‟ to count of triangles. Let us consider „arr[i]„ as „a‟, „arr[j]„ as b and all elements between „arr[j+1]„ and „arr[k]„ as „c‟. The above mentioned conditions (ii) and (iii) are satisfied because „arr[i] < arr[j] < arr[k]'. And we check for condition (i) when we pick 'k' 4. Increment „j‟ to fix the second element again. Note that in step 2, we can use the previous value of „k‟. The reason is simple, if we know that the value of „arr[i] + arr[j-1]„ is greater than „arr[k]„, then we can say „arr[i] + arr[j]„ will also be greater than „arr[k]„, because the array is sorted in increasing order. 5. If „j‟ has reached end, then increment „i‟. Initialize „j‟ as „i + 1′, „k‟ as „i+2′ and repeat the steps 3 and 4. Following is implementation of the above approach. // Program to count number of triangles that can be formed from given array #include #include
/* Following function is needed for library function qsort(). Refer
http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/ */ int comp(constvoid* a, constvoid* b) {
return *(int *)a > *(int *)b ; }
// Function to count all possible triangles with arr[] elements int findNumberOfTriangles(int arr[], int n) {
P a g e | 313 // Sort the array elements in non-decreasing order qsort(arr, n, sizeof( arr[0] ), comp);
// Initialize count of triangles int count = 0;
// Fix the first element. elements are
We need to run till n-3 as the other two
// selected from arr[i+1...n-1] for(int i = 0; i < n-2; ++i) { // Initialize index of the rightmost third element int k = i+2;
// Fix the second element for(int j = i+1; j < n; ++j) { // Find the rightmost element which is smaller than the sum // of two fixed elements // The important thing to note here is, we use the previous // value of k. If value of arr[i] + arr[j-1] was greater than arr[k], // then arr[i] + arr[j] must be greater than k, because the // array is sorted. while(k < n && arr[i] + arr[j] > arr[k]) ++k;
// Total number of possible triangles that can be formed // with the two fixed elements is k - j - 1.
The two fixed
P a g e | 314 // elements are arr[i] and arr[j].
All elements between arr[j+1]
// to arr[k-1] can form a triangle with arr[i] and arr[j]. // One is subtracted from k because k is incremented one extra // in above while loop. // k will always be greater than j. If j becomes equal to k, then // above loop will increment k, because arr[k] + arr[i] is always // greater than arr[k] count += k - j - 1; } }
return count; }
// Driver program to test above functionarr[j+1] int main() { int arr[] =
{10, 21, 22, 100, 101, 200, 300};
int size = sizeof( arr ) / sizeof( arr[0] );
printf("Total number of triangles possible is %d ", findNumberOfTriangles( arr, size ) );
return 0; }
Output:
Total number of triangles possible is 6
P a g e | 315
Time Complexity: O(n^2). The time complexity looks more because of 3 nested loops. If we take a closer look at the algorithm, we observe that k is initialized only once in the outermost loop. The innermost loop executes at most O(n) time for every iteration of outer most loop, because k starts from i+2 and goes upto n for all values of j. Therefore, the time complexity is O(n^2).
Iterative Quick Sort October 13, 2012 Following is a typical recursive implementation of Quick Sort that uses last element as pivot. /* A typical recursive implementation of quick sort */
/* This function takes last element as pivot, places the pivot element at its correct position in sorted array, and places all smaller (smaller than pivot) to left of pivot and all greater elements to right of pivot */ int partition (int arr[], int l, int h) { int x = arr[h]; int i = (l - 1);
for(int j = l; j Starting index, h
--> Ending index */
void quickSort(int A[], int l, int h) { if(l < h) { int p = partition(A, l, h); /* Partitioning index */ quickSort(A, l, p - 1); quickSort(A, p + 1, h); } }
The above implementation can be optimized in many ways 1) The above implementation uses last index as pivot. This causes worst -case behavior on already sorted arrays, which is a commonly occurring case. The problem can be solved by choosing either a random index for the pivot, or choosing the middle index of the partition or choosing the median of the first, middle and last element of the partition for the pivot . (See this for details) 2) To reduce the recursion depth, recur first for the smaller half of the array, and use a tail call to recurse into the othe r. 3) Insertion sort works better for small subarrays. Insertion sort can be used for invocations on such small arrays (i.e. where the length is less than a threshold t determined experimentally). For example, this library implementation of qsort uses insertion sort below size 7. Despite above optimizations, the function remains recursive and uses function call stack to store intermediate values of l and h. The function call stack stores other bookkeeping information together with parameters. Also, function calls involve overheads like storing activation record of the caller function and then resuming execution. The above function can be easily converted to iterative version with the help of an auxiliary stack. Following is an iterative implementation of the above recursive code. // An iterative implementation of quick sort #include
P a g e | 317 // A utility function to swap two elements void swap ( int * a, int * b ) { int t = *a; *a = *b; *b = t; }
/* This function is same in both iterative and recursive*/ int partition (int arr[], int l, int h) { int x = arr[h]; int i = (l - 1);
for(int j = l; j Starting index, h
void quickSortIterative (int arr[], int l, int h) {
--> Ending index */
P a g e | 318 // Create an auxiliary stack int stack[ h - l + 1 ];
// initialize top of stack int top = -1;
// push initial values of l and h to stack stack[ ++top ] = l; stack[ ++top ] = h;
// Keep popping from stack while is not empty while( top >= 0 ) { // Pop h and l h = stack[ top-- ]; l = stack[ top-- ];
// Set pivot element at its correct position in sorted array int p = partition( arr, l, h );
// If there are elements on left side of pivot, then push left // side to stack if( p-1 > l ) { stack[ ++top ] = l; stack[ ++top ] = p - 1; }
P a g e | 319 // If there are elements on right side of pivot, then push right // side to stack if( p+1 < h ) { stack[ ++top ] = p + 1; stack[ ++top ] = h; } } }
// A utility function to print contents of arr void printArr( int arr[], int n ) { int i; for( i = 0; i < n; ++i ) printf( "%d ", arr[i] ); }
// Driver program to test above functions int main() { int arr[] = {4, 3, 5, 2, 1, 3, 2, 3}; int n = sizeof( arr ) / sizeof( *arr ); quickSortIterative( arr, 0, n - 1 ); printArr( arr, n ); return 0; }
Output:
P a g e | 320
1 2 2 3 3 3 4 5 The above mentioned optimizations for recursive quick sort can also be applied to iterative version. 1) Partition process is same in both recursive and iterative. The same techniques to choose optimal pivot can also be applied to iterative version. 2) To reduce the stack size, first push the indexes of smaller half. 3) Use insertion sort when the size reduces below a experimentally calculated threshold. References: http://en.wikipedia.org/wiki/Quicksort
Inplace M x N size matrix transpose | Updated October 16, 2012
About four months of gap (missing GFG), a new post. Given an M x N matrix, transpose the matrix without auxiliary memory.It is easy to transpose matrix using an auxiliary array. If the matrix is symmetric in size, we can transpose the matrix inplace by mirroring the 2D array across it‟s diagonal (try yourself). How to transpose an arbitrary size matrix inplace? See the following matrix,
a d g j
b e h k
c f i l
==>
a d g j b e h k c f i l
As per 2D numbering in C/C++, corresponding location mapping looks like,
Org element New 0 a 0 1 b 4 2 c 8 3 d 1 4 e 5 5 f 9 6 g 2 7 h 6 8 i 10
P a g e | 321
9 10 11
j k l
3 7 11
Note that the first and last elements stay in their original location. We can easily see the transformation forms few permutation cycles. 1->4->5->9->3->1 - Total 5 elements form the cycle 2->8->10->7->6->2 – Another 5 elements form the cycle 0 - Self cycle 11 – Self cycle From the above example, we can easily devise an algorithm to move the elements along these cycles. How can we generate permutation cycles? Number of elements in both the matrices are constant, given by N = R * C, where R is row count and C is column count. An element at location ol (old location in R x C matrix), moved to nl (new location in C x R matrix). We need to establish relation between ol, nl, R and C. Assume ol = A[or][oc]. In C/C++ we can calculate the element address as,
ol = or x C + oc (ignore base reference for simplicity) It is to be moved to new location nl in the transposed matrix, say nl = A[nr][nc], or in C/C++ terms
nl = nr x R + nc (R - column count, C is row count as the matrix is transposed) Observe, nr = oc and nc = or, so replacing these for nl,
nl = oc x R + or -----> [eq 1] after solving for relation between ol and nl, we get
ol = or ol x R = or = or N) = or = or
x C + oc x C x R + oc x R x N + oc x R
(from the fact R * C =
x N + (nl - or) --- from [eq 1] x (N-1) + nl
OR,
nl = ol x R - or x (N-1)
P a g e | 322
Note that the values of nl and ol never go beyond N-1, so considering modulo division on both the sides by (N-1), we get the following based on properties of congruence,
nl mod (N-1) = (ol x R - or x (N-1)) mod (N-1) = (ol x R) mod (N-1) - or x (N-1) mod(N-1) = ol x R mod (N-1), since second term evaluates to zero nl = (ol x R) mod (N-1), since nl is always less than N1 A curious reader might have observed the significance of above relation. Every location is scaled by a factor of R (row size). It is obvious from the matrix that every location is displaced by scaled factor of R. The actual multiplier depends on congruence class of (N-1), i.e. the multiplier can be both -ve and +ve value of the congruent class.Hence every location transformation is simple modulo division. These modulo divisions form cyclic permutations. We need some book keeping information to keep track of already moved elements. Here is code for inplace matrix transformation, // Program for in-place matrix transpose #include #include #include #define HASH_SIZE 128
usingnamespacestd;
// A utility function to print a 2D array of size nr x nc and base address A void Print2DArray(int *A, int nr, int nc) { for(int r = 0; r < nr; r++) { for(int c = 0; c < nc; c++)
P a g e | 323 printf("%4d", *(A + r*nc + c));
printf("\n"); }
printf("\n\n"); }
// Non-square matrix transpose of matrix of size r x c and base address A void MatrixInplaceTranspose(int *A, int r, int c) { int size = r*c - 1; int t; // holds element to be replaced, eventually becomes next element to move int next; // location of 't' to be moved int cycleBegin; // holds start of cycle int i; // iterator bitset b; // hash to mark moved elements
b.reset(); b[0] = b[size] = 1; i = 1; // Note that A[0] and A[size-1] won't move while(i < size) { cycleBegin = i; t = A[i]; do { // Input matrix [r x c]
P a g e | 324 // Output matrix 1 // i_new = (i*r)%(N-1) next = (i*r)%size; swap(A[next], t); b[i] = 1; i = next; } while(i != cycleBegin);
// Get Next Move (what about querying random location?) for(i = 1; i < size && b[i]; i++) ; cout maxSum) { maxSum = sum; *start = local_start; *finish = i; } }
// There is at-least one non-negative number if(*finish != -1) return maxSum;
// Special Case: When all numbers in arr[] are negative maxSum = arr[0]; *start = *finish = 0;
// Find the maximum element in array for(i = 1; i < n; i++) { if(arr[i] > maxSum) { maxSum = arr[i]; *start = *finish = i; } } return maxSum; }
P a g e | 345 // The main function that finds maximum sum rectangle in M[][] void findMaxSum(int M[][COL]) { // Variables to store the final output int maxSum = INT_MIN, finalLeft, finalRight, finalTop, finalBottom;
int left, right, i; int temp[ROW], sum, start, finish;
// Set the left column for(left = 0; left < COL; ++left) { // Initialize all elements of temp as 0 memset(temp, 0, sizeof(temp));
// Set the right column for the left column set by outer loop for(right = left; right < COL; ++right) { // Calculate sum between current left and right for every row 'i' for(i = 0; i < ROW; ++i) temp[i] += M[i][right];
// Find the maximum sum subarray in temp[]. The kadane() function // also sets values of start and finish.
So 'sum' is sum of
// rectangle between (start, left) and (finish, right) which is the //
maximum sum with boundary columns strictly as left and right.
sum = kadane(temp, &start, &finish, ROW);
P a g e | 346 // Compare sum with maximum sum so far. If sum is more, then update // maxSum and other output values if(sum > maxSum) { maxSum = sum; finalLeft = left; finalRight = right; finalTop = start; finalBottom = finish; } } }
// Print final values printf("(Top, Left) (%d, %d)\n", finalTop, finalLeft); printf("(Bottom, Right) (%d, %d)\n", finalBottom, finalRight); printf("Max sum is: %d\n", maxSum); }
// Driver program to test above functions int main() { int M[ROW][COL] = {{1, 2, -1, -4, -20}, {-8, -3, 4, 2, 1}, {3, 8, 10, 1, 3}, {-4, -1, 1, 7, -6} };
P a g e | 347 findMaxSum(M);
return 0; }
Output:
(Top, Left) (1, 1) (Bottom, Right) (3, 3) Max sum is: 29 Time Complexity: O(n^3)
Pancake sorting March 3, 2013
Given an an unsorted array, sort the given array. You are allowed to do only following operation on array.
flip(arr, i): Reverse array from 0 to i Unlike a traditional sorting algorithm, which attempts to sort with the fewest comparisons possible, the goal is to sort the sequence in as few reversals as possible. The idea is to do something similar to Selection Sort. We one by one place maximum element at the end and reduce the size of current array by one. Following are the detailed steps. Let given array be arr[] and size of array be n. 1) Start from current size equal to n and reduce current size by one while it‟s greater than 1. Let the current size be curr_size. Do following for every curr_size ……a) Find index of the maximum element in arr[0..curr_szie-1]. Let the index be „mi‟ ……b) Call flip(arr, mi) ……c) Call flip(arr, curr_size-1) See following video for visualization of the above algorithm.
P a g e | 348 /* A C++ program for Pancake Sorting */ #include #include
/* Reverses arr[0..i] */ void flip(int arr[], int i) { int temp, start = 0; while(start < i) { temp = arr[start]; arr[start] = arr[i]; arr[i] = temp; start++; i--; } }
/* Returns index of the maximum element in arr[0..n-1] */ int findMax(int arr[], int n) { int mi, i; for(mi = 0, i = 0; i < n; ++i) if(arr[i] > arr[mi]) mi = i; return mi; }
// The main function that sorts given array using flip operations
P a g e | 349 int pancakeSort(int *arr, int n) { // Start from the complete array and one by one reduce current size by one for(int curr_size = n; curr_size > 1; --curr_size) { // Find index of the maximum element in arr[0..curr_size-1] int mi = findMax(arr, curr_size);
// Move the maximum element to end of current array if it's not // already at the end if(mi != curr_size-1) { // To move at the end, first move maximum number to beginning flip(arr, mi);
// Now move the maximum number to end by reversing current array flip(arr, curr_size-1); } } }
/* A utility function to print an array of size n */ void printArray(int arr[], int n) { for(int i = 0; i < n; ++i) printf("%d ", arr[i]); }
// Driver program to test above function
P a g e | 350 int main() { int arr[] = {23, 10, 20, 11, 12, 6, 7}; int n = sizeof(arr)/sizeof(arr[0]);
pancakeSort(arr, n);
puts("Sorted Array "); printArray(arr, n);
return 0; }
Output:
Sorted Array 6 7 10 11 12 20 23 Total O(n) flip operations are performed in above code. The overall time complexity is O(n^2).
A Pancake Sorting Problem March 5, 2013
We have discussed Pancake Sorting in the previous post. Following is a problem based on Pancake Sorting. Given an an unsorted array, sort the given array. You are allowed to do only following operation on array.
flip(arr, i): Reverse array from 0 to i Imagine a hypothetical machine where flip(i) always takes O(1) time. Write an efficient program for sorting a given array in O(nLogn) time on the given machine. If we apply the same algorithm here, the time taken will be O(n^2)
P a g e | 351
because the algorithm calls findMax() in a loop and find findMax() takes O(n) time even on this hypothetical machine. We can use insertion sort that uses binary search. The idea is to run a loop from second element to last element (from i = 1 to n-1), and one by one insert arr[i] in arr[0..i-1] (like standard insertion sort algorithm). When we insert an element arr[i], we can use binary search to find position of arr[i] in O(Logi) time. Once we have the position, we can use some flip operations to put arr[i] at its new place. Following are abstract steps.
// Standard Insertion Sort Loop that starts from second element for (i=1; i < n; i++) ----> O(n) { int key = arr[i]; // Find index of ceiling of arr[i] in arr[0..i-1] using binary search j = celiSearch(arr, key, 0, i-1); ----> O(logn) (See this) // Apply some flip operations to put arr[i] at correct place } Since flip operation takes O(1) on given hypothetical machine, total running time of above algorithm is O(nlogn). Thanks to Kumar for suggesting above problem and algorithm. Let us see how does the above algorithm work. ceilSearch() actually returns the index of the smallest element which is greater than arr[i] in arr[0..i-1]. If there is no such element, it returns -1. Let the returned value be j. If j is -1, then we don‟t need to do anything as arr[i] is already the greatest element among arr[0..i]. Otherwise we need to put arr[i] just before arr[j]. So how to apply flip operations to put arr[i] just before arr[j] using values of i and j. Let us take an example to understand this. Let i be 6 and current array be {12, 15, 18, 30, 35, 40, 20, 6, 90, 80}. To put 20 at its new place, the array should be
P a g e | 352
changed to {12, 15, 18, 20, 30, 35, 40, 6, 90, 80}. We apply following steps to put 20 at its new place. 1) Find j using ceilSearch (In the above example j is 3). 2) flip(arr, j-1) (array becomes {18, 15, 12, 30, 35, 40, 20, 6, 90, 80}) 3) flip(arr, i-1); (array becomes {40, 35, 30, 12, 15, 18, 20, 6, 90, 80}) 4) flip(arr, i); (array becomes {20, 18, 15, 12, 30, 35, 40, 6, 90, 80}) 5) flip(arr, j); (array becomes {12, 15, 18, 20, 30, 35, 40, 6, 90, 80}) Following is C implementation of the above algorithm. #include #include
/* A Binary Search based function to get index of ceiling of x in arr[low..high] */ int ceilSearch(int arr[], int low, int high, int x) { int mid;
/* If x is smaller than or equal to the first element, then return
the first element */
if(x arr[high]) return -1;
/* get the index of middle element of arr[low..high]*/ mid = (low + high)/2;
/* low + (high – low)/2 */
-1 */
P a g e | 353
/* If x is same as middle element, then return
mid */
if(arr[mid] == x) return mid;
/* If x is greater than arr[mid], then either arr[mid + 1] is ceiling of x, or ceiling lies in arr[mid+1...high] */ if(arr[mid] < x) { if(mid + 1 arr[mid-1]) return mid; else return ceilSearch(arr, low, mid - 1, x); }
/* Reverses arr[0..i] */ void flip(int arr[], int i) { int temp, start = 0; while(start < i) {
P a g e | 354 temp = arr[start]; arr[start] = arr[i]; arr[i] = temp; start++; i--; } }
/* Function to sort an array using insertion sort, binary search and flip */ void insertionSort(int arr[], int size) { int i, j;
// Start from the second element and one by one insert arr[i] // in already sorted arr[0..i-1] for(i = 1; i < size; i++) { // Find the smallest element in arr[0..i-1] which is also greater than // or equal to arr[i] int j = ceilSearch(arr, 0, i-1, arr[i]);
// Check if there was no element greater than arr[i] if(j != -1) { // Put arr[i] before arr[j] using following four flip operations flip(arr, j-1); flip(arr, i-1); flip(arr, i); flip(arr, j);
P a g e | 355 } } }
/* A utility function to print an array of size n */ void printArray(int arr[], int n) { int i; for(i = 0; i < n; ++i) printf("%d ", arr[i]); }
/* Driver program to test insertion sort */ int main() { int arr[] = {18, 40, 35, 12, 30, 35, 20, 6, 90, 80}; int n = sizeof(arr)/sizeof(arr[0]); insertionSort(arr, n); printArray(arr, n); return 0; }
Output:
6 12 18 20 30 35 35 40 80 90
Tug of War March 13, 2013
Given a set of n integers, divide the set in two subsets of n/2 sizes each such that the difference of the sum of two subsets is as minimum as possible. If n is even, then sizes of two subsets must be strictly n/2 and if n is odd, then size of one subset must be (n-1)/2 and size of other subset must be (n+1)/2.
P a g e | 356
For example, let given set be {3, 4, 5, -3, 100, 1, 89, 54, 23, 20}, the size of set is 10. Output for this set should be {4, 100, 1, 23, 20} and {3, 5, -3, 89, 54}. Both output subsets are of size 5 and sum of elements in both subsets is same (148 and 148). Let us consider another example where n is odd. Let given set be {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}. The output subsets should be {45, -34, 12, 98, -1} and {23, 0, -99, 4, 189, 4}. The sums of elements in two subsets are 120 and 121 respectively. The following solution tries every possible subset of half size. If one subset of half size is formed, the remaining elements form the other subset. We initialize current set as empty and one by one build it. There are two possibilities for every element, either it is part of current set, or it is part of the remaining elements (other subset). We consider both possibilities for every element. When the size of current set becomes n/2, we check whether this solutions is better than the best solution available so far. If it is, then we update the best solution. Following is C++ implementation for Tug of War problem. It prints the required arrays. #include #include #include usingnamespacestd;
// function that tries every possible solution by calling itself recursively void TOWUtil(int * arr, int n, bool * curr_elements, int no_of_selected_elements, bool * soln, int * min_diff, int sum, int curr_sum, int curr_position) { // checks whether the it is going out of bound if(curr_position == n) return ;
P a g e | 357
// checks that the numbers of elements left are not less than the // number of elements required to form the solution if((n/2 - no_of_selected_elements) > (n - curr_position)) return ;
// consider the cases when current element is not included in the solution TOWUtil(arr, n, curr_elements, no_of_selected_elements, soln, min_diff, sum, curr_sum, curr_position+1);
// add the current element to the solution no_of_selected_elements++; curr_sum = curr_sum + arr[curr_position]; curr_elements[curr_position] = true;
// checks if a solution is formed if(no_of_selected_elements == n/2) { // checks if the solution formed is better than the best solution so far if(abs(sum/2 - curr_sum) < *min_diff) { *min_diff = abs(sum/2 - curr_sum); for(int i = 0; i 0) return 0;
// Find 'high' for binary search by repeated doubling int i = 1; while(f(i) arr[mid]) return findMin(arr, low, mid-1); return findMin(arr, mid+1, high); }
// Driver program to test above functions int main() { int arr1[] =
{5, 6, 1, 2, 3, 4};
int n1 = sizeof(arr1)/sizeof(arr1[0]); printf("The minimum element is %d\n", findMin(arr1, 0, n1-1));
int arr2[] =
{1, 2, 3, 4};
int n2 = sizeof(arr2)/sizeof(arr2[0]); printf("The minimum element is %d\n", findMin(arr2, 0, n2-1));
int arr3[] =
{1};
int n3 = sizeof(arr3)/sizeof(arr3[0]); printf("The minimum element is %d\n", findMin(arr3, 0, n3-1));
int arr4[] =
{1, 2};
int n4 = sizeof(arr4)/sizeof(arr4[0]); printf("The minimum element is %d\n", findMin(arr4, 0, n4-1));
int arr5[] =
{2, 1};
int n5 = sizeof(arr5)/sizeof(arr5[0]); printf("The minimum element is %d\n", findMin(arr5, 0, n5-1));
P a g e | 414
int arr6[] =
{5, 6, 7, 1, 2, 3, 4};
int n6 = sizeof(arr6)/sizeof(arr6[0]); printf("The minimum element is %d\n", findMin(arr6, 0, n6-1));
int arr7[] =
{1, 2, 3, 4, 5, 6, 7};
int n7 = sizeof(arr7)/sizeof(arr7[0]); printf("The minimum element is %d\n", findMin(arr7, 0, n7-1));
int arr8[] =
{2, 3, 4, 5, 6, 7, 8, 1};
int n8 = sizeof(arr8)/sizeof(arr8[0]); printf("The minimum element is %d\n", findMin(arr8, 0, n8-1));
int arr9[] =
{3, 4, 5, 1, 2};
int n9 = sizeof(arr9)/sizeof(arr9[0]); printf("The minimum element is %d\n", findMin(arr9, 0, n9-1));
return 0; }
Output:
The The The The The The The The The
minimum minimum minimum minimum minimum minimum minimum minimum minimum
element element element element element element element element element
is is is is is is is is is
1 1 1 1 1 1 1 1 1
P a g e | 415
How to handle duplicates? It turned out that duplicates can‟t be handled in O(Logn) time in all cases. Thanks to Amit Jain for inputs. The special cases that cause problems are like {2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 2} and {2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2}. It doesn‟t look possible to go to left half or right half by doing constant number of comparisons at the middle. Following is an implementation that handles duplicates. It may become O(n) in worst case though. // C program to find minimum element in a sorted and rotated array #include
int min(int x, int y) { return (x < y)? x :y; }
// The function that handles duplicates.
It can be O(n) in worst case.
int findMin(int arr[], int low, int high) { // This condition is needed to handle the case when array is not // rotated at all if(high < low)
return arr[0];
// If there is only one element left if(high == low) return arr[low];
// Find mid int mid = low + (high - low)/2; /*(low + high)/2;*/
// Check if element (mid+1) is minimum element. Consider // the cases like {1, 1, 0, 1} if(mid < high && arr[mid+1] < arr[mid]) return arr[mid+1];
P a g e | 416
// This case causes O(n) time if(arr[low] == arr[mid] && arr[high] == arr[mid]) return min(findMin(arr, low, mid-1), findMin(arr, mid+1, high));
// Check if mid itself is minimum element if(mid > low && arr[mid] < arr[mid - 1]) return arr[mid];
// Decide whether we need to go to left half or right half if(arr[high] > arr[mid]) return findMin(arr, low, mid-1); return findMin(arr, mid+1, high); }
// Driver program to test above functions int main() { int arr1[] =
{5, 6, 1, 2, 3, 4};
int n1 = sizeof(arr1)/sizeof(arr1[0]); printf("The minimum element is %d\n", findMin(arr1, 0, n1-1));
int arr2[] =
{1, 1, 0, 1};
int n2 = sizeof(arr2)/sizeof(arr2[0]); printf("The minimum element is %d\n", findMin(arr2, 0, n2-1));
int arr3[] =
{1, 1, 2, 2, 3};
int n3 = sizeof(arr3)/sizeof(arr3[0]);
P a g e | 417 printf("The minimum element is %d\n", findMin(arr3, 0, n3-1));
int arr4[] =
{3, 3, 3, 4, 4, 4, 4, 5, 3, 3};
int n4 = sizeof(arr4)/sizeof(arr4[0]); printf("The minimum element is %d\n", findMin(arr4, 0, n4-1));
int arr5[] =
{2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 2};
int n5 = sizeof(arr5)/sizeof(arr5[0]); printf("The minimum element is %d\n", findMin(arr5, 0, n5-1));
int arr6[] =
{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1};
int n6 = sizeof(arr6)/sizeof(arr6[0]); printf("The minimum element is %d\n", findMin(arr6, 0, n6-1));
int arr7[] =
{2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2};
int n7 = sizeof(arr7)/sizeof(arr7[0]); printf("The minimum element is %d\n", findMin(arr7, 0, n7-1));
return 0; }
Output:
The The The The The The The
minimum minimum minimum minimum minimum minimum minimum
element element element element element element element
Stable Marriage Problem
is is is is is is is
1 0 1 3 0 1 0
P a g e | 418 July 20, 2013
Given N men and N women, where each person has ranked all members of the opposite sex in order of preference, marry the men and women together such that there are no two people of opposite sex who would both rather have each other than their current partners. If there are no such people, all the marriages are “stable” (Source Wiki). Consider the following example. Let there be two men m1 and m2 and two women w1 and w2. Let m1„s list of preferences be {w1, w2} Let m2„s list of preferences be {w1, w2} Let w1„s list of preferences be {m1, m2} Let w2„s list of preferences be {m1, m2} The matching { {m1, w2}, {w1, m2} } is not stable because m1 and w1 would prefer each other over their assigned partners. The matching {m1, w1} and {m2, w2} is stable because there are no two people of opposite sex that would prefer each other over their assigned partners. It is always possible to form stable marriages from lists of preferences (See references for proof). Following is Gale–Shapley algorithm to find a stable matching: The idea is to iterate through all free men while there is any free man available. Every free man goes to all women in his preference list according to the order. For every woman he goes to, he checks if the woman is free, if yes, they both become engaged. If the woman is not free, then the woman chooses either says no to him or dumps her current engagement according to her preference list. So an engagement done once can be broken if a woman gets better option. Following is complete algorithm from Wiki
Initialize all men and women to free while there exist a free man m who still has a woman w to propose to { w = m's highest ranked such woman to whom he has not yet proposed if w is free (m, w) become engaged
P a g e | 419
else some pair (m', w) already exists if w prefers m to m' (m, w) become engaged m' becomes free else (m', w) remain engaged } Input & Output: Input is a 2D matrix of size (2*N)*N where N is number of women or men. Rows from 0 to N-1 represent preference lists of men and rows from N to 2*N – 1 represent preference lists of women. So men are numbered from 0 to N-1 and women are numbered from N to 2*N – 1. The output is list of married pairs. Following is C++ implementation of the above algorithm. // C++ program for stable marriage problem #include #include #include usingnamespacestd;
// Number of Men or Women #define N
4
// This function return s true if woman 'w' prefers man 'm1' over man 'm' bool wPrefersM1OverM(int prefer[2*N][N], int w, int m, int m1) { // Check if w prefers m over her current engagment m1 for(int i = 0; i < N; i++) { // If m1 comes before m in lisr of w, then w prefers her // cirrent engagement, don't do anything if(prefer[w][i] == m1)
P a g e | 420 return true;
// If m cmes before m1 in w's list, then free her current // engagement and engage her with m if(prefer[w][i] == m) return false; } }
// Prints stable matching for N boys and N girls. Boys are numbered as 0 to // N-1. Girls are numbereed as N to 2N-1. void stableMarriage(int prefer[2*N][N]) { // Stores partner of women. This is our output array that // stores paing information.
The value of wPartner[i]
// indicates the partner assigned to woman N+i.
Note that
// the woman numbers between N and 2*N-1. The value -1 // indicates that (N+i)'th woman is free int wPartner[N];
// An array to store availability of men.
If mFree[i] is
// false, then man 'i' is free, otherwise engaged. bool mFree[N];
// Initialize all men and women as free memset(wPartner, -1, sizeof(wPartner)); memset(mFree, false, sizeof(mFree)); int freeCount = N;
P a g e | 421
// While there are free men while(freeCount > 0) { // Pick the first free man (we could pick any) int m; for(m = 0; m < N; m++) if(mFree[m] == false) break;
// One by one go to all women according to m's preferences. // Here m is the picked free man for(int i = 0; i < N && mFree[m] == false; i++) { int w = prefer[m][i];
// The woman of preference is free, w and m become // partners (Note that the partnership maybe changed // later). So we can say they are engaged not married if(wPartner[w-N] == -1) { wPartner[w-N] = m; mFree[m] = true; freeCount--; }
else // If w is not free {
P a g e | 422 // Find current engagement of w int m1 = wPartner[w-N];
// If w prefers m over her current engagement m1, // then break the engagement between w and m1 and // engage m with w. if(wPrefersM1OverM(prefer, w, m, m1) == false) { wPartner[w-N] = m; mFree[m] = true; mFree[m1] = false; } } // End of Else } // End of the for loop that goes to all women in m's list } // End of main while loop
// Print the solution cout
View more...
Comments