├── Binary Search ├── allocate_min_pages.py ├── binary_search.py ├── binary_search_reverse.py ├── bitonic_array_max.py ├── ceil_sorted_array.py ├── find_element_in_rotated_sorted_array.py ├── first_last_occurence.py ├── floor_sorted_array.py ├── min_diff_element_sorted_array.py ├── no. of times rotated.py ├── number_of_occurances.py ├── occurs_only_once.py ├── order_agnostic_BS.py ├── peak_element_sorted_array.py ├── pos_element_sorted_infinite_array.py ├── row-col-wise_sorted_matrix.py ├── search_nearly_sorted_array.py ├── searching_in_bitonic_array.py └── smallest_alphabet_greater_than_a_character.py ├── README.md ├── Recursion ├── Josephus_problem.py ├── Kth_symbol.py ├── N-bit_binary_more_ones.py ├── all_subsequence.py ├── delete_mid_ele_stack.py ├── generate_all_balanced_paranthesis.py ├── height_of_BT.py ├── letter_case_perm.py ├── perm_with_spaces.py ├── permutation_with_case_change.py ├── powerset.py ├── reverse_stack.py ├── sort_a_stack.py ├── subset.py ├── tower_of_Hanoi.py └── unique_subset_variation.py └── Stacks ├── Celebrity Problem.py ├── Implement Min Stack.py ├── Implement Stack using Heap.py ├── Longest Valid Parenthesis.py ├── Max Area Histogram.py ├── Max Area Rectangle Binary Matrix.py ├── Nearest Greater to Left.py ├── Nearest Greater to Right.py ├── Nearest Smaller to Left.py ├── Nearest Smaller to Right.py ├── Rain Water Trapping.py └── Stock Span Problem.py /Binary Search/allocate_min_pages.py: -------------------------------------------------------------------------------- 1 | # current minimum value is feasible or not. 2 | def isPossible(arr, n, m, curr_min): 3 | studentsRequired = 1 4 | curr_sum = 0 5 | 6 | # iterate over all books 7 | for i in range(n): 8 | 9 | # check if current number of pages are 10 | # greater than curr_min that means 11 | # we will get the result after 12 | # mid no. of pages 13 | if (arr[i] > curr_min): 14 | return False 15 | 16 | # count how many students are required 17 | # to distribute curr_min pages 18 | if (curr_sum + arr[i] > curr_min): 19 | 20 | # increment student count 21 | studentsRequired += 1 22 | 23 | # update curr_sum 24 | curr_sum = arr[i] 25 | 26 | # if students required becomes greater 27 | # than given no. of students, return False 28 | if (studentsRequired > m): 29 | return False 30 | 31 | # else update curr_sum 32 | else: 33 | curr_sum += arr[i] 34 | 35 | return True 36 | 37 | # function to find minimum pages 38 | def findPages(arr, n, m): 39 | 40 | sum = 0 41 | 42 | # return -1 if no. of books is 43 | # less than no. of students 44 | if (n < m): 45 | return -1 46 | 47 | # Count total number of pages 48 | for i in range(n): 49 | sum += arr[i] 50 | 51 | # initialize start as 0 pages and 52 | # end as total pages 53 | start, end = 0, sum 54 | result = 10**9 55 | 56 | # traverse until start <= end 57 | while (start <= end): 58 | 59 | # check if it is possible to distribute 60 | # books by using mid as current minimum 61 | mid = (start + end) // 2 62 | if (isPossible(arr, n, m, mid)): 63 | 64 | # update result to current distribution 65 | # as it's the best we have found till now. 66 | result = mid 67 | 68 | # as we are finding minimum and books 69 | # are sorted so reduce end = mid -1 70 | # that means 71 | end = mid - 1 72 | 73 | else: 74 | # if not possible means pages should be 75 | # increased so update start = mid + 1 76 | start = mid + 1 77 | 78 | # at-last return minimum no. of pages 79 | return result 80 | 81 | # Driver Code 82 | 83 | # Number of pages in books 84 | arr = [12, 34, 67, 90] 85 | n = len(arr) 86 | m = 2 # No. of students 87 | 88 | print("Minimum number of pages = ", 89 | findPages(arr, n, m)) 90 | -------------------------------------------------------------------------------- /Binary Search/binary_search.py: -------------------------------------------------------------------------------- 1 | def binarySearch(arr, l, r, x): 2 | 3 | while l <= r: 4 | 5 | mid = l + (r - l) // 2 6 | 7 | # Check if x is present at mid 8 | if arr[mid] == x: 9 | return mid 10 | 11 | # If x is greater, ignore left half 12 | elif arr[mid] < x: 13 | l = mid + 1 14 | 15 | # If x is smaller, ignore right half 16 | else: 17 | r = mid - 1 18 | 19 | # If we reach here, then the element 20 | # was not present 21 | return -1 22 | 23 | arr = [1,2,4,6,8,9,10] 24 | x = 8 25 | n = len(arr) 26 | print(binarySearch(arr,0,n,x)) 27 | -------------------------------------------------------------------------------- /Binary Search/binary_search_reverse.py: -------------------------------------------------------------------------------- 1 | # Binary Search in the reversed array 2 | 3 | def binarySearchRev(arr, n, x): 4 | l = 0 5 | r = n 6 | while (l <= r): 7 | mid = l + (r-l)//2 8 | if (x == arr[mid]): 9 | return mid 10 | 11 | elif (x < arr[mid]): # Only this condition changes [x < arr[mid]] 12 | l = mid + 1 13 | 14 | else: r = mid - 1 15 | 16 | return -1 17 | 18 | 19 | arr = [5,4,3,2,1] 20 | n = len(arr) 21 | x = 6 22 | print(binarySearchRev(arr,n,x)) 23 | -------------------------------------------------------------------------------- /Binary Search/bitonic_array_max.py: -------------------------------------------------------------------------------- 1 | def findMaximum(arr, low, high): 2 | # Base Case: Only one element is present in arr[low..high]*/ 3 | if low == high: 4 | return arr[low] 5 | 6 | # If there are two elements and first is greater then 7 | # the first element is maximum */ 8 | if high == low + 1 and arr[low] >= arr[high]: 9 | return arr[low]; 10 | 11 | # If there are two elements and second is greater then 12 | # the second element is maximum */ 13 | if high == low + 1 and arr[low] < arr[high]: 14 | return arr[high] 15 | 16 | mid = (low + high)//2 #low + (high - low)/2;*/ 17 | 18 | # If we reach a point where arr[mid] is greater than both of 19 | # its adjacent elements arr[mid-1] and arr[mid+1], then arr[mid] 20 | # is the maximum element*/ 21 | if arr[mid] > arr[mid + 1] and arr[mid] > arr[mid - 1]: 22 | return arr[mid] 23 | 24 | # If arr[mid] is greater than the next element and smaller than the previous 25 | # element then maximum lies on left side of mid */ 26 | if arr[mid] > arr[mid + 1] and arr[mid] < arr[mid - 1]: 27 | return findMaximum(arr, low, mid-1) 28 | else: # when arr[mid] is greater than arr[mid-1] and smaller than arr[mid+1] 29 | return findMaximum(arr, mid + 1, high) 30 | 31 | # Driver program to check above functions */ 32 | arr = [1, 3, 50, 10, 9, 7, 6] 33 | n = len(arr) 34 | print ("The maximum element is %d"% findMaximum(arr, 0, n-1)) -------------------------------------------------------------------------------- /Binary Search/ceil_sorted_array.py: -------------------------------------------------------------------------------- 1 | def ceilSearch(arr, low, high, x): 2 | 3 | # If x is smaller than or equal to the first element, 4 | # then return the first element */ 5 | if x <= arr[low]: 6 | return low 7 | 8 | # If x is greater than the last element, then return -1 */ 9 | if x > arr[high]: 10 | return -1 11 | 12 | # get the index of middle element of arr[low..high]*/ 13 | mid = (low + high)/2; # low + (high - low)/2 */ 14 | 15 | # If x is same as middle element, then return mid */ 16 | if arr[mid] == x: 17 | return mid 18 | 19 | # If x is greater than arr[mid], then either arr[mid + 1] 20 | # is ceiling of x or ceiling lies in arr[mid+1...high] */ 21 | elif arr[mid] < x: 22 | if mid + 1 <= high and x <= arr[mid+1]: 23 | return mid + 1 24 | else: 25 | return ceilSearch(arr, mid+1, high, x) 26 | 27 | # If x is smaller than arr[mid], then either arr[mid] 28 | # is ceiling of x or ceiling lies in arr[low...mid-1] */ 29 | else: 30 | if mid - 1 >= low and x > arr[mid-1]: 31 | return mid 32 | else: 33 | return ceilSearch(arr, low, mid - 1, x) 34 | 35 | # Driver program to check above functions */ 36 | arr = [1, 2, 8, 10, 10, 12, 19] 37 | n = len(arr) 38 | x = 20 39 | index = ceilSearch(arr, 0, n-1, x); 40 | 41 | if index == -1: 42 | print ("Ceiling of %d doesn't exist in array "% x) 43 | else: 44 | print ("ceiling of %d is %d"%(x, arr[index])) -------------------------------------------------------------------------------- /Binary Search/find_element_in_rotated_sorted_array.py: -------------------------------------------------------------------------------- 1 | def search (arr, l, h, key): 2 | if l > h: 3 | return -1 4 | 5 | mid = (l + h) // 2 6 | if arr[mid] == key: 7 | return mid 8 | 9 | # If arr[l...mid] is sorted 10 | if arr[l] <= arr[mid]: 11 | 12 | # As this subarray is sorted, we can quickly 13 | # check if key lies in half or other half 14 | if key >= arr[l] and key <= arr[mid]: 15 | return search(arr, l, mid-1, key) 16 | return search(arr, mid + 1, h, key) 17 | 18 | # If arr[l..mid] is not sorted, then arr[mid... r] 19 | # must be sorted 20 | if key >= arr[mid] and key <= arr[h]: 21 | return search(arr, mid + 1, h, key) 22 | return search(arr, l, mid-1, key) 23 | 24 | # Driver program 25 | arr = [4, 5, 6, 7, 8, 9, 1, 2, 3] 26 | key = 3 27 | i = search(arr, 0, len(arr)-1, key) 28 | if i != -1: 29 | print ("Index: % d"% i) 30 | else: 31 | print ("Key not found") -------------------------------------------------------------------------------- /Binary Search/first_last_occurence.py: -------------------------------------------------------------------------------- 1 | def first(arr, low, high, x, n) : 2 | if(high >= low) : 3 | mid = low + (high - low) // 2 4 | if( ( mid == 0 or x > arr[mid - 1]) and arr[mid] == x) : 5 | return mid 6 | elif(x > arr[mid]) : 7 | return first(arr, (mid + 1), high, x, n) 8 | else : 9 | return first(arr, low, (mid - 1), x, n) 10 | 11 | return -1 12 | 13 | 14 | # if x is present in arr[] then 15 | # returns the index of LAST occurrence 16 | # of x in arr[0..n-1], otherwise 17 | # returns -1 18 | def last(arr, low, high, x, n) : 19 | if (high >= low) : 20 | mid = low + (high - low) // 2 21 | if (( mid == n - 1 or x < arr[mid + 1]) and arr[mid] == x) : 22 | return mid 23 | elif (x < arr[mid]) : 24 | return last(arr, low, (mid - 1), x, n) 25 | else : 26 | return last(arr, (mid + 1), high, x, n) 27 | 28 | return -1 29 | 30 | 31 | # Driver program 32 | arr = [1, 2, 2, 2, 2, 3, 4, 7, 8, 8] 33 | n = len(arr) 34 | 35 | x = 2 36 | print("First Occurrence = ", 37 | first(arr, 0, n - 1, x, n)) 38 | print("Last Occurrence = ", 39 | last(arr, 0, n - 1, x, n)) 40 | 41 | -------------------------------------------------------------------------------- /Binary Search/floor_sorted_array.py: -------------------------------------------------------------------------------- 1 | def floorSearch(arr, low, high, x): 2 | 3 | # If low and high cross each other 4 | if (low > high): 5 | return -1 6 | 7 | # If last element is smaller than x 8 | if (x >= arr[high]): 9 | return high 10 | 11 | # Find the middle point 12 | mid = int((low + high) / 2) 13 | 14 | # If middle point is floor. 15 | if (arr[mid] == x): 16 | return mid 17 | 18 | # If x lies between mid-1 and mid 19 | if (mid > 0 and arr[mid-1] <= x 20 | and x < arr[mid]): 21 | return mid - 1 22 | 23 | # If x is smaller than mid, 24 | # floor must be in left half. 25 | if (x < arr[mid]): 26 | return floorSearch(arr, low, mid-1, x) 27 | 28 | # If mid-1 is not floor and x is greater than 29 | # arr[mid], 30 | return floorSearch(arr, mid + 1, high, x) 31 | 32 | 33 | # Driver Code 34 | arr = [1, 2, 4, 6, 10, 12, 14] 35 | n = len(arr) 36 | x = 7 37 | index = floorSearch(arr, 0, n-1, x) 38 | 39 | if (index == -1): 40 | print("Floor of", x, "doesn't exist\ 41 | in array ", end = "") 42 | else: 43 | print("Floor of", x, "is", arr[index]) -------------------------------------------------------------------------------- /Binary Search/min_diff_element_sorted_array.py: -------------------------------------------------------------------------------- 1 | def findMinDiff(arr, n): 2 | 3 | # Sort array in non-decreasing order 4 | arr = sorted(arr) 5 | 6 | # Initialize difference as infinite 7 | diff = 10**20 8 | 9 | # Find the min diff by comparing adjacent 10 | # pairs in sorted array 11 | for i in range(n-1): 12 | if arr[i+1] - arr[i] < diff: 13 | diff = arr[i+1] - arr[i] 14 | 15 | # Return min diff 16 | return diff 17 | 18 | # Driver code 19 | arr = [1, 5, 3, 19, 18, 25] 20 | n = len(arr) 21 | print("Minimum difference is " + str(findMinDiff(arr, n))) -------------------------------------------------------------------------------- /Binary Search/no. of times rotated.py: -------------------------------------------------------------------------------- 1 | def countRotations(arr): 2 | n = len(arr) 3 | start = 0 4 | end = n-1 5 | 6 | # Finding the index of minimum of the array 7 | # index of min would be equal to number to rotation 8 | while start<=end: 9 | mid = start+(end-start)//2 10 | 11 | # Calculating the previous(prev) 12 | # and next(nex) index of mid 13 | prev = (mid-1+n)%n 14 | nex = (mid+1)%n 15 | 16 | # Checking if mid is minimum 17 | if arr[mid]arr[end]: start = mid+1 24 | else: return 0 25 | 26 | # Driver code 27 | arr = [15, 18, 2, 3, 6, 12] 28 | n = len(arr) 29 | print(countRotations(arr)) -------------------------------------------------------------------------------- /Binary Search/number_of_occurances.py: -------------------------------------------------------------------------------- 1 | def count(arr, x, n): 2 | 3 | # get the index of first 4 | # occurrence of x 5 | i = first(arr, 0, n-1, x, n) 6 | 7 | # If x doesn't exist in 8 | # arr[] then return -1 9 | if i == -1: 10 | return i 11 | 12 | # Else get the index of last occurrence 13 | # of x. Note that we are only looking 14 | # in the subarray after first occurrence 15 | j = last(arr, i, n-1, x, n); 16 | 17 | # return count 18 | return j-i+1; 19 | 20 | # if x is present in arr[] then return 21 | # the index of FIRST occurrence of x in 22 | # arr[0..n-1], otherwise returns -1 23 | def first(arr, low, high, x, n): 24 | if high >= low: 25 | 26 | # low + (high - low)/2 27 | mid = (low + high)//2 28 | 29 | if (mid == 0 or x > arr[mid-1]) and arr[mid] == x: 30 | return mid 31 | elif x > arr[mid]: 32 | return first(arr, (mid + 1), high, x, n) 33 | else: 34 | return first(arr, low, (mid -1), x, n) 35 | return -1; 36 | 37 | # if x is present in arr[] then return 38 | # the index of LAST occurrence of x 39 | # in arr[0..n-1], otherwise returns -1 40 | def last(arr, low, high, x, n): 41 | if high >= low: 42 | 43 | # low + (high - low)/2 44 | mid = (low + high)//2; 45 | 46 | if(mid == n-1 or x < arr[mid+1]) and arr[mid] == x : 47 | return mid 48 | elif x < arr[mid]: 49 | return last(arr, low, (mid -1), x, n) 50 | else: 51 | return last(arr, (mid + 1), high, x, n) 52 | return -1 53 | 54 | # driver program to test above functions 55 | arr = [1, 2, 2, 3, 3, 3, 3] 56 | x = 3 # Element to be counted in arr[] 57 | n = len(arr) 58 | c = count(arr, x, n) 59 | print ("%d occurs %d times "%(x, c)) -------------------------------------------------------------------------------- /Binary Search/occurs_only_once.py: -------------------------------------------------------------------------------- 1 | def search(arr, n) : 2 | 3 | XOR = 0 4 | for i in range(n) : 5 | XOR = XOR ^ arr[i] 6 | 7 | print("The required element is", XOR) 8 | 9 | # Driver code 10 | arr = [ 1, 1, 2, 4, 4, 5, 5, 6, 6 ] 11 | Len = len(arr) 12 | 13 | search(arr, Len) -------------------------------------------------------------------------------- /Binary Search/order_agnostic_BS.py: -------------------------------------------------------------------------------- 1 | def orderagnosticBS(arr, l, r, x): 2 | 3 | isAscending = arr[l] < arr[r] 4 | 5 | while l <= r: 6 | mid = l + (r - l)//2 7 | if (arr[mid] == x): 8 | return mid 9 | 10 | if (isAscending == True): 11 | if (arr[mid] < x): 12 | l = mid + 1 13 | else:r = mid - 1 14 | 15 | else: 16 | if (arr[mid] > x): 17 | l = mid+1 18 | else: r = mid - 1 19 | 20 | return -1 21 | 22 | arr = [50,40,5,3,2] 23 | n = len(arr) 24 | x = 1 25 | print(orderagnosticBS(arr,0,n-1,x)) 26 | -------------------------------------------------------------------------------- /Binary Search/peak_element_sorted_array.py: -------------------------------------------------------------------------------- 1 | def findPeak(arr, n): 2 | 3 | l = 0 4 | r = n-1 5 | 6 | while(l <= r): 7 | 8 | # finding mid by binary right shifting. 9 | mid = (l + r) >> 1 10 | 11 | # first case if mid is the answer 12 | if((mid == 0 or arr[mid - 1] <= arr[mid]) and (mid == n - 1 or arr[mid + 1] <= arr[mid])): 13 | break 14 | 15 | # move the right pointer 16 | if(mid > 0 and arr[mid - 1] > arr[mid]): 17 | r = mid - 1 18 | 19 | # move the left pointer 20 | else: 21 | l = mid + 1 22 | 23 | return mid 24 | 25 | 26 | # Driver Code 27 | arr = [1, 3, 20, 4, 1, 0] 28 | n = len(arr) 29 | print(f"Index of a peak point is {findPeak(arr, n)}") -------------------------------------------------------------------------------- /Binary Search/pos_element_sorted_infinite_array.py: -------------------------------------------------------------------------------- 1 | def binary_search(arr,l,r,x): 2 | 3 | if r >= l: 4 | mid = l+(r-l)//2 5 | 6 | if arr[mid] == x: 7 | return mid 8 | 9 | if arr[mid] > x: 10 | return binary_search(arr,l,mid-1,x) 11 | 12 | return binary_search(arr,mid+1,r,x) 13 | 14 | return -1 15 | 16 | # function takes an infinite size array and a key to be 17 | # searched and returns its position if found else -1. 18 | # We don't know size of a[] and we can assume size to be 19 | # infinite in this function. 20 | # NOTE THAT THIS FUNCTION ASSUMES a[] TO BE OF INFINITE SIZE 21 | # THEREFORE, THERE IS NO INDEX OUT OF BOUND CHECKING 22 | def findPos(a, key): 23 | 24 | l, h, val = 0, 1, arr[0] 25 | 26 | # Find h to do binary search 27 | while val < key: 28 | l = h #store previous high 29 | h = 2*h #double high index 30 | val = arr[h] #update new val 31 | 32 | # at this point we have updated low and high indices, 33 | # thus use binary search between them 34 | return binary_search(a, l, h, key) 35 | 36 | # Driver function 37 | arr = [3, 5, 7, 9, 10, 90, 100, 130, 140, 160, 170] 38 | ans = findPos(arr,10) 39 | if ans == -1: 40 | print ("Element not found") 41 | else: 42 | print("Element found at index",ans) -------------------------------------------------------------------------------- /Binary Search/row-col-wise_sorted_matrix.py: -------------------------------------------------------------------------------- 1 | def search(mat, n, x): 2 | 3 | i = 0 4 | 5 | # set indexes for top right element 6 | j = n - 1 7 | while ( i < n and j >= 0 ): 8 | 9 | if (mat[i][j] == x ): 10 | 11 | print("Element found at ", i, ", ", j) 12 | return 1 13 | 14 | if (mat[i][j] > x ): 15 | j -= 1 16 | 17 | # if mat[i][j] < x 18 | else: 19 | i += 1 20 | 21 | print("Element not found") 22 | return 0 # if (i == n || j == -1 ) 23 | 24 | # Driver Code 25 | mat = [ [10, 20, 30, 40], 26 | [15, 25, 35, 45], 27 | [27, 29, 37, 48], 28 | [32, 33, 39, 50] ] 29 | search(mat, 4, 29) -------------------------------------------------------------------------------- /Binary Search/search_nearly_sorted_array.py: -------------------------------------------------------------------------------- 1 | def binarySearch(arr, l, r, x): 2 | 3 | if (r >= l): 4 | 5 | mid = int(l + (r - l) / 2) 6 | 7 | # If the element is present at one 8 | # of the middle 3 positions 9 | if (arr[mid] == x): return mid 10 | if (mid > l and arr[mid - 1] == x): 11 | return (mid - 1) 12 | if (mid < r and arr[mid + 1] == x): 13 | return (mid + 1) 14 | 15 | # If element is smaller than mid, then 16 | # it can only be present in left subarray 17 | if (arr[mid] > x): 18 | return binarySearch(arr, l, mid - 2, x) 19 | 20 | # Else the element can only 21 | # be present in right subarray 22 | return binarySearch(arr, mid + 2, r, x) 23 | 24 | # We reach here when element 25 | # is not present in array 26 | return -1 27 | 28 | # Driver Code 29 | arr = [3, 2, 10, 4, 40] 30 | n = len(arr) 31 | x = 4 32 | result = binarySearch(arr, 0, n - 1, x) 33 | if (result == -1): 34 | print("Element is not present in array") 35 | else: 36 | print("Element is present at index", result) -------------------------------------------------------------------------------- /Binary Search/searching_in_bitonic_array.py: -------------------------------------------------------------------------------- 1 | # Function for binary search in ascending part 2 | def ascendingBinarySearch(arr, low, high, key): 3 | 4 | while low <= high: 5 | mid = low + (high - low) // 2 6 | 7 | if arr[mid] == key: 8 | return mid 9 | 10 | if arr[mid] > key: 11 | high = mid - 1 12 | else: 13 | low = mid + 1 14 | 15 | return -1 16 | 17 | # Function for binary search in descending part of array 18 | def descendingBinarySearch(arr, low, high, key): 19 | 20 | while low <= high: 21 | mid = low + (high - low) // 2 22 | 23 | if arr[mid] == key: 24 | return mid 25 | 26 | if arr[mid] < key: 27 | high = mid - 1 28 | else: 29 | low = mid + 1 30 | 31 | return -1 32 | 33 | # Find bitonic point 34 | def findBitonicPoint(arr, n, l, r): 35 | 36 | bitonicPoint = 0 37 | mid = (r + l) // 2 38 | 39 | if arr[mid] > arr[mid-1] and arr[mid] > arr[mid+1]: 40 | return mid 41 | 42 | elif arr[mid] > arr[mid-1] and arr[mid] < arr[mid+1]: 43 | bitonicPoint = findBitonicPoint(arr, n, mid, r) 44 | else: 45 | bitonicPoint = findBitonicPoint(arr, n, l, mid) 46 | 47 | return bitonicPoint 48 | 49 | # Function to search key in bitonic array 50 | def searchBitonic(arr, n, key, index): 51 | 52 | if key > arr[index]: 53 | return -1 54 | elif key == arr[index]: 55 | return index 56 | else: 57 | temp = ascendingBinarySearch(arr, 0, index-1, key) 58 | if temp != -1: 59 | return temp 60 | 61 | # search in right of k 62 | return descendingBinarySearch(arr, index+1, n-1, key) 63 | 64 | # Driver code 65 | def main(): 66 | arr = [-8, 1, 2, 3, 4, 5, -2, -3] 67 | key = 1 68 | n = len(arr) 69 | l = 0 70 | r = n - 1 71 | 72 | # Function call 73 | index = findBitonicPoint(arr, n, l, r) 74 | 75 | x = searchBitonic(arr, n, key, index) 76 | 77 | if x == -1: 78 | print("Element Not Found") 79 | else: 80 | print("Element Found at index", x) 81 | 82 | main() 83 | 84 | -------------------------------------------------------------------------------- /Binary Search/smallest_alphabet_greater_than_a_character.py: -------------------------------------------------------------------------------- 1 | def nextGreatestAlphabet(alphabets, K): 2 | 3 | n = len(alphabets) 4 | if(K >= alphabets[n-1]): 5 | return alphabets[0] 6 | l = 0 7 | r = len(alphabets) - 1 8 | ans = -1 9 | # Take the first element as l and 10 | # the rightmost element as r 11 | while (l <= r): 12 | 13 | # if this while condition does 14 | # not satisfy simply return the 15 | # first element. 16 | mid = int((l + r) / 2) 17 | 18 | if (alphabets[mid] > K): 19 | r = mid - 1 20 | ans = mid 21 | else: 22 | l = mid + 1 23 | 24 | # Return the smallest element 25 | if (alphabets[ans] < K): 26 | return alphabets[0] 27 | else: 28 | return alphabets[ans] 29 | 30 | 31 | # Driver Code 32 | letters = ['A', 'r', 'z'] 33 | K = 'z' 34 | 35 | # Function call 36 | result = nextGreatestAlphabet(letters, K) 37 | print(result) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PLACEMENT-DSA 2 | Set of most asked DSA questions and Python Solutions 3 | -------------------------------------------------------------------------------- /Recursion/Josephus_problem.py: -------------------------------------------------------------------------------- 1 | def josephus(n, k): 2 | 3 | if (n == 1): 4 | return 1 5 | else: 6 | 7 | return (josephus(n - 1, k) + k-1) % n + 1 8 | 9 | n = 14 10 | k = 2 11 | 12 | print("The chosen place is ", josephus(n, k)) -------------------------------------------------------------------------------- /Recursion/Kth_symbol.py: -------------------------------------------------------------------------------- 1 | class Solution: 2 | def kthGrammar(self, n: int, k: int) -> int: 3 | return bin(k-1).count('1') % 2 -------------------------------------------------------------------------------- /Recursion/N-bit_binary_more_ones.py: -------------------------------------------------------------------------------- 1 | def printRec(number, extraOnes, remainingPlaces): 2 | 3 | # if number generated 4 | if (0 == remainingPlaces): 5 | print(number, end=" ") 6 | return 7 | 8 | # Append 1 at the current number and 9 | # reduce the remaining places by one 10 | printRec(number + "1", extraOnes + 1, 11 | remainingPlaces - 1) 12 | 13 | # If more ones than zeros, append 0 to 14 | # the current number and reduce the 15 | # remaining places by one 16 | if (0 < extraOnes): 17 | printRec(number + "0", extraOnes - 1, 18 | remainingPlaces - 1) 19 | 20 | 21 | def printNums(n): 22 | str = "" 23 | printRec(str, 0, n) 24 | 25 | 26 | # Driver Code 27 | if __name__ == '__main__': 28 | n = 4 29 | 30 | # Function call 31 | printNums(n) -------------------------------------------------------------------------------- /Recursion/all_subsequence.py: -------------------------------------------------------------------------------- 1 | def printSubsequence(input, output): 2 | # Base Case 3 | if len(input) == 0: 4 | print(output, end=' ') 5 | return 6 | 7 | printSubsequence(input[1:], output+input[0]) 8 | 9 | printSubsequence(input[1:], output) 10 | 11 | output = "" 12 | input = "abcd" 13 | 14 | printSubsequence(input, output) -------------------------------------------------------------------------------- /Recursion/delete_mid_ele_stack.py: -------------------------------------------------------------------------------- 1 | class Stack: 2 | def __init__(self): 3 | self.items = [] 4 | 5 | def isEmpty(self): 6 | return self.items == [] 7 | 8 | def push(self, item): 9 | self.items.append(item) 10 | 11 | def pop(self): 12 | return self.items.pop() 13 | 14 | def peek(self): 15 | return self.items[len(self.items)-1] 16 | 17 | def size(self): 18 | return len(self.items) 19 | 20 | def deleteMid(st, n, curr) : 21 | 22 | # If stack is empty or all items 23 | # are traversed 24 | if (st.isEmpty() or curr == n) : 25 | return 26 | 27 | # Remove current item 28 | x = st.peek() 29 | st.pop() 30 | 31 | # Remove other items 32 | deleteMid(st, n, curr+1) 33 | 34 | # Put all items back except middle 35 | if (curr != int(n/2)) : 36 | st.push(x) 37 | 38 | # Driver function to test above functions 39 | st = Stack() 40 | 41 | # push elements into the stack 42 | st.push('1') 43 | st.push('2') 44 | st.push('3') 45 | st.push('4') 46 | st.push('5') 47 | st.push('6') 48 | st.push('7') 49 | 50 | 51 | 52 | deleteMid(st, st.size(), 0) 53 | 54 | # Printing stack after deletion of middle element. 55 | while (st.isEmpty() == False) : 56 | p = st.peek() 57 | st.pop() 58 | print (str(p) + " ", end="") -------------------------------------------------------------------------------- /Recursion/generate_all_balanced_paranthesis.py: -------------------------------------------------------------------------------- 1 | def printParenthesis(str, n): 2 | if(n > 0): 3 | _printParenthesis(str, 0, 4 | n, 0, 0) 5 | return 6 | 7 | 8 | def _printParenthesis(str, pos, n, 9 | open, close): 10 | 11 | if(close == n): 12 | for i in str: 13 | print(i, end="") 14 | print() 15 | return 16 | else: 17 | if(open > close): 18 | str[pos] = '}' 19 | _printParenthesis(str, pos + 1, n, 20 | open, close + 1) 21 | if(open < n): 22 | str[pos] = '{' 23 | _printParenthesis(str, pos + 1, n, 24 | open + 1, close) 25 | 26 | 27 | # Driver Code 28 | n = 3 29 | str = [""] * 2 * n 30 | printParenthesis(str, n) -------------------------------------------------------------------------------- /Recursion/height_of_BT.py: -------------------------------------------------------------------------------- 1 | class Node: 2 | 3 | # Constructor to create a new node 4 | def __init__(self, data): 5 | self.data = data 6 | self.left = None 7 | self.right = None 8 | 9 | # Compute the "maxDepth" of a tree -- the number of nodes 10 | # along the longest path from the root node down to the 11 | # farthest leaf node 12 | def maxDepth(node): 13 | if node is None: 14 | return 0 15 | 16 | else : 17 | 18 | # Compute the depth of each subtree 19 | lDepth = maxDepth(node.left) 20 | rDepth = maxDepth(node.right) 21 | 22 | # Use the larger one 23 | return 1 + max(lDepth,rDepth) 24 | 25 | 26 | # Driver program to test above function 27 | root = Node(1) 28 | root.left = Node(2) 29 | root.right = Node(3) 30 | root.left.left = Node(4) 31 | root.left.right = Node(5) 32 | 33 | 34 | print ("Height of tree is %d" %(maxDepth(root))) -------------------------------------------------------------------------------- /Recursion/letter_case_perm.py: -------------------------------------------------------------------------------- 1 | def permute(ip, op): 2 | 3 | # base case 4 | if len(ip) == 0: 5 | print(op, end=" ") 6 | return 7 | 8 | # pick lower and uppercase 9 | ch = ip[0].lower() 10 | ch2 = ip[0].upper() 11 | ip = ip[1:] 12 | permute(ip, op+ch) 13 | permute(ip, op+ch2) 14 | 15 | # driver code 16 | def main(): 17 | ip = "AB" 18 | permute(ip, "") 19 | 20 | main() -------------------------------------------------------------------------------- /Recursion/perm_with_spaces.py: -------------------------------------------------------------------------------- 1 | def toString(List): 2 | s = "" 3 | for x in List: 4 | if x == '&# 092;&# 048;': 5 | break 6 | s += x 7 | return s 8 | 9 | def printPatternUtil(string, buff, i, j, n): 10 | 11 | if i == n: 12 | buff[j] = '&# 092;&# 048;' 13 | print (toString(buff)) 14 | return 15 | 16 | # Either put the character 17 | buff[j] = string[i] 18 | printPatternUtil(string, buff, i + 1, 19 | j + 1, n) 20 | 21 | # Or put a space followed by next character 22 | buff[j] = ' ' 23 | buff[j + 1] = string[i] 24 | 25 | printPatternUtil(string, buff, i + 1, j + 2, n) 26 | 27 | def printPattern(string): 28 | n = len(string) 29 | 30 | buff = [0] * (2 * n) 31 | 32 | buff[0] = string[0] 33 | 34 | printPatternUtil(string, buff, 1, 1, n) 35 | 36 | # Driver program 37 | string = "ABCD" 38 | printPattern(string) -------------------------------------------------------------------------------- /Recursion/permutation_with_case_change.py: -------------------------------------------------------------------------------- 1 | def permute(ip, op): 2 | 3 | # base case 4 | if len(ip) == 0: 5 | print(op, end=" ") 6 | return 7 | 8 | # pick lower and uppercase 9 | ch1 = ip[0].lower() 10 | ch2 = ip[0].upper() 11 | ip = ip[1:] 12 | permute(ip, op+ch1) 13 | permute(ip, op+ch2) 14 | 15 | # driver code 16 | def main(): 17 | ip = "AB" 18 | permute(ip, "") 19 | 20 | main() -------------------------------------------------------------------------------- /Recursion/powerset.py: -------------------------------------------------------------------------------- 1 | def powerSet(str1, index, curr): 2 | n = len(str1) 3 | 4 | # base case 5 | if (index == n): 6 | return 7 | 8 | # First print current subset 9 | print(curr) 10 | 11 | # Try appending remaining characters 12 | # to current subset 13 | for i in range(index + 1, n): 14 | curr += str1[i] 15 | powerSet(str1, i, curr) 16 | 17 | # Once all subsets beginning with 18 | # initial "curr" are printed, remove 19 | # last character to consider a different 20 | # prefix of subsets. 21 | curr = curr.replace(curr[len(curr) - 1], "") 22 | 23 | return 24 | 25 | # Driver code 26 | if __name__ == '__main__': 27 | str = "abc" 28 | powerSet(str, -1, "") 29 | -------------------------------------------------------------------------------- /Recursion/reverse_stack.py: -------------------------------------------------------------------------------- 1 | def insertAtBottom(stack, item): 2 | if isEmpty(stack): 3 | push(stack, item) 4 | else: 5 | temp = pop(stack) 6 | insertAtBottom(stack, item) 7 | push(stack, temp) 8 | 9 | # Below is the function that reverses the given stack using insertAtBottom() 10 | def reverse(stack): 11 | if not isEmpty(stack): 12 | temp = pop(stack) 13 | reverse(stack) 14 | insertAtBottom(stack, temp) 15 | 16 | def createStack(): 17 | stack = [] 18 | return stack 19 | 20 | # Function to check if the stack is empty 21 | def isEmpty( stack ): 22 | return len(stack) == 0 23 | 24 | # Function to push an item to stack 25 | def push( stack, item ): 26 | stack.append( item ) 27 | 28 | # Function to pop an item from stack 29 | def pop( stack ): 30 | 31 | # If stack is empty then error 32 | if(isEmpty( stack )): 33 | print("Stack Underflow ") 34 | exit(1) 35 | 36 | return stack.pop() 37 | 38 | # Function to print the stack 39 | def prints(stack): 40 | for i in range(len(stack)-1, -1, -1): 41 | print(stack[i], end = ' ') 42 | print() 43 | 44 | # Driver Code 45 | stack = createStack() 46 | push( stack, str(4) ) 47 | push( stack, str(3) ) 48 | push( stack, str(2) ) 49 | push( stack, str(1) ) 50 | print("Original Stack ") 51 | prints(stack) 52 | 53 | reverse(stack) 54 | 55 | print("Reversed Stack ") 56 | prints(stack) -------------------------------------------------------------------------------- /Recursion/sort_a_stack.py: -------------------------------------------------------------------------------- 1 | def sortedInsert(s, element): 2 | 3 | # Base case: Either stack is empty or newly inserted 4 | # item is greater than top (more than all existing) 5 | if len(s) == 0 or element > s[-1]: 6 | s.append(element) 7 | return 8 | else: 9 | 10 | # Remove the top item and recur 11 | temp = s.pop() 12 | sortedInsert(s, element) 13 | 14 | # Put back the top item removed earlier 15 | s.append(temp) 16 | 17 | # Method to sort stack 18 | 19 | 20 | def sortStack(s): 21 | 22 | # If stack is not empty 23 | if len(s) != 0: 24 | 25 | # Remove the top item 26 | temp = s.pop() 27 | 28 | # Sort remaining stack 29 | sortStack(s) 30 | 31 | # Push the top item back in sorted stack 32 | sortedInsert(s, temp) 33 | 34 | # Printing contents of stack 35 | 36 | 37 | def printStack(s): 38 | for i in s[::-1]: 39 | print(i, end=" ") 40 | print() 41 | 42 | 43 | # Driver Code 44 | if __name__ == '__main__': 45 | s = [] 46 | s.append(30) 47 | s.append(-5) 48 | s.append(18) 49 | s.append(14) 50 | s.append(-3) 51 | 52 | print("Stack elements before sorting: ") 53 | printStack(s) 54 | 55 | sortStack(s) 56 | 57 | print("\nStack elements after sorting: ") 58 | printStack(s) -------------------------------------------------------------------------------- /Recursion/subset.py: -------------------------------------------------------------------------------- 1 | def combinationUtil(arr, n, r, index, data, i): 2 | # Current combination is ready to be printed,print it 3 | if(index == r): 4 | for j in range(r): 5 | print(data[j], end = " ") 6 | print(" ") 7 | return 8 | 9 | # When no more elements are there to put in data[] 10 | if(i >= n): 11 | return 12 | 13 | # current is included, put next at next location 14 | data[index] = arr[i] 15 | combinationUtil(arr, n, r, index + 1, data, i + 1) 16 | 17 | # current is excluded,replace it with next 18 | combinationUtil(arr, n, r, index, data, i + 1) 19 | 20 | def printcombination(arr, n, r): 21 | data = list(range(r)) 22 | combinationUtil(arr, n, r, 0, data, 0) 23 | 24 | 25 | # Driver Code 26 | arr = [10, 20, 30, 40, 50] 27 | r = 3 28 | n = len(arr) 29 | printcombination(arr, n, r) -------------------------------------------------------------------------------- /Recursion/tower_of_Hanoi.py: -------------------------------------------------------------------------------- 1 | def TowerOfHanoi(n , source, destination, auxiliary): 2 | if n==1: 3 | print ("Move disk 1 from source",source,"to destination",destination) 4 | return 5 | TowerOfHanoi(n-1, source, auxiliary, destination) 6 | print ("Move disk",n,"from source",source,"to destination",destination) 7 | TowerOfHanoi(n-1, auxiliary, destination, source) 8 | 9 | # Driver code 10 | n = 4 11 | TowerOfHanoi(n,'A','B','C') -------------------------------------------------------------------------------- /Recursion/unique_subset_variation.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | def printPowerSet(S, i, out=deque()): 3 | 4 | # if all elements are processed, print the current subset 5 | if i < 0: 6 | print(list(out)) 7 | return 8 | 9 | # include the current element in the current subset and recur 10 | out.append(S[i]) 11 | printPowerSet(S, i - 1, out) 12 | 13 | # backtrack: exclude the current element from the current subset 14 | out.pop() 15 | 16 | # remove adjacent duplicate elements 17 | while i > 0 and S[i] == S[i - 1]: 18 | i = i - 1 19 | 20 | # exclude the current element from the current subset and recur 21 | printPowerSet(S, i - 1, out) 22 | 23 | 24 | # Wrapper over `printPowerSet()` function 25 | def findPowerSet(S): 26 | 27 | # sort the set 28 | S.sort() 29 | 30 | # print the power set 31 | printPowerSet(S, len(S) - 1) 32 | 33 | 34 | if __name__ == '__main__': 35 | 36 | S = [1, 3, 1] 37 | 38 | findPowerSet(S) -------------------------------------------------------------------------------- /Stacks/Celebrity Problem.py: -------------------------------------------------------------------------------- 1 | # Python3 code 2 | class Solution: 3 | 4 | # Function to find if there is a celebrity in the party or not. 5 | # return index if celebrity else return -1 6 | def celebrity(self, M, n): 7 | # code here 8 | i = 0 9 | j = n-1 10 | candidate = -1 11 | while(i < j): 12 | if M[j][i] == 1: 13 | j -= 1 14 | else: 15 | i += 1 16 | 17 | candidate = i 18 | for k in range(n): 19 | if candidate != k: 20 | if M[candidate][k] == 1 or M[k][candidate] == 0: 21 | return -1 22 | 23 | return candidate 24 | 25 | 26 | n = 4 27 | m = [[0, 0, 1, 0], 28 | [0, 0, 1, 0], 29 | [0, 0, 0, 0], 30 | [0, 0, 1, 0]] 31 | ob = Solution() 32 | print("Celebrity at index "+str(ob.celebrity(m, n))) 33 | -------------------------------------------------------------------------------- /Stacks/Implement Min Stack.py: -------------------------------------------------------------------------------- 1 | # Class to make a Node 2 | class Node: 3 | # Constructor which assign argument to nade's value 4 | def __init__(self, value): 5 | self.value = value 6 | self.next = None 7 | 8 | # This method returns the string representation of the object. 9 | def __str__(self): 10 | return "Node({})".format(self.value) 11 | 12 | # __repr__ is same as __str__ 13 | __repr__ = __str__ 14 | 15 | 16 | class Stack: 17 | # Stack Constructor initialise top of stack and counter. 18 | def __init__(self): 19 | self.top = None 20 | self.count = 0 21 | self.minimum = None 22 | 23 | # This method returns the string representation of the object (stack). 24 | def __str__(self): 25 | temp = self.top 26 | out = [] 27 | while temp: 28 | out.append(str(temp.value)) 29 | temp = temp.next 30 | out = '\n'.join(out) 31 | return ('Top {} \n\nStack :\n{}'.format(self.top,out)) 32 | 33 | # __repr__ is same as __str__ 34 | __repr__=__str__ 35 | 36 | # This method is used to get minimum element of stack 37 | def getMin(self): 38 | if self.top is None: 39 | return "Stack is empty" 40 | else: 41 | print("Minimum Element in the stack is: {}" .format(self.minimum)) 42 | 43 | 44 | 45 | # Method to check if Stack is Empty or not 46 | def isEmpty(self): 47 | # If top equals to None then stack is empty 48 | if self.top == None: 49 | return True 50 | else: 51 | # If top not equal to None then stack is empty 52 | return False 53 | 54 | # This method returns length of stack 55 | def __len__(self): 56 | self.count = 0 57 | tempNode = self.top 58 | while tempNode: 59 | tempNode = tempNode.next 60 | self.count+=1 61 | return self.count 62 | 63 | # This method returns top of stack 64 | def peek(self): 65 | if self.top is None: 66 | print ("Stack is empty") 67 | else: 68 | if self.top.value < self.minimum: 69 | print("Top Most Element is: {}" .format(self.minimum)) 70 | else: 71 | print("Top Most Element is: {}" .format(self.top.value)) 72 | 73 | # This method is used to add node to stack 74 | def push(self,value): 75 | if self.top is None: 76 | self.top = Node(value) 77 | self.minimum = value 78 | 79 | elif value < self.minimum: 80 | temp = (2 * value) - self.minimum 81 | new_node = Node(temp) 82 | new_node.next = self.top 83 | self.top = new_node 84 | self.minimum = value 85 | else: 86 | new_node = Node(value) 87 | new_node.next = self.top 88 | self.top = new_node 89 | print("Number Inserted: {}" .format(value)) 90 | 91 | # This method is used to pop top of stack 92 | def pop(self): 93 | if self.top is None: 94 | print( "Stack is empty") 95 | else: 96 | removedNode = self.top.value 97 | self.top = self.top.next 98 | if removedNode < self.minimum: 99 | print ("Top Most Element Removed :{} " .format(self.minimum)) 100 | self.minimum = ( ( 2 * self.minimum ) - removedNode ) 101 | else: 102 | print ("Top Most Element Removed : {}" .format(removedNode)) 103 | 104 | 105 | 106 | 107 | # Driver program to test above class 108 | stack = Stack() 109 | 110 | stack.push(3) 111 | stack.push(5) 112 | stack.getMin() 113 | stack.push(2) 114 | stack.push(1) 115 | stack.getMin() 116 | stack.pop() 117 | stack.getMin() 118 | stack.pop() 119 | stack.peek() 120 | 121 | -------------------------------------------------------------------------------- /Stacks/Implement Stack using Heap.py: -------------------------------------------------------------------------------- 1 | class MyStack: 2 | 3 | def __init__(self): 4 | self.queue = [] 5 | 6 | def push(self, x: int) -> None: 7 | self.queue.append(x) 8 | 9 | def pop(self) -> int: 10 | return self.queue.pop() 11 | 12 | 13 | def top(self) -> int: 14 | return self.queue[-1] 15 | 16 | def empty(self) -> bool: 17 | return len(self.queue) == 0 -------------------------------------------------------------------------------- /Stacks/Longest Valid Parenthesis.py: -------------------------------------------------------------------------------- 1 | def solve(s, n): 2 | 3 | # Variables for left and right counter. 4 | # maxlength to store the maximum length found so far 5 | left = 0 6 | right = 0 7 | maxlength = 0 8 | 9 | # Iterating the string from left to right 10 | for i in range(n): 11 | 12 | # If "(" is encountered, 13 | # then left counter is incremented 14 | # else right counter is incremented 15 | if (s[i] == '('): 16 | left += 1 17 | else: 18 | right += 1 19 | 20 | # Whenever left is equal to right, it signifies 21 | # that the subsequence is valid and 22 | if (left == right): 23 | maxlength = max(maxlength, 2 * right) 24 | 25 | # Resetting the counters when the subsequence 26 | # becomes invalid 27 | elif (right > left): 28 | left = right = 0 29 | 30 | left = right = 0 31 | 32 | # Iterating the string from right to left 33 | for i in range(n - 1, -1, -1): 34 | 35 | # If "(" is encountered, 36 | # then left counter is incremented 37 | # else right counter is incremented 38 | if (s[i] == '('): 39 | left += 1 40 | else: 41 | right += 1 42 | 43 | # Whenever left is equal to right, it signifies 44 | # that the subsequence is valid and 45 | if (left == right): 46 | maxlength = max(maxlength, 2 * left) 47 | 48 | # Resetting the counters when the subsequence 49 | # becomes invalid 50 | elif (left > right): 51 | left = right = 0 52 | return maxlength 53 | 54 | 55 | # Driver code 56 | # Function call 57 | print(solve("((()()()()(((())", 16)) 58 | 59 | -------------------------------------------------------------------------------- /Stacks/Max Area Histogram.py: -------------------------------------------------------------------------------- 1 | # Stack logic 2 | class Stack: 3 | def __init__(self): 4 | self.stack = [] 5 | 6 | def is_empty(self): 7 | return len(self.stack) == 0 8 | 9 | def push(self, num): 10 | self.stack.append(num) 11 | 12 | def pop(self): 13 | if self.is_empty(): 14 | raise Exception('Stack Underflow') 15 | return self.stack.pop() 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | return None 20 | return self.stack[-1] 21 | 22 | # ------------------Stack Ends------------------# 23 | 24 | # Nearest smaller to left 25 | def nearest_smaller_to_left(arr): 26 | stack = Stack() 27 | result = [] 28 | 29 | for i in range(0, len(arr)): 30 | if stack.is_empty(): 31 | result.append(-1) 32 | stack.push(arr[i]) 33 | elif not stack.is_empty(): 34 | while(not stack.is_empty() and arr[i] < stack.peek()): 35 | stack.pop() 36 | if stack.is_empty(): 37 | result.append(-1) 38 | else: 39 | result.append(stack.peek()) 40 | stack.push(arr[i]) 41 | 42 | return result 43 | 44 | # Nearest Smaller to Right 45 | def nearest_smaller_to_right(arr): 46 | stack = Stack() 47 | result = [] 48 | 49 | for i in range(len(arr)-1,-1,-1): 50 | if stack.is_empty(): 51 | result.append(-1) 52 | stack.push(arr[i]) 53 | elif not stack.is_empty(): 54 | while(not stack.is_empty() and arr[i] < stack.peek()): 55 | stack.pop() 56 | if stack.is_empty(): 57 | result.append(-1) 58 | else: 59 | result.append(stack.peek()) 60 | stack.push(arr[i]) 61 | result.reverse() 62 | return result 63 | 64 | #--------------------------# 65 | 66 | # Area calculation Logic 67 | def max_area_histogram(arr): 68 | NSL = nearest_smaller_to_left(arr) 69 | NSR = nearest_smaller_to_right(arr) 70 | 71 | width = [] 72 | for i in range(0, len(arr)): 73 | width.append(NSR[i] - NSL[i] - 1) 74 | 75 | area = [] 76 | for i in range(0, len(arr)): 77 | area.append(arr[i]*width[i]) 78 | 79 | return max(area) 80 | 81 | 82 | # Print statement 83 | arr = [6,2,5,4,5,1,6] 84 | print(max_area_histogram(arr)) -------------------------------------------------------------------------------- /Stacks/Max Area Rectangle Binary Matrix.py: -------------------------------------------------------------------------------- 1 | class Solution(): 2 | def maxHist(self, row): 3 | # Create an empty stack. The stack holds 4 | # indexes of hist array / The bars stored 5 | # in stack are always in increasing order 6 | # of their heights. 7 | result = [] 8 | 9 | # Top of stack 10 | top_val = 0 11 | 12 | # Initialize max area in current 13 | max_area = 0 14 | # row (or histogram) 15 | 16 | area = 0 # Initialize area with current top 17 | 18 | # Run through all bars of given 19 | # histogram (or row) 20 | i = 0 21 | while (i < len(row)): 22 | 23 | # If this bar is higher than the 24 | # bar on top stack, push it to stack 25 | if (len(result) == 0) or (row[result[-1]] <= row[i]): 26 | result.append(i) 27 | i += 1 28 | else: 29 | 30 | # If this bar is lower than top of stack, 31 | # then calculate area of rectangle with 32 | # stack top as the smallest (or minimum 33 | # height) bar. 'i' is 'right index' for 34 | # the top and element before top in stack 35 | # is 'left index' 36 | top_val = row[result.pop()] 37 | area = top_val * i 38 | 39 | if (len(result)): 40 | area = top_val * (i - result[-1] - 1) 41 | max_area = max(area, max_area) 42 | 43 | # Now pop the remaining bars from stack 44 | # and calculate area with every popped 45 | # bar as the smallest bar 46 | while (len(result)): 47 | top_val = row[result.pop()] 48 | area = top_val * i 49 | if (len(result)): 50 | area = top_val * (i - result[-1] - 1) 51 | 52 | max_area = max(area, max_area) 53 | 54 | return max_area 55 | 56 | # Returns area of the largest rectangle 57 | # with all 1s in A 58 | def maxRectangle(self, A): 59 | 60 | # Calculate area for first row and 61 | # initialize it as result 62 | result = self.maxHist(A[0]) 63 | 64 | # iterate over row to find maximum rectangular 65 | # area considering each row as histogram 66 | for i in range(1, len(A)): 67 | 68 | for j in range(len(A[i])): 69 | 70 | # if A[i][j] is 1 then add A[i -1][j] 71 | if (A[i][j]): 72 | A[i][j] += A[i - 1][j] 73 | 74 | # Update result if area with current 75 | # row (as last row) of rectangle) is more 76 | result = max(result, self.maxHist(A[i])) 77 | 78 | return result 79 | 80 | 81 | # Driver Code 82 | if __name__ == '__main__': 83 | A = [[0, 1, 1, 0], 84 | [1, 1, 1, 1], 85 | [1, 1, 1, 1], 86 | [1, 1, 0, 0]] 87 | ans = Solution() 88 | 89 | print("Area of maximum rectangle is", 90 | ans.maxRectangle(A)) 91 | 92 | -------------------------------------------------------------------------------- /Stacks/Nearest Greater to Left.py: -------------------------------------------------------------------------------- 1 | # Stack logic 2 | class Stack: 3 | def __init__(self): 4 | self.stack = [] 5 | 6 | def is_empty(self): 7 | return len(self.stack) == 0 8 | 9 | def push(self, num): 10 | self.stack.append(num) 11 | 12 | def pop(self): 13 | if self.is_empty(): 14 | raise Exception('Stack Underflow') 15 | return self.stack.pop() 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | return None 20 | return self.stack[-1] 21 | 22 | # ------------------Stack Ends------------------# 23 | 24 | # Problem solving logic 25 | def nearest_greater_to_left(arr): 26 | stack = Stack() 27 | result = [] 28 | 29 | for i in range(0, len(arr)): 30 | if stack.is_empty(): 31 | result.append(-1) 32 | stack.push(arr[i]) 33 | elif not stack.is_empty(): 34 | while(not stack.is_empty() and arr[i] > stack.peek()): 35 | stack.pop() 36 | if stack.is_empty(): 37 | result.append(-1) 38 | else: 39 | result.append(stack.peek()) 40 | stack.push(arr[i]) 41 | 42 | return result 43 | 44 | #-----------Problem logic ends---------------# 45 | 46 | #Output and function call 47 | arr = [1, 6, 4, 10, 2, 5] 48 | print(nearest_greater_to_left(arr)) -------------------------------------------------------------------------------- /Stacks/Nearest Greater to Right.py: -------------------------------------------------------------------------------- 1 | # Stack logic 2 | class Stack: 3 | def __init__(self): 4 | self.stack = [] 5 | 6 | def is_empty(self): 7 | return len(self.stack) == 0 8 | 9 | def push(self, num): 10 | self.stack.append(num) 11 | 12 | def pop(self): 13 | if self.is_empty(): 14 | raise Exception('Stack Underflow') 15 | return self.stack.pop() 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | return None 20 | return self.stack[-1] 21 | 22 | # ------------------Stack Ends------------------# 23 | 24 | # Problem solving logic 25 | def nearest_greater_to_right(arr): 26 | stack = Stack() 27 | result = [] 28 | 29 | for i in range(len(arr)-1,-1,-1): 30 | if stack.is_empty(): 31 | result.append(-1) 32 | stack.push(arr[i]) 33 | elif not stack.is_empty(): 34 | while(not stack.is_empty() and arr[i] > stack.peek()): 35 | stack.pop() 36 | if stack.is_empty(): 37 | result.append(-1) 38 | else: 39 | result.append(stack.peek()) 40 | stack.push(arr[i]) 41 | result.reverse() 42 | return result 43 | 44 | #-----------Problem logic ends---------------# 45 | 46 | #Output and function call 47 | arr = [1, 13, 21, 3] 48 | print(nearest_greater_to_right(arr)) -------------------------------------------------------------------------------- /Stacks/Nearest Smaller to Left.py: -------------------------------------------------------------------------------- 1 | # Stack logic 2 | class Stack: 3 | def __init__(self): 4 | self.stack = [] 5 | 6 | def is_empty(self): 7 | return len(self.stack) == 0 8 | 9 | def push(self, num): 10 | self.stack.append(num) 11 | 12 | def pop(self): 13 | if self.is_empty(): 14 | raise Exception('Stack Underflow') 15 | return self.stack.pop() 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | return None 20 | return self.stack[-1] 21 | 22 | # ------------------Stack Ends------------------# 23 | 24 | # Problem solving logic 25 | def nearest_smaller_to_left(arr): 26 | stack = Stack() 27 | result = [] 28 | 29 | for i in range(0, len(arr)): 30 | if stack.is_empty(): 31 | result.append(-1) 32 | stack.push(arr[i]) 33 | elif not stack.is_empty(): 34 | while(not stack.is_empty() and arr[i] < stack.peek()): 35 | stack.pop() 36 | if stack.is_empty(): 37 | result.append(-1) 38 | else: 39 | result.append(stack.peek()) 40 | stack.push(arr[i]) 41 | 42 | return result 43 | 44 | #-----------Problem logic ends---------------# 45 | 46 | #Output and function call 47 | arr = [1, 6, 4, 10, 2, 5] 48 | print(nearest_smaller_to_left(arr)) -------------------------------------------------------------------------------- /Stacks/Nearest Smaller to Right.py: -------------------------------------------------------------------------------- 1 | # Stack logic 2 | class Stack: 3 | def __init__(self): 4 | self.stack = [] 5 | 6 | def is_empty(self): 7 | return len(self.stack) == 0 8 | 9 | def push(self, num): 10 | self.stack.append(num) 11 | 12 | def pop(self): 13 | if self.is_empty(): 14 | raise Exception('Stack Underflow') 15 | return self.stack.pop() 16 | 17 | def peek(self): 18 | if self.is_empty(): 19 | return None 20 | return self.stack[-1] 21 | 22 | # ------------------Stack Ends------------------# 23 | 24 | # Problem solving logic 25 | def nearest_smaller_to_right(arr): 26 | stack = Stack() 27 | result = [] 28 | 29 | for i in range(len(arr)-1,-1,-1): 30 | if stack.is_empty(): 31 | result.append(-1) 32 | stack.push(arr[i]) 33 | elif not stack.is_empty(): 34 | while(not stack.is_empty() and arr[i] < stack.peek()): 35 | stack.pop() 36 | if stack.is_empty(): 37 | result.append(-1) 38 | else: 39 | result.append(stack.peek()) 40 | stack.push(arr[i]) 41 | result.reverse() 42 | return result 43 | 44 | #-----------Problem logic ends---------------# 45 | 46 | #Output and function call 47 | arr = [1, 13, 21, 3] 48 | print(nearest_smaller_to_right(arr)) -------------------------------------------------------------------------------- /Stacks/Rain Water Trapping.py: -------------------------------------------------------------------------------- 1 | from math import dist 2 | from turtle import distance 3 | 4 | 5 | def maxWater(height): 6 | stack = [] 7 | n = len(height) 8 | ans = 0 9 | for i in range(n): 10 | while (len(stack)!=0 and (height[stack[-1]] < height[i])): 11 | pop_height = height[stack[-1]] 12 | stack.pop() 13 | if len(stack) == 0: 14 | break 15 | 16 | distance = i - stack[-1] - 1 17 | min_height = min(height[stack[-1]],height[i]) - pop_height 18 | 19 | ans += distance * min_height 20 | stack.append(i) 21 | return ans 22 | 23 | arr = [0,1,0,2,1,0,1,3,2,1,2,1] 24 | print(maxWater(arr)) -------------------------------------------------------------------------------- /Stacks/Stock Span Problem.py: -------------------------------------------------------------------------------- 1 | # Stock Span Problem 2 | 3 | def span(rates): 4 | stockspan = [] 5 | stack = [] 6 | 7 | stockspan.append(1) 8 | stack.append(0) 9 | 10 | for i in range(1,len(rates)): 11 | while rates[i] > rates[stack[-1]]: 12 | stack.pop() 13 | 14 | if len(stack) == 0: 15 | break 16 | 17 | if len(stack) > 0: 18 | stockspan.append(i - stack[-1]) 19 | else: 20 | stockspan.append(i+1) 21 | 22 | stack.append(i) 23 | return stockspan 24 | 25 | rates = [31,27,14,21,30,22] 26 | stockspan = span(rates) 27 | print(stockspan) 28 | 29 | 30 | --------------------------------------------------------------------------------