├── Algorithm Data Structures Python ├── .gitignore ├── Algorithms │ ├── Bubble_sort.py │ ├── Count_inversion.py │ ├── Dselect.py │ ├── Insertion_sort.py │ ├── MergeSort.py │ ├── QuickSelect-1.py │ ├── Quicksort-1.py │ ├── Quicksort-2.py │ ├── Quicksort_InPlac2.py │ ├── Quicksort_InPlace.py │ ├── Random_Select_InPlace.py │ └── Selection_sort.py ├── Data Structures │ ├── Common_data_structures_class.py │ ├── Common_data_structures_test.py │ ├── Graph-1.py │ ├── Graph1.py │ ├── Graphs-1.ipynb │ ├── LinkedList-test.py │ ├── LinkedList.ipynb │ ├── LinkedList.py │ ├── Misc Data Structures.ipynb │ ├── Stack-Queue-using-List.py │ ├── Stack-using-LinkedList.ipynb │ └── Trees_class.py ├── LICENSE └── README.md ├── Coursera Python Data Structures University of Michigan ├── Assignments │ ├── Assignment 10.2.py │ ├── Assignment 2.2.py │ ├── Assignment 2.3.py │ ├── Assignment 3.1.py │ ├── Assignment 5.2.py │ ├── Assignment 6.5.py │ ├── Assignment 7.1.py │ ├── Assignment 7.2.py │ ├── Assignment 8.4.py │ ├── Assignment 8.5.py │ ├── Assignment 9.4.py │ ├── mbox-short.txt │ ├── romeo.txt │ └── words.txt ├── Quizzes │ ├── Chapter 10 Quiz.txt │ ├── Chapter 6 Quiz.txt │ ├── Chapter 7 Quiz.doc │ ├── Chapter 8 Quiz.md │ └── Chapter 9 Quiz.txt └── README.md ├── Data Structures and Algorithms Python ├── .gitignore ├── 01. Resources │ ├── BigO-cheat-sheet.pdf │ ├── Books │ │ ├── Data Structures - Reema Thareja.pdf │ │ └── competitiveCoding.pdf │ ├── DAA Syllabus.pdf │ ├── Interview cheatsheet.pdf │ ├── Master Plan.pdf │ └── Master_the_Interview.pdf ├── 02. Big-O │ ├── O(1).py │ ├── O(m + n).py │ ├── O(m x n).py │ ├── O(n).py │ └── O(n^2).py ├── 03. Data Structures │ ├── Arrays │ │ ├── Contains_Duplicate.py │ │ ├── Implementation.py │ │ ├── Introduction.py │ │ ├── Longest_Word.py │ │ ├── Maximum_SubArray.py │ │ ├── Merging_sorted_arrays.py │ │ ├── Move_Zeroes.py │ │ ├── Reversing_String.py │ │ └── Rotate_Array.py │ ├── Graphs │ │ └── Undirected_Graph_Implementation.py │ ├── Hash Tables │ │ ├── First_Recurring_Character.py │ │ ├── Implementation.py │ │ ├── Introduction.py │ │ ├── Legacy │ │ │ └── hash_algo.py │ │ └── Pattern_Matching.py │ ├── Linked Lists │ │ ├── Doubly_Linked_Lists.py │ │ ├── Implementation.py │ │ ├── Legacy │ │ │ └── linked_list_template.py │ │ └── Reverse.py │ ├── Queues │ │ ├── Legacy │ │ │ └── queue_demo.py │ │ ├── Linked_List_Implementation.py │ │ └── Queue_Using_Stacks.py │ ├── Stacks │ │ ├── Array_Implementation.py │ │ ├── Legacy │ │ │ └── stack_demo.py │ │ └── Linked_List_Implementation.py │ └── Trees │ │ ├── Binary_Search_Tree.py │ │ ├── Heap.py │ │ ├── Legacy │ │ └── bst_demo.py │ │ ├── Priority_Queues_Using_Heap.py │ │ └── Trie.py ├── 04. Algorithms │ ├── Divide and Conquer │ │ └── karatsuba_multiplication.py │ ├── Dynamic Programming │ │ ├── Fibonacci.py │ │ └── Memoization.py │ ├── Recursion │ │ ├── Factorial.py │ │ ├── Fibonacci.py │ │ └── Reverse_String.py │ ├── Searching │ │ └── Alt_Binary_Search.py │ ├── Sorting │ │ ├── Bubble_Sort.py │ │ ├── Heap_Sort.py │ │ ├── Insertion_Sort.py │ │ ├── Merge_Sort.py │ │ ├── Quick_Sort.py │ │ ├── Selection_Sort.py │ │ └── legacy │ │ │ ├── bubble_sort.py │ │ │ ├── insertion_sort.py │ │ │ ├── merge_sort.py │ │ │ ├── quick_sort.py │ │ │ └── selection_sort.py │ └── Traversals │ │ ├── BFS.py │ │ ├── DFS.py │ │ ├── bisection_iter.py │ │ └── bisection_recur.py ├── 05. File Handling and OOPS │ ├── data.txt │ └── file+classes.py ├── 06. Error Handling │ ├── error_handling.py │ ├── error_handling2.py │ ├── raise_error.py │ └── raise_error2.py ├── 07. Functional Programming │ ├── dict_comprehension.py │ ├── enumerate.py │ ├── filter().py │ ├── lambda_expressions.py │ ├── lambda_expressions2.py │ ├── list_set_comprehension.py │ ├── map().py │ ├── pure_functions.py │ ├── reduce().py │ └── zip().py ├── 08. Decorators │ ├── HOC.py │ ├── authentication.py │ ├── decorators.py │ ├── decorators0.py │ ├── decorators1.py │ ├── decorators2.py │ └── performance_decorator.py ├── 09. Debugging │ └── dubugging_pdb.py ├── 10. Generators │ ├── fibonacci_list.py │ ├── fibonacci_range.py │ ├── generator.py │ ├── our_own_forloop.py │ └── our_own_range.py ├── 11. Regular Expressions │ ├── email_password_regex.py │ └── regular_exp.py ├── 12. Unit Testing │ ├── guess_game.py │ ├── script.py │ ├── test.py │ ├── test2.py │ └── test_guess_game.py ├── 13. Mini-Projects │ ├── Job Scheduler │ │ ├── bst_demo.py │ │ ├── data.txt │ │ └── job_scheduler.py │ ├── data.txt │ ├── email_project │ │ ├── demo.py │ │ └── run.py │ ├── hash_project │ │ ├── hash_algo.py │ │ ├── project_script.py │ │ └── tempCodeRunnerFile.py │ ├── planeSimulator.py │ ├── recursion_miniprojects │ │ ├── countdown_timer.py │ │ ├── factorial.py │ │ ├── fibonacci.py │ │ ├── multi_tasker.py │ │ └── tempCodeRunnerFile.py │ └── runtime_analyser │ │ ├── analyser.py │ │ └── sorts.py ├── 14. Questions │ ├── barclays plc uk - online assesment.py │ ├── leetcode 01 - two sum.py │ ├── leetcode 02 - add two numbers.py │ ├── leetcode 03 - longest substring without repeating characters.py │ ├── leetcode 09 - palindrome number.py │ ├── leetcode 100 - same tree.py │ ├── leetcode 101 - symmetric tree.py │ ├── leetcode 1011 - capacity to ship packages.py │ ├── leetcode 102 - level order traversal of tree.py │ ├── leetcode 1022 - sum of root-leaf binary num.py │ ├── leetcode 103 - zigzag level order traversal.py │ ├── leetcode 104 - max depth of binary tree.py │ ├── leetcode 108 - sorted array to bst.py │ ├── leetcode 110 - balanced bst.py │ ├── leetcode 112 - path sum.py │ ├── leetcode 114 - binary tree preorder traversal.py │ ├── leetcode 1147 - largest number at least twice of others.py │ ├── leetcode 121 - best time to buy and sell stock.py │ ├── leetcode 128 - longest consecutive sequence.py │ ├── leetcode 13 - roman to integer.py │ ├── leetcode 1302 - deepest leaves sum.py │ ├── leetcode 1305 - all elements in two binary search trees.py │ ├── leetcode 133 - clone graph.py │ ├── leetcode 1379 - corresponding target in cloned tree.py │ ├── leetcode 1382 - balance a bst.py │ ├── leetcode 14 - longest common prefix.py │ ├── leetcode 15 - three sum.py │ ├── leetcode 162 - peak element.py │ ├── leetcode 167 - two sum II.py │ ├── leetcode 1971 - find if path exists in a graph.py │ ├── leetcode 1991 - find the middle index in array.py │ ├── leetcode 20 - valid parentheses.py │ ├── leetcode 207 - course schedule.py │ ├── leetcode 21 - merge two sorted lists.py │ ├── leetcode 217 - contains duplicates.py │ ├── leetcode 226 - invert binary tree.py │ ├── leetcode 2265 - count nodes equal to average of subtree.py │ ├── leetcode 2306 - naming a company.py │ ├── leetcode 2331 - evaluate boolean binary tree.py │ ├── leetcode 234 - palindrome linked list.py │ ├── leetcode 235 - lowest common ancestor in bst.py │ ├── leetcode 238 - product of array except self.py │ ├── leetcode 257 - binary tree paths.py │ ├── leetcode 26 - remove duplicates from sorted array.py │ ├── leetcode 27 - remove element.py │ ├── leetcode 28 - implement strStr().py │ ├── leetcode 28 - index of first occurrence.py │ ├── leetcode 290 - word pattern.py │ ├── leetcode 347 - top k frequent elements.py │ ├── leetcode 35 - search insert position.py │ ├── leetcode 350 - intersection of two arrays II.py │ ├── leetcode 36 - valid sudoku.py │ ├── leetcode 424 - longest repeating character replacement.py │ ├── leetcode 427 - construct quad tree.py │ ├── leetcode 435 - non-overlapping intervals.py │ ├── leetcode 438 - find all anagrams in string.py │ ├── leetcode 443 - string compression.py │ ├── leetcode 48 - rotate image (by rotation).py │ ├── leetcode 48 - rotate image (by transpose).py │ ├── leetcode 49 - group anagrams.py │ ├── leetcode 494 - target sum.py │ ├── leetcode 502 - ipo.py │ ├── leetcode 53 - maximum subarray.py │ ├── leetcode 530 - minimum absolute difference in BST.py │ ├── leetcode 540 - single element in a sorted array.py │ ├── leetcode 559 - max depth of n-ary tree.py │ ├── leetcode 58 - length of last word.py │ ├── leetcode 590 - n-ary tree postorder.py │ ├── leetcode 598 - n-ary tree preorder.py │ ├── leetcode 617 - merge binary trees.py │ ├── leetcode 637 - avg of levels in binary tree.py │ ├── leetcode 653 - two sum with binary tree.py │ ├── leetcode 66 - plus one.py │ ├── leetcode 67 - add binary.py │ ├── leetcode 69 - sqrt(x).py │ ├── leetcode 70 - climbing stairs.py │ ├── leetcode 705 - hash set.py │ ├── leetcode 724 - find pivot index.py │ ├── leetcode 783 - minimum distance between bst nodes.py │ ├── leetcode 797 - all paths from source to target.py │ ├── leetcode 83 - remove duplicates from sorted list.py │ ├── leetcode 872 - leaf-similar trees.py │ ├── leetcode 88 - merger sort array.py │ ├── leetcode 897 - increasing order bst.py │ ├── leetcode 94 - binary tree inorder traversal.py │ ├── leetcode 944 - delete columns to make sorted.py │ ├── leetcode 96 - unique binary search trees.py │ ├── leetcode 98 - validate binary search tree.py │ ├── leetcode 989 - add to array form of integer.py │ └── leetcode 997 - find the town judge.py ├── DSA_Cheatsheet.pdf ├── Python_Cheatsheet.pdf ├── Python_Cheatsheet_2.pdf └── readme.md ├── LICENSE └── Readme.md /Algorithm Data Structures Python/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Bubble_sort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Dec 22 17:45:47 2017 4 | @author: Tirthajyoti Sarkar 5 | Simple Bubble sort with counter for number of swap operations 6 | Accepts user input on minimum and maximum bound of the array and the size of the array 7 | """ 8 | 9 | import random 10 | 11 | def bubble_sort(array): 12 | n = len(array) 13 | # Set a swap counter to a non-zero value 14 | swap_counter=-1 15 | swap_op=0 16 | # Unitll swap counter hits zero... 17 | while(swap_counter!=0): 18 | # Reset the swap counter at the beginnig of each iteration 19 | swap_counter=0 20 | # Iterate over the array examining the a pair of data 21 | for i in range(n-1): 22 | if(array[i]>array[i+1]): 23 | temp=array[i] 24 | array[i]=array[i+1] 25 | array[i+1]=temp 26 | # Print for troubleshooting 27 | #print(sorted_array) 28 | swap_counter+=1 29 | swap_op+=1 30 | else: 31 | pass 32 | return (array,swap_op) 33 | 34 | # User inputs for generating the random arrays 35 | mini = int(input("Enter the minimum bound:")) 36 | maxi = int(input("Enter the maximum bound:")) 37 | num = int(input("Enter the size:")) 38 | 39 | # Create random array based on user-specified minimum/maximum bounds and number of elements 40 | a= [] 41 | for i in range(num): 42 | a.append(random.randint(mini,maxi)) 43 | 44 | print("\nInitial array:",a) 45 | 46 | # Get the sorted array back along with the count of # of operations it took to sort 47 | sorted_array,n_op=bubble_sort(a) 48 | print("Sorted array: {}\nTook {} operations".format(sorted_array,n_op)) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Count_inversion.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Jan 25 21:16:36 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | def merge_count_SplitInv(L1,L2): 9 | result=[] 10 | count=0 11 | # This loop runs till both input lists have non-zero elements in them 12 | # That means this loop stops when either of the input list runs out of element 13 | while (len(L1)>0 and len(L2)>0): 14 | if L1[0]<=L2[0]: 15 | # Append to the result list 16 | result.append(L1[0]) 17 | #print("Result:",result) 18 | # Pop the first element of the list 19 | L1.pop(0) 20 | else: 21 | # Append to the result list 22 | result.append(L2[0]) 23 | #print("Result:",result) 24 | # Pop the first element of the list 25 | L2.pop(0) 26 | # CRUX OF THE ALGORITHM: When we copy over from L2, we increment 27 | #count by the number of elements REMAINING in L1 i.e. length of L1 because 28 | # the length is dynamically modified by popping the first element out whenever 29 | # we copy over from L1 30 | count+=len(L1) 31 | # Now checking which input list has run out of element. 32 | # Whichever list still has element left, append all of them to the result array 33 | # Note, only one of these if-loops will be executed 34 | if(len(L1)>0): 35 | result=result+L1 36 | if(len(L2)>0): 37 | result=result+L2 38 | 39 | return (result,count) 40 | 41 | def sort_count_inversion(my_list): 42 | length=len(my_list) 43 | # Base case 44 | if length==1: 45 | return (my_list,0) 46 | # Recursive case 47 | else: 48 | l1_sorted,x=sort_count_inversion(my_list[0:int(length/2)]) 49 | l2_sorted,y=sort_count_inversion(my_list[int(length/2):length]) 50 | l_sorted,z=merge_count_SplitInv(l1_sorted,l2_sorted) 51 | return (l_sorted,(x+y+z)) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Insertion_sort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Dec 22 23:26:32 2017 4 | @author: Tirthajyoti Sarkar 5 | Simple Insertion sort with counter for total number of operations (shifting and iterating) 6 | Accepts user input on minimum and maximum bound of the array and the size of the array 7 | """ 8 | import random 9 | 10 | def insertion_sort(array): 11 | counter = 0 12 | # Iterate over the array starting from 2nd element i.e. index 1 13 | for index in range(1,len(array)): 14 | # Set current value and index 15 | currentvalue = array[index] 16 | position = index 17 | # Keep shifting the elements to insert the next unsorted element in the proper position 18 | while position>0 and array[position-1]>currentvalue: 19 | array[position]=array[position-1] 20 | position = position-1 21 | array[position]=currentvalue 22 | counter+=1 23 | # Print current state of array for troubleshooting 24 | #print(array) 25 | return (array,counter) 26 | 27 | # User inputs for generating the random arrays 28 | mini = int(input("Enter the minimum bound:")) 29 | maxi = int(input("Enter the maximum bound:")) 30 | num = int(input("Enter the size:")) 31 | 32 | # Create random array based on user-specified minimum/maximum bounds and number of elements 33 | a= [] 34 | for i in range(num): 35 | a.append(random.randint(mini,maxi)) 36 | 37 | print("\nInitial array:",a) 38 | 39 | # Get the sorted array back along with the count of # of operations it took to sort 40 | sorted_array,n_op=insertion_sort(a) 41 | print("Sorted array: {}\nTook {} operations".format(sorted_array,n_op)) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/MergeSort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed Jan 24 22:42:19 2018 4 | 5 | @author: Tirtha 6 | """ 7 | def merge(list1,list2): 8 | """ 9 | Takes two lists and merge them in a sorted list 10 | """ 11 | # Initialie the empty list 12 | result=[] 13 | i=0 14 | j=0 15 | # This loop runs till both input lists have non-zero elements in them 16 | # That means this loop stops when either of the input list runs out of element 17 | while (len(list1)>0 and len(list2)>0): 18 | if list1[0]<=list2[0]: 19 | # Append to the result list 20 | result.append(list1[0]) 21 | #print("Result:",result) 22 | # Pop the first element of the list 23 | list1.pop(0) 24 | i=i+1 25 | else: 26 | # Append to the result list 27 | result.append(list2[0]) 28 | #print("Result:",result) 29 | # Pop the first element of the list 30 | list2.pop(0) 31 | j+=1 32 | # Now checking which input list has run out of element. 33 | # Whichever list still has element left, append all of them to the result array 34 | # Note, only one of these if-loops will be executed 35 | if(len(list1)>0): 36 | result=result+list1 37 | if(len(list2)>0): 38 | result=result+list2 39 | print("Result:",result) 40 | #print(f"i:{i},j:{j}") 41 | return (result) 42 | 43 | def mergeSort(my_list): 44 | n = len(my_list) 45 | # Base case for 1-element array 46 | if n==1: 47 | return (my_list) 48 | # Recursive case: 49 | # Divide the array into two halves. 50 | # Mergesort on the left half 51 | # Mergesort on the right half 52 | # Merge two sorted arrays 53 | # Return the merged result 54 | else: 55 | left_half=my_list[0:int(n/2)] 56 | right_half=my_list[int(n/2):n] 57 | print("Left half:",left_half) 58 | print("Right half:",right_half) 59 | left=mergeSort(left_half) 60 | right=mergeSort(right_half) 61 | print(f"Merging {left} and {right}") 62 | sorted_list=merge(left,right) 63 | return (sorted_list) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/QuickSelect-1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Sun Jan 28 16:17:46 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | import random 9 | 10 | def Rselect(my_list,n): 11 | length=len(my_list) 12 | if length==1: 13 | return my_list[0] 14 | else: 15 | low=[] 16 | high=[] 17 | p_idx = random.randint(1,length-1) 18 | pivot = my_list[p_idx] 19 | #print("Pivot chosen",pivot) 20 | if pivot==max(my_list): 21 | high.append(pivot) 22 | my_list.remove(pivot) 23 | low=my_list 24 | else: 25 | for ele in my_list: 26 | if ele<=pivot: 27 | low.append(ele) 28 | else: 29 | high.append(ele) 30 | #low=low+equal 31 | #print("Low list",low) 32 | #print("High list",high) 33 | if n<=len(low): 34 | #print("Recursing on {} with order {}".format(low,n)) 35 | return Rselect(low,n) 36 | else: 37 | #print("Recursing on {} with order {}".format(high,n-len(low))) 38 | return Rselect(high,n-len(low)) 39 | 40 | 41 | # Test code for single case with fixed order statistic 42 | ##============= 43 | """ 44 | N_test=7 45 | test_lst=[] 46 | for i in range(N_test): 47 | test_lst.append(random.randint(0,100)) 48 | #n= random.randint(1,6) 49 | n=3 50 | print("Original list:",test_lst) 51 | print("Order statistic sought",n) 52 | print("") 53 | 54 | result = Rselect(test_lst,n) 55 | test_lst.sort() 56 | #element = test_lst[result-1] 57 | print("{}-th order statistic is {}".format(n,result)) 58 | 59 | print("Sorted list",test_lst) 60 | 61 | """ 62 | ## Test code with 100 cases with random order statistic 63 | N=1000 64 | check = [] 65 | # Create a test array of 20 integers 66 | for i in range(N): 67 | N_test=20 68 | test_lst=[] 69 | for i in range(N_test): 70 | test_lst.append(random.randint(0,100)) 71 | # Picking a random test input for order statistic 72 | n= random.randint(0,19) 73 | result = Rselect(test_lst,n) 74 | # Call Python's built-in sort method on the test array 75 | test_lst.sort() 76 | # Check if the sorted array's n-1-th element is the n-th order statistic returned by our program 77 | check.append(test_lst[n-1]==result) 78 | # Print the sum total of truth values in the check array 79 | print(sum(check)) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Quicksort-1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Jan 26 18:26:21 2018 4 | 5 | @author: Tirtha 6 | """ 7 | import random 8 | 9 | def quicksort(lst): 10 | #count_op=0 11 | smaller=[] 12 | equal=[] 13 | bigger=[] 14 | if len(lst)==0 or len(lst)==1: 15 | return (lst) 16 | else: 17 | pivot=lst[0] 18 | for n in lst: 19 | if n start: 10 | pivot = array[start] 11 | middle = start + 1 12 | for i in range(start+1, end): 13 | if array[i] > array[middle]: 14 | tmp = array[i] 15 | array[i] = array[middle] 16 | array[middle] = tmp 17 | middle += 1 18 | sort(array, start, middle) 19 | sort(array, middle, end) 20 | 21 | N_test=10 22 | test_lst=[] 23 | for i in range(N_test): 24 | test_lst.append(random.randint(0,100)) 25 | 26 | print("Original list:",test_lst) 27 | sort(test_lst,0,9) 28 | print("Sorted list:",test_lst) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Quicksort_InPlac2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Jan 26 18:32:13 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | import random 9 | 10 | def partition(A,l,r): 11 | p=A[l] 12 | i=l+1 13 | for j in range(l+1,r): 14 | if A[j]<=p: 15 | temp=A[j] 16 | A[j]=A[i] 17 | A[i]=temp 18 | i+=1 19 | temp=A[i-1] 20 | A[i-1]=A[l] 21 | A[l]=temp 22 | print("Modified list:",A) 23 | print("Pivot pos",i) 24 | return (i) 25 | 26 | def QuickSortInPlace(lst,low,high): 27 | #count_op=0 28 | length=high-low 29 | # Base case: Nothing to do 30 | if length<=1: 31 | pass 32 | elif length==2: 33 | if (lst[0]>=lst[1]): 34 | temp=lst[0] 35 | lst[0]=lst[1] 36 | lst[1]=temp 37 | # Recursive case 38 | else: 39 | # Partition the array and get back the pivot position 40 | pivot_pos=partition(lst,low,high) 41 | # Quicksort on the left half of the pivot 42 | QuickSortInPlace(lst,low,pivot_pos-1) 43 | # Quicksort on the right half of the pivot 44 | QuickSortInPlace(lst,pivot_pos,high) 45 | 46 | # Test code 47 | ##============= 48 | N_test=15 49 | test_lst=[] 50 | for i in range(N_test): 51 | test_lst.append(random.randint(0,100)) 52 | 53 | print("Original list:",test_lst) 54 | QuickSortInPlace(test_lst,0,15) 55 | print("Sorted list: ",test_lst) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Quicksort_InPlace.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Jan 26 18:32:13 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | import random 9 | import math 10 | 11 | def partition(A,l,r): 12 | global count_op 13 | p=A[l] 14 | i=l+1 15 | for j in range(l+1,r): 16 | if A[j]<=p: 17 | temp=A[j] 18 | A[j]=A[i] 19 | A[i]=temp 20 | i+=1 21 | count_op+=4 22 | temp=A[i-1] 23 | A[i-1]=A[l] 24 | A[l]=temp 25 | print("Modified list:",A) 26 | #print("Pivot pos",i) 27 | return (i) 28 | 29 | def QuickSortInPlace(lst,low,high): 30 | global count_op 31 | length=high-low 32 | # Base case: Nothing to do 33 | if length<=1: 34 | pass 35 | # Recursive case 36 | else: 37 | # Partition the array and get back the pivot position 38 | pivot_pos=partition(lst,low,high) 39 | # Quicksort on the left half of the pivot 40 | QuickSortInPlace(lst,low,pivot_pos-1) 41 | # Quicksort on the right half of the pivot 42 | QuickSortInPlace(lst,pivot_pos,high) 43 | 44 | # Test code 45 | ##============= 46 | 47 | N_test=15 48 | test_lst=[] 49 | for i in range(N_test): 50 | test_lst.append(random.randint(0,100)) 51 | 52 | print("Original list:",test_lst) 53 | QuickSortInPlace(test_lst,0,15) 54 | print("Sorted list: ",test_lst) 55 | 56 | """ 57 | count_array=[] 58 | log_array=[] 59 | for i in range(2,102): 60 | test_lst=[] 61 | count_op=0 62 | for k in range(i): 63 | test_lst.append(random.randint(0,1000)) 64 | QuickSortInPlace(test_lst,0,i) 65 | count_array.append(count_op) 66 | log_array.append(5*i*math.log(i,2)) 67 | 68 | print(count_array) 69 | 70 | import matplotlib.pyplot as plt 71 | plt.scatter(range(2,102),count_array) 72 | plt.plot(range(2,102),log_array,lw=3,color='red') 73 | plt.grid(True) 74 | plt.show() 75 | """ -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Algorithms/Selection_sort.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Dec 22 18:44:02 2017 4 | @author: Tirthajyoti Sarkar 5 | Simple Selection sort with counter for total number of operations (finding minimum and swapping) 6 | Accepts user input on minimum and maximum bound of the array and the size of the array 7 | """ 8 | import random 9 | 10 | def find_min(array): 11 | n=len(array) 12 | r = array[0] 13 | count=0 14 | for i in range(1,n): 15 | count+=1 16 | if r>array[i]: 17 | r=array[i] 18 | return(r,count) 19 | 20 | def selection_sort(array): 21 | n=len(array) 22 | num_op=0 23 | # Iterate over the length of the array, pushing smaller values to the left 24 | for i in range(n): 25 | # Scan the array from i-th element (where the iterator is currently) to the end for minimum 26 | m,c_min=find_min(array[i:n]) 27 | # IMPORTANT: Get the index of the minimum element w.r.t. to the main array 28 | m_index=array[i:n].index(m)+i 29 | # If the first element of the unsorted portion i.e. i-th element> minimum, then SWAP 30 | if (array[i]>m): 31 | # Print statement for examining minimum and its index, Troubleshooting 32 | #print("Minimum found {} at position {}. Swapping positions {} and {}".format(m,m_index,i,m_index)) 33 | temp=array[i] 34 | array[i]=m 35 | array[m_index]=temp 36 | num_op+=(c_min+1) 37 | print(array) 38 | else: 39 | pass 40 | return (array,num_op) 41 | 42 | # User inputs for generating the random arrays 43 | mini = int(input("Enter the minimum bound:")) 44 | maxi = int(input("Enter the maximum bound:")) 45 | num = int(input("Enter the size:")) 46 | 47 | # Create random array based on user-specified minimum/maximum bounds and number of elements 48 | a= [] 49 | for i in range(num): 50 | a.append(random.randint(mini,maxi)) 51 | 52 | print("\nInitial array:",a) 53 | 54 | # Get the sorted array back along with the count of # of operations it took to sort 55 | sorted_array,n_op=selection_sort(a) 56 | print("Sorted array: {}\nTook {} operations".format(sorted_array,n_op)) -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Data Structures/Graph-1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Jun 14 20:55:21 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | class Node (object): 9 | def __init__(self,name): 10 | self.name=name 11 | 12 | def getName(self): 13 | return (self.name) 14 | 15 | def __str__(self): 16 | return (self.name) 17 | 18 | class Edge (object): 19 | def __init__(self,src,dest): 20 | self.src=src 21 | self.dest=dest 22 | 23 | def getSource(self): 24 | return (self.src) 25 | 26 | def getDest(self): 27 | return (self.dest) 28 | 29 | def __str__(self): 30 | return (self.src+"->"self.dest) 31 | -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Data Structures/Graph1.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Jun 14 20:55:21 2018 4 | 5 | @author: Tirtha 6 | """ 7 | 8 | class Node (object): 9 | def __init__(self,name): 10 | self.name=name 11 | 12 | def getName(self): 13 | return (self.name) 14 | 15 | def __str__(self): 16 | return (self.name) 17 | 18 | class Edge (object): 19 | def __init__(self,src,dest): 20 | self.src=src 21 | self.dest=dest 22 | 23 | def getSource(self): 24 | return (self.src) 25 | 26 | def getDest(self): 27 | return (self.dest) 28 | 29 | def __str__(self): 30 | return (self.src.getName()+"->"+self.dest.getName()) 31 | 32 | class Digraph(object): 33 | def __init__(self): 34 | self.edges={} 35 | 36 | def addNode(self,node): 37 | if node in self.edges: 38 | raise ValueError("Duplicate node") 39 | else: 40 | self.edges[node]=[] 41 | 42 | def addEdge(self,edge): 43 | src=edge.getSource() 44 | dest=edge.getDest() 45 | if (src not in self.edges) and (dest not in self.edges): 46 | raise ValueError("Node not in graph") 47 | else: 48 | self.edges[src].append(dest) # Builds adjacency list 49 | 50 | def childrenOf(self,node): 51 | return self.edges[node] 52 | 53 | def hasNode(self,node): 54 | return node in self.edges 55 | 56 | def getNode(self,name): 57 | for n in self.edges: 58 | if n.getName()==name: 59 | return n 60 | raise NameError(name) 61 | 62 | def __str__(self): 63 | toPrint='' 64 | for src in self.edges: 65 | for dest in self.edges[src]: 66 | toPrint=toPrint+src.getName()+"->"+dest.getName()+"\n" 67 | 68 | if (toPrint==''): 69 | return ("Empty graph! Nothing to print") 70 | else: 71 | return toPrint[:-1] 72 | 73 | -------------------------------------------------------------------------------- /Algorithm Data Structures Python/Data Structures/LinkedList-test.py: -------------------------------------------------------------------------------- 1 | from LinkedList import LinkedList, Node 2 | 3 | def main(): 4 | print() 5 | print("An empty list initialized...") 6 | ll = LinkedList() 7 | print("Is the list empty? ",ll.isEmpty()) 8 | print("Now a list with an initial value...") 9 | ll = LinkedList(Node(10)) 10 | ll.show() 11 | print("Is the list empty? ",ll.isEmpty()) 12 | print("Appending at the end...") 13 | ll.append(Node(20)) 14 | ll.show() 15 | print("Inserting at the beginning...") 16 | ll.insert_first(Node(100)) 17 | ll.show() 18 | print("Deleting the tail...") 19 | ll.delete_tail() 20 | ll.show() 21 | print("Inserting few more nodes...") 22 | ll.append(Node(25)) 23 | ll.append(Node(50)) 24 | ll.show() 25 | print("Length of the list:", ll.length()) 26 | print() 27 | 28 | if __name__ == "__main__": 29 | main() -------------------------------------------------------------------------------- /Algorithm Data Structures Python/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Tirthajyoti Sarkar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Algorithm Data Structures Python/README.md: -------------------------------------------------------------------------------- 1 | # Popular algorithms and useful data Structures in Python 2 | 3 | ## Building useful data structures in Python 4 | * Linked List 5 | * Queue 6 | * Stack 7 | * Trees 8 | * Graph 9 | 10 | ## Coding fundamentally important algorithms 11 | * Binary search 12 | * Bubble sort 13 | * Insertion sort 14 | * Selection sort 15 | * Quick sort 16 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 10.2.py: -------------------------------------------------------------------------------- 1 | name = input("Enter file:") 2 | if len(name) < 1 : name = "mbox-short.txt" 3 | handle = open(name) 4 | lst=list() 5 | di=dict() 6 | for line in handle: 7 | if line.startswith("From "): 8 | pos=line.find(":") 9 | lst.append(line[pos-2:pos]) 10 | for word in lst: 11 | di[word]=di.get(word,0)+1 12 | newlst=list() 13 | for key,val in di.items(): 14 | newtup=(key,val) 15 | newlst.append(newtup) 16 | newlst=sorted(newlst) 17 | for key,val in newlst: 18 | print(key,val) 19 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 2.2.py: -------------------------------------------------------------------------------- 1 | name = input("Enter your name") 2 | print("Hello " + name) 3 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 2.3.py: -------------------------------------------------------------------------------- 1 | hrs = input("Enter Hours:") 2 | rate = input("Enter rate:") 3 | pay = float(hrs) * float(rate) 4 | print(pay) 5 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 3.1.py: -------------------------------------------------------------------------------- 1 | hrs = input("Enter Hours:") 2 | h = float(hrs) 3 | rate = input("Enter rate: ") 4 | r = float(rate) 5 | if h <= 40: 6 | pay = h * r 7 | else: 8 | pay = r * 40 + (r * 1.5) * (h - 40) 9 | print(pay) 10 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 5.2.py: -------------------------------------------------------------------------------- 1 | largest = None 2 | smallest = None 3 | while True: 4 | num = input("Enter a number: ") 5 | if num == "done" : 6 | break 7 | n = int(num) 8 | elif largest < n : 9 | largest = n 10 | elif smallest == None or smallest > n : 11 | smallest = n 12 | else: 13 | print("Invalid input") 14 | 15 | print("Maximum is",largest) 16 | print ("Minimum is",smallest) 17 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 6.5.py: -------------------------------------------------------------------------------- 1 | text = "X-DSPAM-Confidence: 0.8475"; 2 | pos=text.find(':') 3 | value=text[pos+1:] 4 | print(float(value)) 5 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 7.1.py: -------------------------------------------------------------------------------- 1 | # Use words.txt as the file name 2 | fname = input("Enter file name: ") 3 | fh = open(fname) 4 | for line in fh.readlines(): 5 | print(line.upper().strip()) 6 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 7.2.py: -------------------------------------------------------------------------------- 1 | # Use the file name mbox-short.txt as the file name 2 | total=0 3 | count=0 4 | fname = input("Enter file name: ") 5 | fh = open(fname) 6 | for line in fh: 7 | if not line.startswith("X-DSPAM-Confidence:") : 8 | continue 9 | count=count+1 10 | pos=line.find(':') 11 | value=line[pos+1:] 12 | total=total+float(value) 13 | avg=total/count 14 | print("Average spam confidence:",avg) 15 | 16 | #Output: 17 | #Average spam confidence: 0.750718518519 18 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 8.4.py: -------------------------------------------------------------------------------- 1 | #file used is romeo.txt 2 | fname = input("Enter file name: ") 3 | fh = open(fname) 4 | lst = list() 5 | for line in fh: 6 | for i in line.split(): 7 | if not i in lst: 8 | lst.append(i) 9 | lst.sort() 10 | print(lst) 11 | 12 | #Output 13 | #['Arise', 'But', 'It', 'Juliet', 'Who', 'already', 'and', 'breaks', 'east', 'envious', 'fair', 'grief', 'is', 'kill', 'light', 'moon', 'pale', 'sick', 'soft', 'sun', 'the', 'through', 'what', 'window', 'with', 'yonder'] 14 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 8.5.py: -------------------------------------------------------------------------------- 1 | fname = input("Enter file name: ") 2 | if len(fname) < 1 : fname = "mbox-short.txt" 3 | fhand = open(fname) 4 | count = 0 5 | for line in fhand: 6 | line.rstrip() 7 | if line.startswith("From "): 8 | words = line.split() 9 | print(words[1]) 10 | count += 1 11 | print("There were",count, "lines in the file with From as the first word") 12 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/Assignment 9.4.py: -------------------------------------------------------------------------------- 1 | name = input("Enter file:") 2 | if len(name) < 1 : name = "mbox-short.txt" 3 | handle = open(name) 4 | 5 | count = dict() 6 | for line in handle: 7 | if not line.startswith("From "):continue 8 | line = line.split() 9 | line = line[1] 10 | count[line] = count.get(line, 0) +1 11 | 12 | bigcount = None 13 | bigword = None 14 | for k,v in count.items(): 15 | if bigcount == None or v > bigcount: 16 | bigword = k 17 | bigcount = v 18 | print(bigword, bigcount) 19 | 20 | #Output : cwen@iupui.edu 5 21 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/romeo.txt: -------------------------------------------------------------------------------- 1 | But soft what light through yonder window breaks 2 | It is the east and Juliet is the sun 3 | Arise fair sun and kill the envious moon 4 | Who is already sick and pale with grief 5 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Assignments/words.txt: -------------------------------------------------------------------------------- 1 | Writing programs or programming is a very creative 2 | and rewarding activity You can write programs for 3 | many reasons ranging from making your living to solving 4 | a difficult data analysis problem to having fun to helping 5 | someone else solve a problem This book assumes that 6 | {\em everyone} needs to know how to program and that once 7 | you know how to program, you will figure out what you want 8 | to do with your newfound skills 9 | 10 | We are surrounded in our daily lives with computers ranging 11 | from laptops to cell phones We can think of these computers 12 | as our personal assistants who can take care of many things 13 | on our behalf The hardware in our current-day computers 14 | is essentially built to continuously as us the question 15 | What would you like me to do next 16 | 17 | Our computers are fast and have vasts amounts of memory and 18 | could be very helpful to us if we only knew the language to 19 | speak to explain to the computer what we would like it to 20 | do next If we knew this language we could tell the 21 | computer to do tasks on our behalf that were reptitive 22 | Interestingly, the kinds of things computers can do best 23 | are often the kinds of things that we humans find boring 24 | and mind-numbing 25 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Quizzes/Chapter 10 Quiz.txt: -------------------------------------------------------------------------------- 1 | 1> What is the difference between a Python tuple and Python list? 2 | sol) Lists are mutable and tuples are not mutable 3 | 4 | 2> Which of the following methods work both in Python lists and Python tuples? 5 | sol) index() 6 | 7 | 3> What will end up in the variable y after this code is executed? x , y = 3, 4 8 | sol) 4 9 | 10 | 4> In the following Python code, what will end up in the variable y? x = { 'chuck' : 1 , 'fred' : 42, 'jan': 100}; y = x.items() 11 | sol) A list of tuples 12 | 13 | 5> Which of the following tuples is greater than x in the following Python sequence? x = (5, 1, 3); if ??? > x : ... 14 | sol) (6, 0, 0) 15 | 16 | 6> What does the following Python code accomplish, assuming the c is a non-empty dictionary? tmp = list(); for k, v in c.items(): tmp.append( (v, k)) 17 | sol) It creates a list of tuples where each tuple is a value, key pair 18 | 19 | 7> If the variable data is a Python list, how do we sort it in reverse order? 20 | sol) data.sort(reverse=True) 21 | 22 | 8> Using the following tuple, how would you print 'Wed'? days = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun') 23 | sol) print(days[2]) 24 | 25 | 9> In the following Python loop, why are there two iteration variables (k and v)? c = {'a':10, 'b':1, 'c':22}; for k, v in c.items() : ... 26 | sol) Because the items() method in dictionaries returns a list of tuples 27 | 28 | 10> Given that Python lists and Python tuples are quite similar - when might you prefer to use a tuple over a list? 29 | sol) For a temporary variable that you will use and discard without modifying 30 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Quizzes/Chapter 6 Quiz.txt: -------------------------------------------------------------------------------- 1 | 1> What does the following Python Program print out? str1 = "Hello"; str2 = 'there'; bob = str1 + str2; print bob 2 | sol) Hellothere 3 | 4 | 2> What does the following Python program print out? x = '40'; y = int(x) + 2; print y 5 | sol) 42 6 | 7 | 3> How would you use the index operator [] to print out the letter q from the following string? x = 'From marquard@uct.ac.za' 8 | sol) print(x[8]) 9 | 10 | 4> How would you use string slicing [:] to print out 'uct' from the following string? x = 'From marquard@uct.ac.za' 11 | sol) print(x[14:17]) 12 | 13 | 5> What is the iteration variable in the following Python code? for letter in 'banana' : print letter 14 | sol) letter 15 | 16 | 6> What does the following Python code print out? print len('banana')*7 17 | sol) 42 18 | 19 | 7> How would you print out the following variable in all upper case in Python? greet = 'Hello Bob' 20 | sol) print(greet.upper()) 21 | 22 | 8> Which of the following is not a valid string method in Python? 23 | sol) twist() 24 | 25 | 9> What will the following Python code print out? data = 'From stephen.marquard@uct.ac.za Sat Jan 5 09:14:16 2008';pos = data.find('.');print(data[pos:pos+3]) 26 | sol) .ma 27 | 28 | 10> Which of the following string methods removes whitespace from both the beginning and end of a string? 29 | sol) strip() 30 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Quizzes/Chapter 7 Quiz.doc: -------------------------------------------------------------------------------- 1 | 1> Given the architecture and terminology we introduced in Chapter 1, where are files stored? 2 | sol) Secondary memory 3 | 4 | 2> What is stored in a "file handle" that is returned from a successful open() call? 5 | sol) The handle is a connection to the file's data 6 | 7 | 3> What do we use the second parameter of the open() call to indicate? 8 | sol) Whether we want to read data from the file or write data to the file 9 | 10 | 4> What Python function would you use if you wanted to prompt the user for a file name to open? 11 | sol) input() 12 | 13 | 5> What is the purpose of the newline character in text files? 14 | sol) It indicates the end of one line of text and the beginning of another line of text 15 | 16 | 6> If we open a file as follows: xfile = open('mbox.txt'). What statement would we use to read the file one line at a time? 17 | sol) for line in xfile: 18 | 19 | 7> What is the purpose of the following Python code? fhand = open('mbox.txt'); x = 0; for line in fhand: x = x + 1; print x 20 | sol) Count the lines in the file 'mbox.txt' 21 | 22 | 8> If you write a Python program to read a text file and you see extra blank lines in the output that are not present in the file input as shown below, what Python string function will likely solve the problem?. From: stephen.marquard@uct.ac.za; From: louis@media.berkeley.edu; From: zqian@umich.edu; From: rjlowe@iupui.edu ... 23 | sol) strip() 24 | 25 | 9> The following code sequence fails with a traceback when the user enters a file that does not exist. How would you avoid the traceback and make it so you could print out your own error message when a bad file name was entered? fname = raw_input('Enter the file name: '); fhand = open(fname) 26 | sol) try / except 27 | 28 | 10> What does the following Python code do? fhand = open('mbox-short.txt'); inp = fhand.read() 29 | sol) Reads the entire file into the variable inp as a string 30 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Quizzes/Chapter 8 Quiz.md: -------------------------------------------------------------------------------- 1 | 1> How are "collection" variables different from normal variables? 2 | sol) Collection variables can store multiple values in a single variable 3 | 4 | 2> What are the Python keywords used to construct a loop to iterate through a list? 5 | sol) for/in 6 | 7 | 3> For the following list, how would you print out 'Sally'? friends = [ 'Joseph', 'Glenn', 'Sally'] 8 | sol) print(friends[2]) 9 | 10 | 4> fruit = 'Banana' fruit[0] = 'b'; print(fruit) 11 | sol) Nothing would print the program fails with a traceback 12 | 13 | 5> Which of the following Python statements would print out the length of a list stored in the variable data? 14 | sol) print(len(data)) 15 | 16 | 6> What type of data is produced when you call the range() function? x = range(5) 17 | sol) A list of integers 18 | 19 | 7> What does the following Python code print out? a = [1, 2, 3]; b = [4, 5, 6]; c = a + b; print len(c) 20 | sol) 6 21 | 22 | 8> Which of the following slicing operations will produce the list [12, 3]? t = [9, 41, 12, 3, 74, 15] 23 | sol) t[2:4] 24 | 25 | 9> What list method adds a new item to the end of an existing list? 26 | sol) append() 27 | 28 | 10> What will the following Python code print out? friends = [ 'Joseph', 'Glenn', 'Sally' ]; friends.sort(); print(friends[0]) 29 | sol) Glenn 30 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/Quizzes/Chapter 9 Quiz.txt: -------------------------------------------------------------------------------- 1 | 1> How are Python dictionaries different from Python lists? 2 | sol) Python lists maintain order and dictionaries do not maintain order 3 | 4 | 2> What is a term commonly used to describe the Python dictionary feature in other programming languages? 5 | sol) Associative arrays 6 | 7 | 3> What would the following Python code print out? stuff = dict(); print(stuff['candy']) 8 | sol) The program would fail with a traceback 9 | 10 | 4> What would the following Python code print out? stuff = dict(); print(stuff.get('candy',-1)) 11 | sol) -1 12 | 13 | 5> (T/F) When you add items to a dictionary they remain in the order in which you added them. 14 | sol) False 15 | 16 | 6> What is a common use of Python dictionaries in a program? 17 | sol) Building a histogram counting the occurrences of various strings in a file 18 | 19 | 7> Which of the following lines of Python is equivalent to the following sequence of statements assuming that counts is a dictionary? if key in counts: counts[key] = counts[key] + 1 else: counts[key] = 1 20 | sol) counts[key] = counts.get(key,0) + 1 21 | 22 | 8> In the following Python, what does the for loop iterate through? x = dict() ... for y in x : ... 23 | sol) It loops through the keys in the dictionary 24 | 25 | 9> Which method in a dictionary object gives you a list of the values in the dictionary? 26 | sol) values() 27 | 28 | 10> What is the purpose of the second parameter of the get() method for Python dictionaries? 29 | sol) To provide a default value if the key is not found 30 | -------------------------------------------------------------------------------- /Coursera Python Data Structures University of Michigan/README.md: -------------------------------------------------------------------------------- 1 | # Coursera-Python-Data-Structures-University-of-Michigan- -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | __pycache__/ 3 | .DS_Store 4 | 14. Questions/code.py 5 | 14. Questions/temp.py 6 | 14. Questions/tempCodeRunnerFile.py -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/BigO-cheat-sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/BigO-cheat-sheet.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/Books/Data Structures - Reema Thareja.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/Books/Data Structures - Reema Thareja.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/Books/competitiveCoding.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/Books/competitiveCoding.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/DAA Syllabus.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/DAA Syllabus.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/Interview cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/Interview cheatsheet.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/Master Plan.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/Master Plan.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/01. Resources/Master_the_Interview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/01. Resources/Master_the_Interview.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/02. Big-O/O(1).py: -------------------------------------------------------------------------------- 1 | #O(1) - Constant Time 2 | #The no. of operations do not depend on the size of the input and are always constant. 3 | import time 4 | 5 | array_small = ['nemo' for i in range(10)] 6 | array_medium = ['nemo' for i in range(100)] 7 | array_large = ['nemo' for i in range(10000)] 8 | 9 | def finding_nemo(array): 10 | t0 = time.time() 11 | for i in array: 12 | pass 13 | t1 = time.time() 14 | print(f'Time taken = {t1-t0}') 15 | 16 | finding_nemo(array_small) 17 | finding_nemo(array_medium) 18 | finding_nemo(array_large) 19 | 20 | #Time taken in all 3 cases would be 0.0 seconds because we are only extracting the first and second elements of the arays. 21 | #We are not looping over the entire array. 22 | #We are performing two O(1) operations, which equal to O(2) 23 | #Any constant number can be considered as 1. There we can say this function is of O(1) - Constant Time Complexity. 24 | 25 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/02. Big-O/O(m + n).py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | large1 = ['nemo' for i in range(100000)] 4 | large2 = ['nemo' for i in range(100000)] 5 | 6 | def find_nemo(array1, array2): 7 | 8 | #Here there are two different variables array1 and array2. 9 | #They have to be represented by 2 different variables in the Big-O representation as well. 10 | #Let array1 correspond to m and array2 correspond to n 11 | 12 | t0 = time.time() #O(1) 13 | for i in range(0,len(array1)): #O(m) 14 | if array1[i] == 'nemo': #m*O(1) 15 | print("Found Nemo!!") #k1*O(1) where k1 <= m because this statement will be executed only if the if statement returns True, which can be k1(<=m) times 16 | t1 = time.time() #O(1) 17 | print(f'The search took {t1-t0} seconds.') #O(1) 18 | 19 | t0 = time.time() #O(1) 20 | for i in range(0, len(array2)): #O(n) 21 | if array2[i] == 'nemo': #n*O(1) 22 | print("Found Nemo!!") #k2*O(1) where k2 <= m because this statement will be executed only if the if statement returns True, which can be k2(<=m) times 23 | t1 = time.time() #O(1) 24 | print(f'The search took {t1 - t0} seconds.') #O(1) 25 | 26 | find_nemo(large1, large2) 27 | 28 | #Total time complexity of the find_nemo function = 29 | #O(1 + m + m*1 + k1*1 + 1 + 1 + 1 + n + n*1 + k2*1 + 1 + 1) = O(6 + 2m + 2n + k1 + k2) 30 | #Now k1<=m and k2<=n. In the worst case, k1 can be m and k2 can be n. We'll consider the worst case and calculate the Big-O 31 | #O(6 + 2m + 2n + m + n) = O(3m + 3n + 6) = O(3(m + n + 2)) 32 | #The constants can be safely ignored. 33 | #Therefore, O(m + n + 2) = O(m + n) 34 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/02. Big-O/O(m x n).py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | array1 = ['a','b','c','d','e'] 4 | array2 = [1,2,3,4,5] 5 | 6 | def pairs(array1, array2): 7 | 8 | # Here there are two different variables array1 and array2. 9 | # They have to be represented by 2 different variables in the Big-O representation as well. 10 | # Let array1 correspond to m and array2 correspond to n 11 | 12 | for i in range(len(array1)): #n*O(m) 13 | for j in range(len(array2)): #m*O(n) 14 | print(array1[i],array2[j]) #m*n*O(1) 15 | 16 | pairs(array1,array2) 17 | 18 | #Total time complexity of the pairs function = 19 | #O(n*m + m*n + m*n*1) = O(3*m*n) 20 | #The constants can be safely ignored. 21 | #Therefore, O(m * n * 3) = O(m * n) 22 | 23 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/02. Big-O/O(n).py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | nemo = ['nemo'] 4 | everyone = ['dory', 'bruce', 'marlin', 'nemo', 'gill', 'bloat', 'nigel', 'squirt', 'darla'] 5 | large = ['nemo' for i in range(100000)] 6 | def find_nemo(array): 7 | t0 = time.time() 8 | for i in range(0,len(array)): 9 | if array[i] == 'nemo': 10 | print("Found Nemo!!") 11 | t1 = time.time() 12 | print(f'The search took {t1-t0} seconds.') 13 | find_nemo(nemo) 14 | find_nemo(everyone) 15 | find_nemo(large) 16 | 17 | 18 | def funchallenge(input): 19 | temp = 10 #O(1) 20 | temp = temp +50 #O(1) 21 | for i in range(len(input)): #O(n) 22 | var = True #n*O(1) 23 | temp += 1 #n*O(1) 24 | return temp #O(1) 25 | 26 | funchallenge(nemo) 27 | funchallenge(everyone) 28 | funchallenge(large) 29 | 30 | #Total running time of the funchallenge function = 31 | #O(1 + 1 + n + n*1 + n*1 + n*1 + 1) = O(3n +3) = O(3(n+1)) 32 | #Any constant in the Big-O representation can be replaced by 1, as it doesn't really matter what constant it is. 33 | #Therefore, O(3(n+1)) becomes O(n+1) 34 | #Similarly, any constant number added or subtracted to n or multiplied or divided by n can also be safely written as just n 35 | #This is because the constant that operates upon n, doesn't depend on n, i.e., the input size 36 | #Therefore, the funchallenge function can be said to be of O(n) or Linear Time Complexity. -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/02. Big-O/O(n^2).py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | array = ['a','b','c','d','e'] 4 | 5 | def log_all_pairs(array): 6 | 7 | #There are nested for loops in this function but there is only one variable array. So we don't need two variables for the Big-O 8 | 9 | for i in range(len(array)): #n*O(n) 10 | for j in range(len(array)): #n*O(n) 11 | print(array[i], array[j]) #n*n*O(1) 12 | 13 | log_all_pairs(array) 14 | 15 | #Total time complexity of the log_all_pairs function = 16 | #O(n*n + n*n + n*n*1) = O(3n^2) 17 | #The constants can be safely ignored. 18 | #Therefore, O(3n^2) = O(n^2) 19 | 20 | new_array = [1,2,3,4,5] 21 | def print_numbers_then_pairs(array): 22 | 23 | #There are a total of three loops here but only one variable. So we need only variable for our Big-O notation 24 | 25 | print("The numbers are : ") #O(1) 26 | for i in range(len(array)): #O(n) 27 | print(array[i]) #n*O(1) 28 | 29 | print("The pairs are :") #O(1) 30 | for i in range(len(array)): #n*O(n) 31 | for j in range(len(array)): #n*O(n) 32 | print(array[i],array[j]) #n*n*O(1) 33 | 34 | print_numbers_then_pairs(new_array) 35 | 36 | #Total time complexity of the print_numbers_then_pairs function = 37 | #O(1 + n + n*1 + 1 + n*n + n*n + n*n*1) = O(3n^2 + 2n + 2) 38 | #Now, Big-O presents scalability of the cod, i.e., how the code will behave as the inputs grow larger and larger 39 | #Therefore if the expression contains terms of different degrees and the size of inputs is huge, the terms of the smaller degrees become negligible in comparison to those of the higher degrees 40 | #Therefore, we can ignore the terms of the smaller degrees and only keep the highest degree term 41 | #O(3n^2 + 2n + 2) = O(3n2) 42 | #The constants can be safely ignored. 43 | #Therefore, O(3n^2) = O(n^2) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/03. Data Structures/Arrays/Contains_Duplicate.py: -------------------------------------------------------------------------------- 1 | #Given an array of integers, find if the array contains any duplicates. 2 | #Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct. 3 | #Example 1: 4 | #Input: [1,2,3,1] 5 | #Output: true 6 | #Example 2: 7 | #Input: [1,2,3,4] 8 | #Output: false 9 | 10 | #As usual we'll get the naive approach out of the way first. 11 | 12 | def brute_force_duplicate_search(array): 13 | for i in range(len(array)-1): 14 | for j in range(i+1,len(array)): 15 | if array[i] == array[j]: 16 | return True 17 | return False 18 | 19 | array = [1,2,46,32,98,61,34,46] 20 | print(brute_force_duplicate_search(array)) 21 | 22 | #This is pretty simple, as we go through every possible pair of elements to check if they are the same. 23 | #If we find a pair having the same elements we return True, else we return False 24 | #Time Complexity - O(n^2) 25 | 26 | #A slightly better solution can be : 27 | #First we sort the array using O(nlog n) built-in sort of Python. 28 | #Then we loop through the array once to check if any consecutive elements are same, which will be O(n). 29 | #So overall complexity will be O(nlog n) 30 | 31 | def better_duplicate_search(array): 32 | array.sort() 33 | for i in range(len(array)-1): 34 | if array[i] == array[i+1]: 35 | return True 36 | return False 37 | 38 | print(better_duplicate_search(array)) 39 | 40 | #An even better solution can be using a dictionary. 41 | #As we loop through the array, we'll check first if the current element is present in the dictionary 42 | #If yes, we return True 43 | #If no, we add the element to the dictionary. 44 | #Since looking up in a dictionary is O(1) time, overall complexity would be O(n) 45 | 46 | def smart_duplicate_search(array): 47 | dictionary = dict() 48 | if len(array)<2: 49 | return False 50 | else: 51 | for i in range(len(array)): 52 | if array[i] in dictionary: 53 | return True 54 | else: 55 | dictionary[array[i]] = True 56 | return False 57 | 58 | print(smart_duplicate_search(array)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/03. Data Structures/Arrays/Merging_sorted_arrays.py: -------------------------------------------------------------------------------- 1 | #Given two sorted arrays, we need to merge them and create one big sorted array. 2 | #For example, array1 = [1,3,5,7], array2 = [2,4,6,8] 3 | #The result should be array = [1,2,3,4,5,6,7,8] 4 | 5 | #One solution can be : we compare the corresponding elements of both arrays 6 | #We add the smaller element to a new array and increment the index of the array from which the element was added. 7 | #Again we compare the elements of both arrays and repeat the procedure until all the elements have been added. 8 | 9 | def merge(array1, array2): 10 | new_array = [] 11 | flag = 0 12 | first_array_index = second_array_index = 0 13 | while not (first_array_index>=len(array1) or second_array_index>=len(array2)): #The loop runs until we reach the end of either of the arrays 14 | if array1[first_array_index] <= array2[second_array_index]: 15 | new_array.append(array1[first_array_index]) 16 | first_array_index += 1 17 | else: 18 | new_array.append(array2[second_array_index]) 19 | second_array_index += 1 20 | 21 | if first_array_index==len(array1): #When the loop finishes, we need to know which array's end was reached, so that the remaining elements of the other array can be appended to the new array 22 | flag = 1 #This flag will tell us if we reached the end of the first array or the second array 23 | 24 | if flag == 1: #If the end of the first array was reached, the remaining elements of the second array are added to the new array 25 | for item in array2[second_array_index:]: 26 | new_array.append(item) 27 | else: #And if the end of the second array was reached, the remaining elements of the first array are added to the new array 28 | for item in array1[first_array_index:]: 29 | new_array.append(item) 30 | 31 | return new_array 32 | 33 | array1 = [1,3,5,7] 34 | array2 = [2,4,6,8,10,12] 35 | print(merge(array1,array2)) 36 | #[1, 2, 3, 4, 5, 6, 7, 8, 10, 12] 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/03. Data Structures/Arrays/Reversing_String.py: -------------------------------------------------------------------------------- 1 | # A string is given. We have to print the reversed string. 2 | # For example, the string is "Hi how are you?" 3 | # The output should be "?ouy era woh iH" 4 | 5 | #The first solution that comes to mind is we can create a new array and append the characters of the original array, 6 | #one by one from the end to the beginning. 7 | 8 | def simple_reverse(string): 9 | new_string = [] 10 | for i in range(len(string)-1, -1, -1): #The for loop runs from the last element to the first element of the original string 11 | new_string.append(string[i]) #The characters of the original string are added to the new string 12 | return ''.join(new_string) #The characters of the reversed array are joined to form a string 13 | 14 | string = "Hello" 15 | print(simple_reverse(string)) 16 | #Since we only have to traverse the string once, the time complexity is O(n) 17 | #But since we are also creating a new array of the same size , the space complexity is also O(n) 18 | 19 | 20 | #A smarter way to do this , can be taking a pair of elements from either end of the string and swapping them 21 | #We have start at both the ends and continue swapping pairs till the middle of the string 22 | #This way we can avoid having to create a new array and save on space complexity while keeping time complexity at O(n) 23 | 24 | def swap(string, a, b): #Function which swaps two characters of a string 25 | string = list(string) 26 | temp = string[a] 27 | string[a] = string[b] 28 | string[b] = temp 29 | return ''.join(string) 30 | 31 | def smarter_reverse(string): 32 | for i in range(len(string)//2): 33 | string = swap(string, i, len(string)-i-1) 34 | return string 35 | 36 | print(smarter_reverse(string)) 37 | 38 | 39 | #Apart from these, some built-in functions that can be used to reverse a string are as follows: 40 | 41 | string1 = 'abcde' 42 | string2 = reversed(string1) 43 | print(''.join(string2)) 44 | 45 | list1 = list(string1) 46 | list1.reverse() 47 | print(''.join(list1)) 48 | 49 | #Both these methods are of O(n) time complexity -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/03. Data Structures/Hash Tables/Introduction.py: -------------------------------------------------------------------------------- 1 | #Hash Tables are data structures which generally provide very fast(O(1)) lookups, insertions and deletions 2 | #In Python, dictionaries are implemented as hash tables. 3 | 4 | #The way hashing works is that there is a bucket containing slots to fill with elements. 5 | #Like in arrays, elements are referenced by their integer indexes, in dictionaries, or hash tables, 6 | #values are referenced by their keys, which can be of any data type. 7 | #Now there are different kinds of hash functions (eg: MD5, SHA1, SHA256) which are used to convert the keys into hashes, which are unique for each key 8 | #And the hashes are then mapped to some slot in the bucket. And the key and value pair get stored in the slot, 9 | #or in some accompanying data structure within the slot (like, linked lists) 10 | 11 | #In general, the lookup, insert and delete operations all are very fast, in the order of O(1) 12 | #But in some cases, more than one keys can map to the same slot and that increases the time complexity by some margin, 13 | #although not by a lot in most cases. This is known as a collision. 14 | #Now, like for almost all problem there is some sort of a solution in the computer science world, 15 | #collisions can also be resolved by numerous collision resolution techniques like open addressing and closed addressing 16 | 17 | #Enough details, let's look at how hash tables are implemented in Python using dictionaries. 18 | 19 | dictionary = dict() 20 | dictionary = {'one':1, 'two':2, 'three':3, 'four':4, 'five':5} 21 | print(dictionary) 22 | #{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5} 23 | 24 | print(dictionary.keys()) 25 | #dict_keys(['one', 'two', 'three', 'four', 'five']) 26 | 27 | print(dictionary.values()) 28 | #dict_values([1, 2, 3, 4, 5]) 29 | 30 | print(dictionary.items()) 31 | #dict_items([('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]) 32 | 33 | print(dictionary['one']) #Accessing a value by its key in O(1) time 34 | #1 35 | 36 | dictionary['six'] = 6 #Inserting the value 6 for the key 'six' in O(1) time. 37 | print(dictionary) 38 | #{'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} 39 | 40 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/03. Data Structures/Hash Tables/Legacy/hash_algo.py: -------------------------------------------------------------------------------- 1 | class AlgoHashTable: 2 | 3 | def __init__ (self, size): 4 | self.size = size 5 | self.hash_table = self.create_buckets() 6 | 7 | def create_buckets(self): 8 | return [[] for _ in range(self.size)] 9 | 10 | def __str__(self): 11 | return "".join(str(item) for item in self.hash_table) 12 | 13 | 14 | 15 | def set_val(self, key, value): 16 | 17 | hashed_key = hash(key)%self.size 18 | bucket = self.hash_table[hashed_key] 19 | 20 | found_key = False 21 | 22 | for index, record in enumerate(bucket): 23 | record_key, record_value = record 24 | if record_key == key: 25 | found_key = True 26 | break 27 | 28 | if found_key: 29 | bucket[index] = (key, value) 30 | 31 | else: 32 | bucket.append((key, value)) 33 | 34 | def get_val(self, key): 35 | 36 | hashed_key = hash(key)%self.size 37 | bucket = self.hash_table[hashed_key] 38 | found_key = False 39 | 40 | for index, record in enumerate(bucket): 41 | record_key, record_value = record 42 | if record_key == key: 43 | found_key = True 44 | break 45 | 46 | if found_key: 47 | return record_value 48 | 49 | else: 50 | return f"{key} not found" 51 | 52 | 53 | 54 | 55 | hash_table = AlgoHashTable(200) 56 | 57 | file = open("data.txt") 58 | 59 | lines = file.readline().strip().split(':') 60 | 61 | for line in file: 62 | key, value = line.split(":") 63 | hash_table.set_val(key, value) 64 | 65 | 66 | print(hash_table) 67 | 68 | print("-"*100) 69 | 70 | print(hash_table.get_val("ahlrdmukjn@yaexample.com")) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Divide and Conquer/karatsuba_multiplication.py: -------------------------------------------------------------------------------- 1 | ''' 2 | karatsuba multiplication (integer-wise) 3 | to multiply two n-digit integers, the following formula holds: 4 | => (a * c * 10^n) + (b * d) + {[(b * c) + (a * d)] * 10^(n/2)} 5 | where: a = first half of first integer 6 | b = second half of first integer 7 | c = first half of second integer 8 | d = second half of second integer 9 | this can further be used with recursion to implement divide-and-conquer 10 | wherein each product (ac, bd, bc, ad) can be calculated using the same. 11 | 12 | note: assuming n = even & n1 = n2 13 | ''' 14 | def k_multiply(x, y): 15 | if len(x) > 1 and len(y) > 1: # base condition: length of integers > 1 16 | a, b = x[:len(x) // 2], x[len(x) // 2:] # divide first int for a, b, 17 | c, d = y[:len(y) // 2], y[len(y) // 2:] # divide second int for c, d 18 | 19 | print(a, b, c, d) 20 | ac = k_multiply(a, c) 21 | bd = k_multiply(b, d) 22 | bc = k_multiply(b, c) 23 | ad = k_multiply(a, d) 24 | n = len(x) 25 | n2 = n // 2 26 | prod = (ac * pow(10, n)) + (bd) + ((bc + ad) * pow(10, n2)) # prod by karatsuba 27 | 28 | return prod 29 | else: 30 | return (x[0] * y[0]) # return product if length <= 1 31 | 32 | if __name__ == '__main__': 33 | try: 34 | first_integer = [int(x) for x in input('first integer: ')] 35 | second_integer = [int(x) for x in input('second integer: ')] 36 | 37 | if (len(second_integer) != len(first_integer)): 38 | raise ValueError 39 | 40 | prod = k_multiply(first_integer, second_integer) 41 | print(prod) 42 | except ValueError: 43 | print('Invalid Inputs') 44 | 45 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Dynamic Programming/Fibonacci.py: -------------------------------------------------------------------------------- 1 | #Now we will implement our old Fibonacci program using Dynamic Programming 2 | #Fibonacci Sequence : 0 1 1 2 3 5 8 13 21 35 55 89 144 233 . . . 3 | 4 | import time 5 | 6 | def fibonacci(n): 7 | if n<2: 8 | return n 9 | else: 10 | return fibonacci(n-1) + fibonacci(n-2) 11 | 12 | 13 | cache = {} 14 | def dynamic_fibonacci(n): 15 | if n in cache: 16 | return cache[n] 17 | else: 18 | if n < 2: 19 | return n 20 | else: 21 | cache[n] = dynamic_fibonacci(n-1) + dynamic_fibonacci(n-2) 22 | return cache[n] 23 | 24 | 25 | t1 = time.time() 26 | print(fibonacci(30)) 27 | t2 = time.time() 28 | print(t2-t1) 29 | #832040 30 | #0.39888763427734375 31 | 32 | t1 = time.time() 33 | print(dynamic_fibonacci(30)) 34 | t2 = time.time() 35 | print(t2-t1) 36 | #832040 37 | #0.0 38 | 39 | 40 | t1 = time.time() 41 | print(dynamic_fibonacci(60)) 42 | t2 = time.time() 43 | print(t2-t1) 44 | #1548008755920 45 | #0.0 46 | 47 | 48 | t1 = time.time() 49 | print(dynamic_fibonacci(100)) 50 | t2 = time.time() 51 | print(t2-t1) 52 | #354224848179261915075 53 | #0.0 54 | 55 | t1 = time.time() 56 | print(dynamic_fibonacci(1000)) 57 | t2 = time.time() 58 | print(t2-t1) 59 | #43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 60 | #0.0009982585906982422 61 | 62 | #I won't even dare to try calculating fibonacci(1000) using the normal recursive function! -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Dynamic Programming/Memoization.py: -------------------------------------------------------------------------------- 1 | #Memoization is an optimization technique used to speed up programs by storing the results of expensive function calls 2 | #and returning the cached result when the same inputs occur again. 3 | #In Python there's a module named functools with a method lru_cache() which allows us to use this optimization technique 4 | #First, we'll implement memoization on our own with an example function, then with the help of lru_cache 5 | 6 | import time, random 7 | 8 | times =[] 9 | 10 | def squaring_without_memoization(number): #Function to calculate the square of a number 11 | return number**2 12 | 13 | array = [random.randint(1,10) for _ in range(10000000)] #Generates an array of size 1000000 with random integers between 1-10(both included) 14 | t1 = time.time() 15 | for i in range(len(array)): 16 | print(squaring_without_memoization(array[i])) 17 | t2 = time.time() 18 | times.append(t2-t1) 19 | 20 | 21 | cache = {} 22 | def squaring_with_memoization(number): 23 | if number in cache: 24 | return cache[number] 25 | else: 26 | cache[number] = number**2 27 | return cache[number] 28 | 29 | t1 = time.time() 30 | for i in range(len(array)): 31 | print(squaring_with_memoization(array[i])) 32 | t2 = time.time() 33 | times.append(t2-t1) 34 | 35 | 36 | from functools import lru_cache 37 | 38 | @lru_cache(maxsize=10000) 39 | def squaring(number): 40 | return number**2 41 | 42 | print(array) 43 | t1 = time.time() 44 | for i in range(len(array)): 45 | print(squaring(array[i])) 46 | t2 = time.time() 47 | times.append(t2-t1) 48 | 49 | print(times) 50 | #[203.95188665390015, 148.48580384254456, 148.26833629608154] --- When array size was 10000000 51 | #[7.06306266784668, 6.145563125610352, 5.758295774459839] --- When array size was 1000000 52 | 53 | print(cache) 54 | #{8: 64, 7: 49, 6: 36, 1: 1, 4: 16, 9: 81, 2: 4, 5: 25, 3: 9, 10: 100} 55 | 56 | print(squaring.cache_info()) 57 | #CacheInfo(hits=999990, misses=10, maxsize=10000, currsize=10) --- When array size was 1000000 58 | #CacheInfo(hits=9999990, misses=10, maxsize=10000, currsize=10) --- When array size was 10000000 59 | 60 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Recursion/Factorial.py: -------------------------------------------------------------------------------- 1 | #Given a number, we have to return its factorial. 2 | #For example, factorial(5) should return 5! = 5*4*3*2*1 = 120 3 | #We can solve this recursively, or iteratively. 4 | #First we are going to solve it iteratively. 5 | 6 | def iterative_factorial(number): 7 | f = 1 8 | for i in range(1, number+1): 9 | f = f * i 10 | return f 11 | 12 | print(iterative_factorial(0)) 13 | #1 14 | print(iterative_factorial(5)) 15 | #120 16 | print(iterative_factorial(50)) 17 | #30414093201713378043612608166064768844377641568960512000000000000 18 | 19 | def recursive_factorial(number): 20 | if number <= 1: 21 | return 1 22 | else: 23 | return number * recursive_factorial(number-1) 24 | 25 | print(recursive_factorial(0)) 26 | #1 27 | print(recursive_factorial(5)) 28 | #120 29 | print(recursive_factorial(50)) 30 | #30414093201713378043612608166064768844377641568960512000000000000 31 | print(recursive_factorial(1000)) 32 | #RecursionError: maximum recursion depth exceeded in comparison 33 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Recursion/Fibonacci.py: -------------------------------------------------------------------------------- 1 | #Given a number, we have to return the number at that index of the fibonacci sequence. 2 | #Fibonacci Sequence - 0 1 1 2 3 5 8 13 21 34 55 89 144 . . . . 3 | #For example, fibonacci(5) should return 5 as the 5th index (staring from 0) of the fibonacci sequence is the number 5 4 | #Again , we will do both the iterative and recursive solutions 5 | 6 | def iterative_fibonacci(index): 7 | first_number = 0 8 | second_number = 1 9 | if index == 0: 10 | return first_number 11 | if index == 1: 12 | return second_number 13 | for i in range(2,index +1): 14 | third_number = first_number + second_number 15 | first_number = second_number 16 | second_number = third_number 17 | return third_number 18 | 19 | print(iterative_fibonacci(0)) #0 20 | print(iterative_fibonacci(1)) #1 21 | print(iterative_fibonacci(5)) #5 22 | print(iterative_fibonacci(7)) #13 23 | print(iterative_fibonacci(10)) #55 24 | print(iterative_fibonacci(12)) #144 25 | 26 | 27 | def recursive_fibonacci(index): 28 | if index == 0: #Base case 1 29 | return 0 30 | if index == 1: #Base case 2 31 | return 1 32 | return recursive_fibonacci(index-1) + recursive_fibonacci(index-2) #Every term in fib sequence = sum of previous two terms 33 | 34 | print(recursive_fibonacci(0)) #0 35 | print(recursive_fibonacci(1)) #1 36 | print(recursive_fibonacci(5)) #5 37 | print(recursive_fibonacci(7)) #13 38 | print(recursive_fibonacci(10)) #55 39 | print(recursive_fibonacci(12)) #144 40 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Recursion/Reverse_String.py: -------------------------------------------------------------------------------- 1 | #Given a string , we need to reverse it using recursion (and iteration) 2 | #For example, input = "Zero To Mastery", output = "yretsaM oT oreZ" 3 | 4 | #First we will implement the iterative solution 5 | def iterative_reverse(string): #Here we use a second string to store the reversed version. Time and Space complexity = O(n) 6 | reversed_string = '' 7 | for i in range(len(string)): 8 | reversed_string = reversed_string + string[len(string)-i-1] 9 | return reversed_string 10 | 11 | print(iterative_reverse("Zero To Mastery")) 12 | #yretsaM oT oreZ 13 | 14 | #Here we append the string backwards into the original string itself and then slice it to contain only the 2nd half,i.e.,the reversed part. 15 | #Time complexity = O(n). Space complexity = O(n) 16 | def second_iterative_reverse(string): 17 | original_length = len(string) 18 | for i in range(original_length): 19 | string = string + string[original_length - i - 1] 20 | string = string[original_length:] 21 | return string 22 | 23 | print(second_iterative_reverse("Zero To Mastery")) 24 | #yretsaM oT oreZ 25 | 26 | 27 | def recursive_reverse(string): 28 | print(string) 29 | if len(string) == 0: 30 | return string 31 | else: 32 | return recursive_reverse(string[1:]) + string[0] 33 | 34 | print(recursive_reverse("Zero To Mastery")) 35 | ''' 36 | Zero To Mastery 37 | ero To Mastery 38 | ro To Mastery 39 | o To Mastery 40 | To Mastery 41 | To Mastery 42 | o Mastery 43 | Mastery 44 | Mastery 45 | astery 46 | stery 47 | tery 48 | ery 49 | ry 50 | y 51 | 52 | yretsaM oT oreZ 53 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Searching/Alt_Binary_Search.py: -------------------------------------------------------------------------------- 1 | # alternative binary search 2 | # - based on "efficient iteration" 3 | # - make jumps and slow down as we get close to target 4 | # - time complexity => O(logn) 5 | 6 | # iterative 7 | def bsearch_alt(target, arr): 8 | n = len(arr) 9 | k = 0 10 | i = n // 2 11 | while (i >= 1): 12 | while (k + i < n) and (arr[k + i] <= target): 13 | k = k + 1 14 | i = i // 2 15 | 16 | return k if arr[k] == target else -1 17 | 18 | 19 | 20 | print(bsearch_alt(4, [1, 2, 3, 4, 5])) 21 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/Heap_Sort.py: -------------------------------------------------------------------------------- 1 | #Heap Sort as the name suggests, uses the heap data structure. 2 | #First the array is converted into a binary heap. Then the first element which is the maximum elemet in case of a max-heap, 3 | #is swapped with the last element so that the maximum element goes to the end of the array as it should be in a sorted array. 4 | #Then the heap size is reduced by 1 and max-heapify function is called on the root. 5 | #Time complexity is O(nlog N) in all cases and space complexity = O(1) 6 | 7 | count = 0 8 | def max_heapify(array, heap_size, i): 9 | left = 2 * i + 1 10 | right = 2 * i + 2 11 | largest = i 12 | global count 13 | if left < heap_size: 14 | count += 1 15 | if array[left] > array[largest]: 16 | largest = left 17 | if right < heap_size: 18 | count += 1 19 | if array[right] > array[largest]: 20 | largest = right 21 | if largest != i: 22 | array[i], array[largest] = array[largest], array[i] 23 | max_heapify(array, heap_size, largest) 24 | 25 | def build_heap(array): 26 | heap_size = len(array) 27 | for i in range ((heap_size//2),-1,-1): 28 | max_heapify(array,heap_size, i) 29 | 30 | def heap_sort(array): 31 | heap_size = len(array) 32 | build_heap(array) 33 | print (f'Heap : {array}') 34 | for i in range(heap_size-1,0,-1): 35 | array[0], array[i] = array[i], array[0] 36 | heap_size -= 1 37 | max_heapify(array, heap_size, 0) 38 | 39 | array = [5,9,3,10,45,2,0] 40 | heap_sort(array) 41 | print (array) 42 | print(f'Number of comparisons = {count}') 43 | ''' 44 | Heap : [45, 10, 3, 5, 9, 2, 0] 45 | [0, 2, 3, 5, 9, 10, 45] 46 | Number of comparisons = 22 47 | ''' 48 | 49 | sorted_array = [5,6,7,8,9] 50 | heap_sort(sorted_array) 51 | print(sorted_array) 52 | print(f'Number of comparisons = {count}') 53 | ''' 54 | Heap : [9, 8, 7, 5, 6] 55 | [5, 6, 7, 8, 9] 56 | Number of comparisons = 12 57 | ''' 58 | 59 | reverse_sorted_array = [9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10] 60 | heap_sort(reverse_sorted_array) 61 | print(reverse_sorted_array) 62 | print(f'Number of comparisons = {count}') 63 | ''' 64 | Heap : [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10] 65 | [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 66 | Number of comparisons = 105 67 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/legacy/bubble_sort.py: -------------------------------------------------------------------------------- 1 | def bubble_sort(arr): 2 | """ 3 | Fill in this docstring to practice writing docstrings 4 | along with summarizing what the function does 5 | """ 6 | swap_happened = True 7 | while swap_happened: 8 | print('bubble sort status: ' + str(arr)) 9 | swap_happened = False 10 | for num in range(len(arr)-1): 11 | if arr[num] > arr[num+1]: 12 | swap_happened = True 13 | arr[num], arr[num+1] = arr[num+1], arr[num] 14 | 15 | l = [6, 8, 1, 4, 10, 7, 8, 9, 3, 2, 5] # original case 16 | # l = [10, 9, 8, 8, 7, 6, 5, 4, 3, 2, 1] # worst case 17 | # l = [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10] # best case 18 | bubble_sort(l) 19 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/legacy/insertion_sort.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(arr): 2 | for key in range(1, len(arr)): 3 | if arr[key] < arr[key-1]: 4 | j = key 5 | while j > 0 and arr[j] < arr[j-1]: 6 | arr[j], arr[j-1] = arr[j-1], arr[j] 7 | j -= 1 8 | 9 | l = [6,1,8,4,10] 10 | insertion_sort(l) 11 | print(l) 12 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/legacy/merge_sort.py: -------------------------------------------------------------------------------- 1 | def merge_sorted(arr1,arr2): 2 | print("Merge function called with lists below:") 3 | print(f"left: {arr1} and right: {arr2}") 4 | sorted_arr = [] 5 | i, j = 0, 0 6 | 7 | while i < len(arr1) and j < len(arr2): 8 | 9 | if arr1[i] < arr2[j]: 10 | sorted_arr.append(arr1[i]) 11 | i += 1 12 | 13 | else: 14 | sorted_arr.append(arr2[j]) 15 | j += 1 16 | 17 | while j < len(arr2): 18 | sorted_arr.append(arr2[j]) 19 | j += 1 20 | 21 | 22 | while i < len(arr1): 23 | sorted_arr.append(arr1[i]) 24 | i += 1 25 | 26 | return sorted_arr 27 | 28 | def mergersort(arr): 29 | if len(arr) < 2: 30 | return arr[:] 31 | else: 32 | middle = len(arr)//2 33 | l1 = divide_arr(arr[:middle]) 34 | l2 = divide_arr(arr[middle:]) 35 | return merge_sorted(l1, l2) 36 | 37 | 38 | # xxxxxxxxxxxxxxxx Program Execution xxxxxxxxxxxxxxxx 39 | l = [8, 6, 2, 5, 10, 13, 4, 55, 61, 23, 100] 40 | print(divide_arr(l)) 41 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/legacy/quick_sort.py: -------------------------------------------------------------------------------- 1 | def quicksort(arr): 2 | if len(arr)<2: 3 | return arr 4 | else: 5 | pivot = arr[-1] 6 | smaller, equal, larger = [], [], [] 7 | for num in arr: 8 | if num < pivot: 9 | smaller.append(num) 10 | 11 | elif num == pivot: 12 | equal.append(num) 13 | 14 | else: 15 | larger.append(num) 16 | 17 | return quicksort(smaller)+ equal+ quicksort(larger) 18 | 19 | l = [6,8,1,4,10,7,8.9,3,2,5] 20 | print(quicksort(l)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Sorting/legacy/selection_sort.py: -------------------------------------------------------------------------------- 1 | def selection_sort(arr): 2 | """ 3 | Use selection sort algorithm to sort a list of numbers 4 | """ 5 | spot_marker = 0 6 | while spot_marker < len(arr): 7 | for num in range(spot_marker, len(arr)): 8 | if arr[num] < arr[spot_marker]: 9 | arr[spot_marker], arr[num] = arr[num], arr[spot_marker] 10 | spot_marker += 1 11 | 12 | l = [6, 8, 1, 4, 10, 7, 8, 9, 3, 2, 5] # original case 13 | # l = [10, 9, 8, 8, 7, 6, 5, 4, 3, 2, 1] # worst case 14 | # l = [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10] # best case 15 | selection_sort(l) 16 | print(l) 17 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Traversals/bisection_iter.py: -------------------------------------------------------------------------------- 1 | def bisection_iter(n, arr): 2 | start = 0 3 | stop = len(arr)-1 4 | 5 | while start <= stop: 6 | mid = (start + stop)//2 7 | if n == arr[mid]: 8 | return (f"{n} found at index {mid}") 9 | 10 | elif n > arr[mid]: 11 | start = mid+1 12 | 13 | else: 14 | stop = mid-1 15 | 16 | return (f"{n} not found in list") 17 | 18 | def create_list(max_val): 19 | arr = [] 20 | for num in range(1, max_val+1): 21 | arr.append(num) 22 | 23 | return arr 24 | 25 | 26 | max = int(input("Enter the maximum length of the list : ")) 27 | num_to_search = int(input("Enter the number you want to search for : ")) 28 | l = create_list(max) 29 | print(bisection_iter(num_to_search, l)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/04. Algorithms/Traversals/bisection_recur.py: -------------------------------------------------------------------------------- 1 | def bisection_recur(n, arr, start, stop): 2 | 3 | if start > stop: 4 | return f"{n} not found in list" 5 | 6 | else: 7 | mid = (start+stop)//2 8 | if n == arr[mid]: 9 | return f"{n} is found at index {mid}" 10 | 11 | elif n > arr[mid]: 12 | start = mid+1 13 | return bisection_recur(n, arr, start, stop) 14 | 15 | else: 16 | stop = mid-1 17 | return bisection_recur(n, arr, start, stop) 18 | 19 | def create_list(max_val): 20 | arr = [] 21 | for num in range(1, max_val+1): 22 | arr.append(num) 23 | 24 | return arr 25 | 26 | 27 | max = int(input("Enter the maximum length of the list : ")) 28 | num_to_search = int(input("Enter the number you want to search for : ")) 29 | l = create_list(max) 30 | print(l) 31 | print(bisection_recur(num_to_search, l, 1, len(l)-1)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/05. File Handling and OOPS/data.txt: -------------------------------------------------------------------------------- 1 | mashrur,hossain:python,ruby,javascript 2 | joe,schmo:python,ruby,javascript 3 | john,schmoe:python,ruby,javascript 4 | jane,doe:c,ruby,javascript 5 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/06. Error Handling/error_handling.py: -------------------------------------------------------------------------------- 1 | 2 | while True: 3 | try: 4 | age = int(input("Enter your age: ")) 5 | age_in_dogs_year = 10/age 6 | 7 | except ZeroDivisionError: 8 | print("enter age greater than 0") 9 | continue 10 | 11 | except ValueError: 12 | print("Please enter a no.") 13 | break 14 | 15 | except ValueError: 16 | print("!!!!") 17 | 18 | else: 19 | print(f"thank you, and your age is {age}") 20 | break 21 | 22 | finally: 23 | print("I will always get printed no matter what :)") 24 | 25 | print("can you hear me??????") 26 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/06. Error Handling/error_handling2.py: -------------------------------------------------------------------------------- 1 | 2 | def division_fn(num1, num2): 3 | try: 4 | return num1/num2 5 | except (ZeroDivisionError, TypeError) as err: 6 | print(f'error: {err}') 7 | 8 | print(division_fn(1,'0')) 9 | print(division_fn(1,0)) 10 | print(division_fn(1,4)) 11 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/06. Error Handling/raise_error.py: -------------------------------------------------------------------------------- 1 | 2 | # we can stop the program by raising our own errors. 3 | 4 | print("Hello!!!!") 5 | # raise TypeError("yo") 6 | raise Exception("Any message ") 7 | print("bye") 8 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/06. Error Handling/raise_error2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | try: 4 | age = int(input("age: ")) 5 | age = 10/age 6 | raise ValueError("Ending the program") 7 | # raise Exception("quit") 8 | 9 | except ValueError: 10 | print("Please enter a no.") -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/dict_comprehension.py: -------------------------------------------------------------------------------- 1 | 2 | my_dict = {num:num**2 for num in range(1,11)} 3 | print(my_dict) 4 | 5 | random_dict = { 6 | 'a': 1, 7 | 'b': 2, 8 | 'c': 3, 9 | 'd': 4 10 | } 11 | 12 | my_new_dict = {k:v**2 for k,v in random_dict.items()} 13 | print(my_new_dict) 14 | 15 | my_new_dict2 = {k:v**2 for k,v in random_dict.items() if v % 2 == 0} 16 | print(my_new_dict2) 17 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/enumerate.py: -------------------------------------------------------------------------------- 1 | fruits = ['apple', 'banana', 'cherry', 'grape'] 2 | 3 | for index, fruit in enumerate(fruits, 1): 4 | print(index, fruit) 5 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/filter().py: -------------------------------------------------------------------------------- 1 | 2 | def only_even(item): 3 | return item % 2 == 0 4 | 5 | my_list = [5,8,9,2,5,6,98,56,62] 6 | 7 | print(filter(only_even, my_list)) 8 | print(list(filter(only_even, my_list))) 9 | print(list(map(only_even, my_list))) 10 | print(my_list) 11 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/lambda_expressions.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | import functools 4 | 5 | my_list = [1,2,3,4,5] 6 | 7 | print(list(map(lambda item: item*2, my_list))) 8 | 9 | print(list(filter(lambda item: item % 2 != 0, my_list))) 10 | 11 | print(functools.reduce(lambda acc,item: item+acc, my_list)) 12 | 13 | ''' 14 | syntax: 15 | lambda param: action(param) 16 | it automatically returns the action taken, 17 | it do not have any name, doesn't get stored in the memory. 18 | and so used only once. 19 | and behaves exactly like a function. 20 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/lambda_expressions2.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | a = [(0,2),(4,4),(10,-1),(5,3)] 4 | 5 | a.sort(key=lambda x:x[1], reverse=False) 6 | print(a) 7 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/list_set_comprehension.py: -------------------------------------------------------------------------------- 1 | 2 | my_list = [] 3 | 4 | for item in 'hello': 5 | my_list.append(item) 6 | 7 | print(my_list) 8 | 9 | my_list1 = [item for item in 'Saurabh'] 10 | print(my_list1) 11 | 12 | my_list2 = [num**2 for num in range(1,11)] 13 | print(my_list2) 14 | 15 | # only even squares 16 | my_set = {num**2 for num in range(1,11) if num**2 % 2 == 0} 17 | print(my_set) 18 | # remember that set don't contain duplicate values 19 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/map().py: -------------------------------------------------------------------------------- 1 | 2 | def multiply_by2(item): 3 | return item*2 4 | 5 | my_list = [5,8,9] 6 | 7 | print(map(multiply_by2, my_list)) # it returns a map object, which then we can convert to a list/tuple/set 8 | print(list(map(multiply_by2, my_list))) # notice that we just write the function name without the curly braces 9 | print(my_list) 10 | 11 | ''' 12 | notice that map is not modifying anything, and creating a new list. 13 | it is also using separate data and function to work upon them. 14 | it's a nice concept of Functional programming and pure function. 15 | ''' 16 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/pure_functions.py: -------------------------------------------------------------------------------- 1 | 2 | def multiply_by2(li): 3 | new_li = [] 4 | for item in li: 5 | new_li.append(item) 6 | return new_li 7 | 8 | print(multiply_by2([5,6,8])) 9 | 10 | ''' 11 | If we define 'new_li' outside the function, or print something inside the function, then it is no longer 12 | a pure function. 13 | ''' 14 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/reduce().py: -------------------------------------------------------------------------------- 1 | 2 | from functools import reduce 3 | 4 | def accumulator(acc, item): 5 | print(f'acc: {acc}, item: {item}') 6 | return acc+item 7 | 8 | my_list = [1,2,3,4,5] 9 | print(reduce(accumulator, my_list)) # by default takes '0' as the 3rd argument 10 | print(reduce(accumulator, my_list, 10)) 11 | print(my_list) 12 | 13 | ''' 14 | acc is nothing but the return of the last iteration. 15 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/07. Functional Programming/zip().py: -------------------------------------------------------------------------------- 1 | 2 | li1 = [1,2,3] 3 | set1 = {4,5,6} 4 | tuple1 = (7,8,9) 5 | 6 | print(zip(li1, set1, tuple1)) 7 | print(list(zip(li1, set1, tuple1))) # combines the items sequence wise into a sequence of tuples 8 | print(li1, set1, tuple1) 9 | 10 | ''' 11 | use the same no.s of items in all the iterables, otherwise it can ruin the sequence. 12 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/HOC.py: -------------------------------------------------------------------------------- 1 | 2 | # Higher Order Function (HOC) is a function which returns another function, or accepts another function 3 | 4 | def greet(func): 5 | func() 6 | 7 | def greet2(): 8 | def hello(): 9 | print("hello!") 10 | return hello() 11 | 12 | print(greet(greet2)) 13 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/authentication.py: -------------------------------------------------------------------------------- 1 | # Create an @authenticated decorator that only allows the function to run is user1 has 'valid' set to True: 2 | user1 = { 3 | 'name': 'Sorna', 4 | 'valid': True 5 | } 6 | 7 | def authenticated(fn): 8 | def wrapper(*args, **kwargs): 9 | if args[0]['valid']: 10 | return fn(*args, **kwargs) 11 | return wrapper 12 | 13 | @authenticated 14 | def message_friends(user): 15 | print('message has been sent') 16 | 17 | message_friends(user1) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/decorators.py: -------------------------------------------------------------------------------- 1 | 2 | def my_decorator(func): 3 | def wrap_func(): 4 | print("***********") 5 | func() 6 | print("***********") 7 | return wrap_func 8 | 9 | @my_decorator 10 | def hello(): 11 | print("Hello!") 12 | 13 | hello() 14 | 15 | # using decorator is same as doing the below: 16 | # my_decorator(hello)() 17 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/decorators0.py: -------------------------------------------------------------------------------- 1 | 2 | def my_decorator(func): 3 | def wrap_func(*args, **kwargs): 4 | func(*args, **kwargs) 5 | return wrap_func 6 | 7 | @my_decorator 8 | def hello(name, age): 9 | print(f"Hello {name}, your age is {age}.") 10 | 11 | @my_decorator 12 | def logged_in(username): 13 | print(f"{username} is logged in.") 14 | 15 | hello("saurabh", 21) 16 | logged_in("saurabh") 17 | 18 | # using decorator is same as doing the below: 19 | # my_decorator(hello)() 20 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/decorators1.py: -------------------------------------------------------------------------------- 1 | 2 | def hello(): 3 | print("hello!") 4 | 5 | greet = hello 6 | 7 | del hello 8 | # here the function is not deleted, just the keyword, because greet is still pointing to the function memory 9 | # and python has not deleted it 10 | #(hello() # this will give error, because it has been deleted 11 | print(greet) 12 | greet() 13 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/decorators2.py: -------------------------------------------------------------------------------- 1 | 2 | def hello(func): 3 | func() 4 | 5 | def greet(): 6 | print("Hello!") 7 | 8 | hello(greet) 9 | 10 | # this example shows us that functions can also be used as variables. 11 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/08. Decorators/performance_decorator.py: -------------------------------------------------------------------------------- 1 | 2 | from time import time 3 | 4 | def performance(fn): 5 | def wrap_fn(*args, **kwargs): 6 | t1 = time() 7 | fn(*args, **kwargs) 8 | t2 = time() 9 | print(f'It took {t2-t1} sec') 10 | return wrap_fn 11 | 12 | @performance 13 | def long_fn(): 14 | for i in range(10000000): 15 | i*5 16 | 17 | long_fn() 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/09. Debugging/dubugging_pdb.py: -------------------------------------------------------------------------------- 1 | import pdb 2 | 3 | def add(n1, n2): 4 | return n1+n2 5 | 6 | pdb.set_trace() 7 | add(4, 'five') 8 | 9 | ''' 10 | Some useful commands for pdb: 11 | a : Print the argument list of the current function. 12 | step: to run the current line of code, and stop at the first possible occasion 13 | help: to list all the commands available 14 | help : to see what a command does 15 | continue: to continue the program till the error comes 16 | w: previous line, current line and next line content 17 | next: Continue execution until the next line in the current function is reached or it returns. 18 | 19 | We can change the variables value in the console window as well. 20 | we can type in the variable name to get its value 21 | ''' 22 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/10. Generators/fibonacci_list.py: -------------------------------------------------------------------------------- 1 | 2 | def fib(num): 3 | a = 0 4 | b= 1 5 | li=[] 6 | for i in range(num): 7 | li.append(a) 8 | temp = a 9 | a = b 10 | b = temp + b 11 | print(li) 12 | 13 | num = int(input("Enter a number: ")) 14 | fib(num) 15 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/10. Generators/fibonacci_range.py: -------------------------------------------------------------------------------- 1 | 2 | def fib(num): 3 | a = 0 4 | b= 1 5 | for i in range(num): 6 | yield a 7 | temp = a 8 | a = b 9 | b = temp + b 10 | 11 | num = int(input("Enter a number: ")) 12 | 13 | for i in fib(num): 14 | print(i) 15 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/10. Generators/generator.py: -------------------------------------------------------------------------------- 1 | 2 | # here we are generating our own generator function, just like a range(). 3 | 4 | def generator_fn(num): 5 | print("check") 6 | #yield 7 | for i in range(num): 8 | print("****") 9 | yield i*2 10 | print("####") 11 | 12 | g = generator_fn(3) 13 | print(g) 14 | print(next(g)) 15 | print(next(g)) 16 | print(next(g)) 17 | #print(next(g)) # StopIteration error 18 | print(g) 19 | 20 | for item in generator_fn(5): 21 | print(item) 22 | 23 | # here it goes to the generator_fn(), gets the 'i' value, pauses the function, until called for the 2nd time, 24 | # and so on, it doesn't store all the no.s in the memory (just the most recent one). 25 | 26 | ''' 27 | 'yield' pauses the function and comes back to it when we do something to it, which is called 'next'. 28 | 29 | if there is the keyword 'yield' written inside the function, then python recognises that its a 30 | generator function, and won't run the function until the function is being iterated. 31 | ''' 32 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/10. Generators/our_own_forloop.py: -------------------------------------------------------------------------------- 1 | 2 | def my_own_forloop(iterable): 3 | iterator = iter(iterable) 4 | while True: 5 | try: 6 | print(iterator) 7 | print(next(iterator)) 8 | except StopIteration: 9 | break 10 | 11 | my_own_forloop([1,2,3,4,5]) 12 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/10. Generators/our_own_range.py: -------------------------------------------------------------------------------- 1 | 2 | class OurOwnRange(): 3 | current = 0 4 | def __init__(self,first,last): 5 | self.first = first 6 | self.last = last 7 | 8 | def __iter__(self): 9 | return self 10 | 11 | def __next__(self): 12 | print("hehehheh") 13 | # if self.current < self.last: 14 | # num = OurOwnRange.current 15 | # OurOwnRange.current += 1 16 | # return num 17 | # raise StopIteration 18 | 19 | gen = OurOwnRange(0,10) 20 | print(gen) 21 | 22 | for i in gen: 23 | print(i) 24 | 25 | ''' 26 | loops by default deal with StopIteration error. they have build in functionality to handle them. 27 | ''' 28 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/11. Regular Expressions/email_password_regex.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | 4 | email_pattern = re.compile(r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)") 5 | check_email = email_pattern.fullmatch('saurabh_1089@gmail.com') 6 | 7 | password_patter = re.compile(r"([a-zA-Z0-9@#$%]{8,}$)") 8 | check_password = password_patter.fullmatch('12345678') 9 | 10 | if check_email and check_password: 11 | print("Both email and password are correct.") 12 | else: 13 | print("Try again.") 14 | 15 | ''' 16 | password is also checking for minimum 8 chars 17 | ''' 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/11. Regular Expressions/regular_exp.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | string = "this is a really cool string really!" 4 | 5 | a = re.search('really',string) 6 | print(a) 7 | 8 | # the below 4 commands will give error if the searching string does not exist. 9 | print(a.span()) 10 | print(a.start()) 11 | print(a.end()) 12 | print(a.group()) 13 | 14 | pattern = re.compile('really') 15 | 16 | b = pattern.search(string) 17 | c = pattern.findall(string) 18 | 19 | pattern = re.compile('this is a really cool string really!') 20 | d = pattern.fullmatch('this is a really cool string really!') 21 | e = pattern.fullmatch('hello this is a really cool string really!') # this should be exact match, otherwise returns none 22 | 23 | pattern = re.compile('really') 24 | f = pattern.match('really cool feature') # it starts matching from the first character otherwise returns none 25 | g = pattern.match('yo really') 26 | 27 | print(f"b: {b}") 28 | print(f"c: {c}") 29 | print(f"d: {d}") 30 | print(f"e: {e}") 31 | print(f"f: {f}") 32 | print(f"g: {g}") 33 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/12. Unit Testing/guess_game.py: -------------------------------------------------------------------------------- 1 | 2 | import random 3 | 4 | def run_guess(guess, answer): 5 | if 0 < guess < 11: 6 | if guess == answer: 7 | print('you are a genius!') 8 | return True 9 | else: 10 | print('hey bozo, I said 1~10') 11 | return False 12 | 13 | if __name__ == '__main__': # so that the game don't start while testing. 14 | answer = random.randint(1, 10) 15 | while True: 16 | try: 17 | guess = int(input('guess a number 1~10: ')) 18 | if (run_guess(guess, answer)): 19 | break 20 | except ValueError: 21 | print('please enter a number') 22 | continue 23 | 24 | ''' 25 | we test a function at a time. 26 | that is why it is called unit testing. 27 | hence we try to make pure functions and test them. 28 | ''' -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/12. Unit Testing/script.py: -------------------------------------------------------------------------------- 1 | 2 | def add(num): 3 | try: 4 | return int(num) + 5 5 | except ValueError as err: 6 | return err 7 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/12. Unit Testing/test.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | import script 4 | 5 | class TestMain(unittest.TestCase): # inheriting TestCase class 6 | 7 | def setUp(self): # this method will run before starting all the other test methods 8 | print("Starting a method/test: ") 9 | 10 | def test_add(self): 11 | '''This is the info for this particular test''' 12 | test_param = 10 13 | result = script.add(test_param) 14 | self.assertEqual(result,15) 15 | 16 | def test_add2(self): 17 | test_param = 'random string' 18 | result = script.add(test_param) 19 | self.assertTrue(isinstance(result,ValueError)) 20 | 21 | def tearDown(self): # this method will run after every test method. Generally used to reset/cleaning up data variables. 22 | print("Cleaning up....") 23 | 24 | 25 | class A: 26 | print("\nClass A") 27 | 28 | if __name__ == '__main__': 29 | unittest.main() # this will run the entire classes present in the file 30 | 31 | 32 | class B: 33 | print("Class B") 34 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/12. Unit Testing/test2.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | import script 4 | 5 | class TestMain(unittest.TestCase): # inheriting TestCase class 6 | def test_add(self): 7 | test_param = 10 8 | result = script.add(test_param) 9 | self.assertEqual(result,15) 10 | 11 | def test_add2(self): 12 | test_param = 'random string' 13 | result = script.add(test_param) 14 | self.assertTrue(isinstance(result,ValueError)) 15 | 16 | if __name__ == '__main__': 17 | unittest.main() 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/12. Unit Testing/test_guess_game.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | import guess_game 4 | 5 | class testGame(unittest.TestCase): 6 | def test_game(self): 7 | result = guess_game.run_guess(5,5) 8 | self.assertTrue(result) 9 | 10 | def test_game2(self): 11 | result = guess_game.run_guess(0,5) 12 | self.assertFalse(result) 13 | 14 | def test_game3(self): 15 | result = guess_game.run_guess(15,4) 16 | self.assertFalse(result) 17 | 18 | if __name__ == '__main__': 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/Job Scheduler/data.txt: -------------------------------------------------------------------------------- 1 | 4:30,30,Price Loader 2 | 3:00,15,Load Transactions 3 | 8:30,90,Balance Sheet 4 | 1:30,60,Web Refresh 5 | 15:00,20,Transaction Validator 6 | 18:00,75,Batch Process 7 | 19:15,15,Batch Report 8 | 2:30,30,Transaction Preprocess 9 | 21:00,30,Nightly Refresh 10 | 22:30,15,Batch Cleanup 11 | 10:30,15,This will reject 12 | 19:25,10,This will reject 13 | 5:15,30,Schedule Distribution 14 | 23:00,15,Test Insert 15 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/email_project/demo.py: -------------------------------------------------------------------------------- 1 | import time 2 | from random import randint, random, seed, choice 3 | from string import ascii_letters as letters 4 | 5 | def bisection_iter(n, arr): 6 | start = 0 7 | stop = len(arr)-1 8 | 9 | while start <= stop: 10 | mid = (start + stop)//2 11 | if n == arr[mid]: 12 | return mid, f"{n} found at index {mid}" 13 | 14 | elif n > arr[mid]: 15 | start = mid+1 16 | 17 | else: 18 | stop = mid-1 19 | 20 | return None, f"{n} not found in list" 21 | 22 | def analyze_func(func_name, *arr): 23 | tic = time.time() 24 | func_name(*arr) 25 | toc = time.time() 26 | seconds = toc-tic 27 | print(f"Time Elapsed while {func_name.__name__.capitalize()} --> {seconds:.5f}") 28 | 29 | 30 | seed(1) 31 | length_of_name = randint(1,15) 32 | 33 | def generate_name (): 34 | seed(1) 35 | length_of_name = randint(1,15) 36 | return ''.join(choice(letters) for i in range(length_of_name)) 37 | 38 | def get_domain(list_of_domain): 39 | return choice(list_of_domain) 40 | 41 | def generate_emails(list_of_domain, total_email): 42 | emails = [] 43 | for num in range(total_email): 44 | emails.append(generate_name()+"@"+get_domain(list_of_domain)) 45 | return emails -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/email_project/run.py: -------------------------------------------------------------------------------- 1 | from demo import bisection_iter, analyze_func, generate_emails 2 | 3 | list_of_domains = ['gmail.com', 'yahoo.com', 'hotmail.com'] 4 | 5 | total_email = int(input("Number of emails in the list : ")) 6 | 7 | emails = generate_emails(list_of_domains, total_email) 8 | 9 | email = 'shushrut@gmail.com' 10 | email2 = 'sk6554@gmail.com' 11 | emails.append(email) 12 | 13 | sorted_emails = sorted(emails) 14 | 15 | index, found = bisection_iter(email, sorted_emails) 16 | 17 | print(found) 18 | 19 | if index == None: 20 | print("Email not found") 21 | 22 | else: 23 | print(f"Element at index : {index} is {sorted_emails[index]}") 24 | 25 | analyze_func(bisection_iter, email, sorted_emails) 26 | analyze_func(generate_emails, list_of_domains, total_email) 27 | 28 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/hash_project/hash_algo.py: -------------------------------------------------------------------------------- 1 | class AlgoHashTable: 2 | 3 | def __init__ (self, size): 4 | self.size = size 5 | self.hash_table = self.create_buckets() 6 | 7 | def create_buckets(self): 8 | return [[] for _ in range(self.size)] 9 | 10 | def __str__(self): 11 | return "".join(str(item) for item in self.hash_table) 12 | 13 | 14 | 15 | def set_val(self, key, value): 16 | 17 | hashed_key = hash(key)%self.size 18 | bucket = self.hash_table[hashed_key] 19 | 20 | found_key = False 21 | 22 | for index, record in enumerate(bucket): 23 | record_key, record_value = record 24 | if record_key == key: 25 | found_key = True 26 | break 27 | 28 | if found_key: 29 | bucket[index] = (key, value) 30 | 31 | else: 32 | bucket.append((key, value)) 33 | 34 | def get_val(self, key): 35 | 36 | hashed_key = hash(key)%self.size 37 | bucket = self.hash_table[hashed_key] 38 | found_key = False 39 | 40 | for index, record in enumerate(bucket): 41 | record_key, record_value = record 42 | if record_key == key: 43 | found_key = True 44 | break 45 | 46 | if found_key: 47 | return record_value 48 | 49 | else: 50 | return f"{key} not found" 51 | 52 | 53 | 54 | 55 | hash_table = AlgoHashTable(200) 56 | 57 | file = open("data.txt") 58 | 59 | lines = file.readline().strip().split(':') 60 | 61 | for line in file: 62 | key, value = line.split(":") 63 | hash_table.set_val(key, value) 64 | 65 | 66 | print(hash_table) 67 | 68 | print("-"*100) 69 | 70 | print(hash_table.get_val("ahlrdmukjn@yaexample.com")) 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/hash_project/project_script.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | from string import ascii_lowercase as letters 3 | 4 | list_of_domains = ['yaexample.com','goexample.com','example.com'] 5 | 6 | quotes = [ 'Luck is what happens when preparation meets opportunity', 7 | 'All cruelty springs from weakness', 8 | 'Begin at once to live, and count each separate day as a separate life', 9 | 'Throw me to the wolves and I will return leading the pack'] 10 | 11 | def generate_name(length_of_name): 12 | return ''.join(choice(letters) for i in range(length_of_name)) 13 | 14 | def get_domain(list_of_domains): 15 | return choice(list_of_domains) 16 | 17 | def get_quotes(list_of_quotes): 18 | return choice(list_of_quotes) 19 | 20 | def generate_records(length_of_name, list_of_domains, total_records, list_of_quotes): 21 | with open("./data.txt", "w") as to_write: 22 | for num in range(total_records): 23 | key = generate_name(length_of_name)+"@"+get_domain(list_of_domains) 24 | value = get_quotes(quotes) 25 | to_write.write(key + ":" + value + "\n") 26 | to_write.write("mashrur@example.com:Don't let me leave Murph\n") 27 | to_write.write("evgeny@example.com:All I do is win win win no matter what!\n") 28 | 29 | generate_records(10, list_of_domains, 199, quotes) 30 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/hash_project/tempCodeRunnerFile.py: -------------------------------------------------------------------------------- 1 | print(key) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/recursion_miniprojects/countdown_timer.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def recur_countdown_time(n): 4 | if n == 0: 5 | return n 6 | else: 7 | print(n) 8 | time.sleep(2) 9 | return recur_countdown_time(n-1) 10 | 11 | def iter_countdown_timer(n): 12 | while n>0: 13 | print(n) 14 | time.sleep(1) 15 | n -=1 16 | print(n) 17 | 18 | z = int(input("Enter the starting number : ")) 19 | print(f"Counting down from {z}") 20 | # iter_countdown_timer(z) 21 | 22 | print(recur_countdown_time(z)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/recursion_miniprojects/factorial.py: -------------------------------------------------------------------------------- 1 | def factorial_recur(n): 2 | if n == 0: 3 | return 1 4 | else : 5 | return n*factorial_recur(n-1) 6 | 7 | z = int(input("Enter the value to get factorial : ")) 8 | print(f"The value of {z}! is {factorial_recur(z)}") -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/recursion_miniprojects/fibonacci.py: -------------------------------------------------------------------------------- 1 | def fib_recur(z): 2 | if z == 0: 3 | return 0 4 | elif z == 1: 5 | return 1 6 | else: 7 | return fib_recur(z-1) + fib_recur(z-2) 8 | 9 | def fib_runner(z): 10 | print(f"The {z}th number in the fibonacci sequence is {fib_recur(z)}") 11 | 12 | z = int(input("Enter the number you want fibonacci value as : ")) 13 | fib_runner(z) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/recursion_miniprojects/multi_tasker.py: -------------------------------------------------------------------------------- 1 | #COUNTDOWN TIMER : 2 | import time 3 | 4 | def recur_countdown_time(n): 5 | if n == 0: 6 | return n 7 | else: 8 | print(n) 9 | time.sleep(1) 10 | return recur_countdown_time(n-1) 11 | 12 | def iter_countdown_timer(n): 13 | while n>0: 14 | print(n) 15 | time.sleep(1) 16 | n -=1 17 | print(n) 18 | 19 | #FACTORIAL : 20 | 21 | def factorial_recur(n): 22 | if n == 0: 23 | return 1 24 | else : 25 | return n*factorial_recur(n-1) 26 | 27 | #FIBONACCI SEQUENCE : 28 | 29 | def fib_recur(z): 30 | if z == 0: 31 | return 0 32 | elif z == 1: 33 | return 1 34 | else: 35 | return fib_recur(z-1) + fib_recur(z-2) 36 | 37 | def fib_runner(z): 38 | print(f"The {z}th number in the fibonacci sequence is {fib_recur(z)}") 39 | 40 | 41 | 42 | x = int(input("Type 1 for Countdown \nType 2 for Factorial \nType 3 for Fibonacci Sequence \n: ")) 43 | 44 | if x == 1: 45 | z = int(input("Enter the starting number : ")) 46 | print(f"Counting down from {z}") 47 | print(recur_countdown_time(z)) 48 | 49 | elif x == 2: 50 | z = int(input("Enter the value to get factorial : ")) 51 | print(f"The value of {z}! is {factorial_recur(z)}") 52 | 53 | elif x == 3: 54 | z = int(input("Enter the number you want fibonacci value as : ")) 55 | fib_runner(z) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/recursion_miniprojects/tempCodeRunnerFile.py: -------------------------------------------------------------------------------- 1 | x = input("Type 1 for Countdown \nType 2 for Factorial \nType 3 for Fibonacci Sequence \n: ") 2 | 3 | if (x == 1): 4 | z = int(input("Enter the starting number : ")) 5 | print(f"Counting down from {z}") 6 | print(recur_countdown_time(z)) 7 | 8 | elif (x == 2): 9 | z = int(input("Enter the value to get factorial : ")) 10 | print(f"The value of {z}! is {factorial_recur(z)}") 11 | 12 | elif (x == 3): 13 | z = int(input("Enter the number you want fibonacci value as : ")) 14 | fib_runner(z) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/runtime_analyser/analyser.py: -------------------------------------------------------------------------------- 1 | from sorts import quicksort, mergersort, bubblesort, insertionsort, selectionsort 2 | import random 3 | import time 4 | 5 | 6 | def create_random_list(size, max_val): 7 | ran_list = [] 8 | for num in range(size): 9 | ran_list.append(random.randint(1,max_val)) 10 | return(ran_list) 11 | 12 | 13 | def analyze_func(func_name, arr): 14 | tic = time.time() 15 | func_name(arr) 16 | toc = time.time() 17 | seconds = toc-tic 18 | print(f"Time Elapsed while {func_name.__name__.capitalize()} --> {seconds:.5f}") 19 | 20 | size = int(input("What size of list you want to create? ")) 21 | max = int(input("What is the max value of the range? ")) 22 | run_time = int(input("How many times you want to run : ")) 23 | 24 | 25 | for num in range(run_time): 26 | print(f"Run : {num+1}") 27 | l = create_random_list(size,max) 28 | analyze_func(quicksort, l) 29 | analyze_func(mergersort, l) 30 | analyze_func(bubblesort, l.copy()) 31 | analyze_func(sorted, l) 32 | analyze_func(insertionsort, l.copy()) 33 | analyze_func(selectionsort, l.copy()) 34 | print("-"*70) 35 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/13. Mini-Projects/runtime_analyser/sorts.py: -------------------------------------------------------------------------------- 1 | def quicksort(arr): 2 | if len(arr)<2: 3 | return arr 4 | else: 5 | pivot = arr[-1] 6 | smaller, equal, larger = [], [], [] 7 | for num in arr: 8 | if num < pivot: 9 | smaller.append(num) 10 | 11 | elif num == pivot: 12 | equal.append(num) 13 | 14 | else: 15 | larger.append(num) 16 | 17 | return quicksort(smaller)+ equal+ quicksort(larger) 18 | 19 | 20 | def merge_sorted(arr1,arr2): 21 | sorted_arr = [] 22 | i, j = 0, 0 23 | 24 | while i < len(arr1) and j < len(arr2): 25 | 26 | if arr1[i] < arr2[j]: 27 | sorted_arr.append(arr1[i]) 28 | i += 1 29 | 30 | else: 31 | sorted_arr.append(arr2[j]) 32 | j += 1 33 | 34 | while j < len(arr2): 35 | sorted_arr.append(arr2[j]) 36 | j += 1 37 | 38 | 39 | while i < len(arr1): 40 | sorted_arr.append(arr1[i]) 41 | i += 1 42 | 43 | return sorted_arr 44 | 45 | def mergersort(arr): 46 | if len(arr) < 2: 47 | return arr[:] 48 | else: 49 | middle = len(arr)//2 50 | l1 = mergersort(arr[:middle]) 51 | l2 = mergersort(arr[middle:]) 52 | return merge_sorted(l1, l2) 53 | 54 | 55 | def bubblesort(arr): 56 | swap_happened = True 57 | while swap_happened: 58 | swap_happened = False 59 | for num in range(len(arr)-1): 60 | if arr[num] > arr[num+1]: 61 | swap_happened = True 62 | arr[num], arr[num+1] = arr[num+1], arr[num] 63 | 64 | def insertionsort(arr): 65 | for key in range(1, len(arr)): 66 | if arr[key] < arr[key-1]: 67 | j = key 68 | while j > 0 and arr[j] < arr[j-1]: 69 | arr[j], arr[j-1] = arr[j-1], arr[j] 70 | j -= 1 71 | 72 | def selectionsort(arr): 73 | spot_marker = 0 74 | while spot_marker < len(arr): 75 | for num in range(spot_marker, len(arr)): 76 | if arr[num] < arr[spot_marker]: 77 | arr[spot_marker], arr[num] = arr[num], arr[spot_marker] 78 | spot_marker += 1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 01 - two sum.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. 3 | 4 | You may assume that each input would have exactly one solution, and you may not use the same element twice. 5 | 6 | You can return the answer in any order. 7 | 8 | Question: https://leetcode.com/problems/two-sum/ 9 | 10 | """ 11 | #O(n)^2 solution - brute force 12 | class Solution: 13 | def twoSum(self, nums: List[int], target: int) -> List[int]: 14 | for i in range(len(nums)): 15 | for j in range(i+1, len(nums)): 16 | if nums[i] + nums[j] == target: 17 | return [i,j] 18 | return [] 19 | 20 | #O(n) solution - hash maps 21 | 22 | class Solution: 23 | def twoSum(self, nums: List[int], target: int) -> List[int]: 24 | prevMap = {} 25 | 26 | for i, n in enumerate(nums): 27 | diff = target-n 28 | if diff in prevMap: 29 | return[prevMap[diff],i] 30 | prevMap[n] = i 31 | return -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 02 - add two numbers.py: -------------------------------------------------------------------------------- 1 | # add two numbers | leetcode 02 | https://leetcode.com/problems/add-two-numbers/ 2 | 3 | # Definition for singly-linked list. 4 | class ListNode: 5 | def __init__(self, val=0, next=None): 6 | self.val = val 7 | self.next = next 8 | 9 | class Solution: 10 | def addTwoNumbers(self, l1: list[ListNode], l2: list[ListNode]) -> list[ListNode]: 11 | res = ListNode() 12 | head = res 13 | 14 | while l1 != None or l2 != None: 15 | if l1 == None: 16 | this_val = res.val + l2.val 17 | l2 = l2.next 18 | elif l2 == None: 19 | this_val = res.val + l1.val 20 | l1 = l1.next 21 | else: 22 | this_val = res.val + l1.val + l2.val 23 | l1, l2 = l1.next, l2.next 24 | 25 | this_digit = this_val % 10 26 | next_digit = this_val // 10 27 | 28 | res.val = this_digit 29 | if l1 != None or l2 != None: 30 | res.next = ListNode(next_digit) 31 | res = res.next 32 | 33 | if next_digit > 0: 34 | res.next = ListNode(next_digit) 35 | res = res.next 36 | 37 | return head 38 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 03 - longest substring without repeating characters.py: -------------------------------------------------------------------------------- 1 | # longest substring without repeating characters | leetcode 03 | https://leetcode.com/problems/longest-substring-without-repeating-characters 2 | # sliding window; remove elements until last occurence of current duplicate 3 | 4 | class Solution: 5 | def lengthOfLongestSubstring(self, s: str) -> int: 6 | ptrL = 0 7 | seen = dict() 8 | longest = 0 9 | 10 | for ptrR in range(len(s)): 11 | while seen.get(s[ptrR]) is not None: 12 | seen.pop(s[ptrL]) 13 | ptrL += 1 14 | seen[s[ptrR]] = True 15 | longest = max(ptrR - ptrL + 1, longest) 16 | 17 | return longest 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 09 - palindrome number.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer x, return true if x is palindrome integer. 3 | 4 | An integer is a palindrome when it reads the same backward as forward. 5 | 6 | For example, 121 is a palindrome while 123 is not. 7 | 8 | Question: https://leetcode.com/problems/palindrome-number/ 9 | 10 | """ 11 | 12 | 13 | class Solution: 14 | def isPalindrome(self, x: int) -> bool: 15 | if x < 0: 16 | return False 17 | c = x 18 | b = 0 19 | 20 | while c: 21 | b = b * 10 + c % 10 22 | c //= 10 23 | 24 | return b == x 25 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 100 - same tree.py: -------------------------------------------------------------------------------- 1 | # same tree | leetcode 100 | https://leetcode.com/problems/same-tree/ 2 | # given a root of each of the two trees, check if the trees are the exact same or not 3 | # method: (DFS) inorder traversal to compare left subtree, current node and right subtree 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def isSameTree(self, p, q): 14 | if p is None and q is None: 15 | return True 16 | 17 | if p is None or q is None: 18 | return False 19 | 20 | lResult = self.isSameTree(p.left, q.left) 21 | nResult = p.val == q.val 22 | rResult = self.isSameTree(p.right, q.right) 23 | 24 | return lResult and nResult and rResult -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 101 - symmetric tree.py: -------------------------------------------------------------------------------- 1 | # symmetric tree | leetcode 101 | https://leetcode.com/problems/symmetric-tree/ 2 | # given the root of a binary tree, check whether it is a mirror of itself 3 | # method: recursively compare two copies of the same tree 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def isSymmetric(self, root): 14 | def checkSymm(copy1, copy2): 15 | if copy1 is None and copy2 is None: 16 | return True 17 | if copy1 is None or copy2 is None: 18 | return False 19 | 20 | return (copy1.val == copy2.val) and checkSymm(copy1.left, copy2.right) and checkSymm(copy1.right, copy2.left) 21 | 22 | return checkSymm(root, root) 23 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1011 - capacity to ship packages.py: -------------------------------------------------------------------------------- 1 | # capacity to ship packages within D days | leetcode 1011 | https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/ 2 | # binary search on a range of min and max capacity required 3 | # min capacity = max(weights) and max capacity = sum(weights) 4 | 5 | class Solution: 6 | def shipWithinDays(self, weights: list[int], days: int) -> int: 7 | low, high = max(weights), sum(weights) 8 | res = high 9 | 10 | # check if days required for a capacity is less than D 11 | def isPossible (capacity): 12 | daysReq = 1 13 | window = capacity 14 | for weight in weights: 15 | if window - weight < 0: 16 | window = capacity 17 | daysReq += 1 18 | window -= weight 19 | 20 | return daysReq <= days 21 | 22 | # binary search on [min...max] 23 | while low <= high: 24 | mid = (high + low) // 2 25 | 26 | if isPossible(mid): 27 | res = min(res, mid) 28 | high = mid - 1 29 | else: 30 | low = mid + 1 31 | 32 | return res 33 | 34 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 102 - level order traversal of tree.py: -------------------------------------------------------------------------------- 1 | # binary tree level order traversal | leetcode 102 | https://leetcode.com/problems/binary-tree-level-order-traversal/ 2 | # order: from left to right, level by level 3 | # method: breadth first search 4 | 5 | #Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | 14 | # l to r, level by level 15 | def levelOrder(self, root): 16 | res = [] 17 | tempQ = [] 18 | 19 | # queue to track visits 20 | tempQ.append(root) 21 | LtempQ = len(tempQ) 22 | 23 | # keep iterating till: 24 | # the track queue is empty 25 | while LtempQ is not 0: 26 | LtempQ = len(tempQ) 27 | level = [] 28 | for i in range(LtempQ): 29 | node = tempQ.pop(0) # pop this node from queue (visited) 30 | if node is not None: 31 | level.append(node.val) # add this node to the level 32 | tempQ.append(node.left) # add left child to queue (to visit) 33 | tempQ.append(node.right) # add right child to queue (to visit) 34 | if len(level) is not 0: 35 | res.append(level) 36 | 37 | return res 38 | 39 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1022 - sum of root-leaf binary num.py: -------------------------------------------------------------------------------- 1 | # sum of root to leaf binary numbers | leetcode 1022 | https://leetcode.com/problems/sum-of-root-to-leaf-binary-numbers/ 2 | # method: (dfs) for each node, left-shift 1 bit and add val. 3 | # return sum of both left and right subtree 4 | # return sum till now at each leaf 5 | 6 | # Definition for a binary tree node. 7 | class TreeNode: 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | class Solution: 14 | def sumRootToLeaf(self, root) -> int: 15 | def dfsSum(root, total): 16 | if root is None: 17 | return 0 18 | 19 | total = (total << 1) | root.val 20 | 21 | if root.left is None and root.right is None: 22 | return total 23 | 24 | return dfsSum(root.left, total) + dfsSum(root.right, total) 25 | 26 | return dfsSum(root, 0) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 103 - zigzag level order traversal.py: -------------------------------------------------------------------------------- 1 | # binary tree zigzag level order traversal | leetcode 103 | https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal 2 | # use flag to keep track of reversed levels; O(n) because worst case is full level - n/2 elements 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def zigzagLevelOrder(self, root: TreeNode) -> list[list[int]]: 13 | res = [] 14 | tempQ = [] 15 | zig = False 16 | 17 | # queue to track visits 18 | tempQ.append(root) 19 | LtempQ = len(tempQ) 20 | 21 | # keep iterating till: 22 | # the track queue is empty 23 | while LtempQ is not 0: 24 | LtempQ = len(tempQ) 25 | level = [] 26 | for i in range(LtempQ): 27 | node = tempQ.pop(0) # pop this node from queue (visited) 28 | if node is not None: 29 | level.append(node.val) # add this node to the level 30 | tempQ.append(node.left) # add left child to queue (to visit) 31 | tempQ.append(node.right) # add right child to queue (to visit) 32 | 33 | if len(level) is not 0: # add level and reverse if zig 34 | res.append(reversed(level) if zig else level) 35 | zig = not zig 36 | 37 | return res -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 104 - max depth of binary tree.py: -------------------------------------------------------------------------------- 1 | # max depth of binary tree | leetcode 104 | https://leetcode.com/problems/maximum-depth-of-binary-tree/ 2 | # given the root of a binary tree, return its maximum depth. 3 | # method: recursively increment left and right count for each new node and return max 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def maxDepth(self, root): 14 | def findDepth(node): 15 | if node is None: 16 | return -1 17 | 18 | ldepth = findDepth(node.left) 19 | rdepth = findDepth(node.right) 20 | 21 | if ldepth > rdepth: 22 | return ldepth + 1 23 | else: 24 | return rdepth + 1 25 | 26 | return findDepth(root) + 1 27 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 108 - sorted array to bst.py: -------------------------------------------------------------------------------- 1 | # sorted array to bst | leetcode 108 | https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/ 2 | # given a sorted array of int, convert it to a balanced binary search tree 3 | # method: take middle element as root, use recursion for depth first, add each subtree as a balanced bst 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def sortedArrayToBST(self, nums): 14 | if not nums: 15 | return None 16 | 17 | mid = len(nums) // 2 18 | 19 | root = TreeNode(val = nums[mid]) 20 | root.left = self.sortedArrayToBST(nums[:mid]) 21 | root.right = self.sortedArrayToBST(nums[mid+1:]) 22 | 23 | return root -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 110 - balanced bst.py: -------------------------------------------------------------------------------- 1 | # balanced bst | leetcode 110 | https://leetcode.com/problems/balance-a-binary-search-tree/ 2 | # given a bst, check if it is balanced or not 3 | # method: for each subtree, check if its left and right subtrees and balanced, and return the maxDepth + 1 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def isBalanced(self, root) -> bool: 14 | def dfs(root): 15 | if root is None: return [True, 0] 16 | 17 | left, right = dfs(root.left), dfs(root.right) 18 | balanced = left[0] and right[0] and abs(left[1] - right[1]) <= 1 19 | 20 | return [balanced, max(left[1], right[1]) + 1] 21 | 22 | return dfs(root)[0] -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 112 - path sum.py: -------------------------------------------------------------------------------- 1 | # path sum | leetcode 112 | https://leetcode.com/problems/path-sum/ 2 | # given the root of a tree, check if there exists a path whose sum equals target 3 | # method: (dfs) update curSum for each node, and return true or false for each subtree 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | def hasPathSum(self, root, targetSum): 14 | 15 | def dfs(root, curSum): 16 | if root is None: 17 | return False 18 | 19 | curSum += root.val 20 | if root.left is None and root.right is None: 21 | return curSum == targetSum 22 | 23 | return dfs(root.left, curSum) or dfs(root.right, curSum) 24 | 25 | return dfs(root, 0) 26 | 27 | 28 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 114 - binary tree preorder traversal.py: -------------------------------------------------------------------------------- 1 | # binary tree preorder traversal | leetcode 94 | https://leetcode.com/problems/binary-tree-preorder-traversal/ 2 | # method: node, left subtree, right subtree recursively 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def inorderTraversal(self, root): 13 | travList = [] 14 | 15 | def traverse(root, travList): 16 | if root is None: 17 | return None 18 | 19 | travList.append(root.val) # add this node 20 | traverse(root.left, travList) # traverse left subtree and add nodes 21 | traverse(root.right, travList) # traverse right subtree and add nodes 22 | 23 | traverse(root, travList) 24 | return travList 25 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1147 - largest number at least twice of others.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given an integer array nums where the largest integer is unique. 3 | 4 | Determine whether the largest element in the array is at least twice as much as every other number in the array. If it is, return the index of the largest element, or return -1 otherwise. 5 | 6 | Question: https://leetcode.com/explore/learn/card/array-and-string/201/introduction-to-array/1147/ 7 | 8 | """ 9 | 10 | class Solution: 11 | def dominantIndex(self, nums: List[int]) -> int: 12 | if len(nums) == 1: 13 | return 0 14 | a = max(nums) 15 | for i in range(len(nums)): 16 | if nums[i] == a: 17 | b = i 18 | nums.remove(a) 19 | count = 0 20 | for i in nums: 21 | if (a >= 2*i): 22 | count = count +1 23 | if count == len(nums): 24 | return b 25 | else: 26 | return -1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 121 - best time to buy and sell stock.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given an array prices where prices[i] is the price of a given stock on the ith day. 3 | 4 | You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock. 5 | 6 | Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0. 7 | 8 | Question: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 9 | 10 | """ 11 | class Solution: 12 | def maxProfit(self, prices: List[int]) -> int: 13 | l = 0 14 | r = 1 15 | maxP = 0 16 | 17 | while r int: 6 | if nums == []: 7 | return 0 8 | 9 | all = set(nums) 10 | longest = 0 11 | 12 | for each in all: 13 | if each - 1 not in all: 14 | curr = each 15 | seq = 1 16 | while curr + 1 in all: 17 | seq += 1 18 | curr = curr + 1 19 | if seq > longest: 20 | longest = seq 21 | 22 | return longest -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 13 - roman to integer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. 3 | 4 | Symbol Value 5 | I 1 6 | V 5 7 | X 10 8 | L 50 9 | C 100 10 | D 500 11 | M 1000 12 | For example, 2 is written as II in Roman numeral, just two one's added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II. 13 | 14 | Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used: 15 | 16 | I can be placed before V (5) and X (10) to make 4 and 9. 17 | X can be placed before L (50) and C (100) to make 40 and 90. 18 | C can be placed before D (500) and M (1000) to make 400 and 900. 19 | Given a roman numeral, convert it to an integer. 20 | 21 | Questions: https://leetcode.com/problems/roman-to-integer/ 22 | 23 | """ 24 | 25 | 26 | class Solution: 27 | def romanToInt(self, s: str) -> int: 28 | roman = {'I':1, 'V':5, 'X': 10, 'L':50, 'C':100, 'D':500, 'M':1000} 29 | 30 | res = 0 31 | 32 | for i in range(len(s)): 33 | if i+1 int: 13 | result = 0 14 | maxHeight = 0 15 | 16 | # dfs 17 | def dfs(node, currHeight): 18 | nonlocal result, maxHeight 19 | if node is None: 20 | return 21 | 22 | # reset if current height is not max 23 | if currHeight > maxHeight: 24 | result = 0 25 | maxHeight = currHeight 26 | 27 | # add to sum if current height is max 28 | if currHeight == maxHeight: 29 | result += node.val 30 | 31 | # recursively traverse left and right subtrees 32 | dfs(node.left, currHeight + 1) 33 | dfs(node.right, currHeight + 1) 34 | 35 | dfs(root, 0) 36 | return result 37 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1305 - all elements in two binary search trees.py: -------------------------------------------------------------------------------- 1 | # all elements in two bst | leetcode 1305 | https://leetcode.com/problems/all-elements-in-two-binary-search-trees/ 2 | # method: dfs, sort 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def getAllElements(self, root1: TreeNode, root2: TreeNode) -> list[int]: 13 | elements = [] 14 | 15 | def dfs(node): 16 | if node is None: 17 | return 18 | 19 | dfs(node.left) 20 | elements.append(node.val) 21 | dfs(node.right) 22 | 23 | dfs(root1) 24 | dfs(root2) 25 | elements.sort() 26 | return elements 27 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 133 - clone graph.py: -------------------------------------------------------------------------------- 1 | # clone graph | leetcode 133 | https://leetcode.com/problems/clone-graph/ 2 | # method: depth first search, recursively add neighbours 3 | 4 | # Definition for a Node. 5 | class Node: 6 | def __init__(self, val = 0, neighbors = None): 7 | self.val = val 8 | self.neighbors = neighbors if neighbors is not None else [] 9 | 10 | class Solution: 11 | def cloneGraph(self, node: Node): 12 | oldToNew = {} 13 | 14 | def dfs(node): 15 | if node in oldToNew: 16 | return oldToNew[node] 17 | 18 | duplicate = Node(node.val) 19 | oldToNew[node] = duplicate 20 | for neighbour in node.neighbors: 21 | duplicate.neighbors.append(dfs(neighbour)) 22 | 23 | return duplicate 24 | 25 | return dfs(node) if node else None 26 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1379 - corresponding target in cloned tree.py: -------------------------------------------------------------------------------- 1 | # corresponding node in a clone of the binary tree | leetcode 1379 | https://leetcode.com/problems/find-a-corresponding-node-of-a-binary-tree-in-a-clone-of-that-tree/ 2 | # return a reference to the same node in a cloned tree 3 | # method: traverse through the original and the cloned tree parallely until the original matches the target 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, x): 8 | self.val = x 9 | self.left = None 10 | self.right = None 11 | 12 | class Solution: 13 | def getTargetCopy(self, original: TreeNode, cloned: TreeNode, target: TreeNode) -> TreeNode: 14 | self.clonedTarget = None 15 | def inorderTraversal(original, cloned): 16 | if original: 17 | inorderTraversal(original.left, cloned.left) 18 | if original is target: 19 | self.clonedTarget = cloned 20 | inorderTraversal(original.right, cloned.right) 21 | 22 | inorderTraversal(original, cloned) 23 | return self.clonedTarget -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1382 - balance a bst.py: -------------------------------------------------------------------------------- 1 | # balance a bst | leetcode 1382 | https://leetcode.com/problems/balance-a-binary-search-tree/ 2 | # given a bst, return a balanced bst 3 | # method: use inorder traversal to make a sorted array, convert sorted array to balanced bst 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | class Solution: 13 | # convert sorted array to bst 14 | def sortedArrayToBST(self, nums): 15 | if not nums: 16 | return None 17 | 18 | mid = len(nums) // 2 19 | 20 | root = TreeNode(val = nums[mid]) 21 | root.left = self.sortedArrayToBST(nums[:mid]) 22 | root.right = self.sortedArrayToBST(nums[mid+1:]) 23 | 24 | return root 25 | 26 | # in-order traveral gives sorted array 27 | def inorderTraversal(self, root): 28 | travList = [] 29 | 30 | def traverse(root, travList): 31 | if root is None: 32 | return None 33 | 34 | traverse(root.left, travList) 35 | travList.append(root.val) 36 | traverse(root.right, travList) 37 | 38 | traverse(root, travList) 39 | return travList 40 | 41 | # balance a binary search tree 42 | def balanceBST(self, root): 43 | return self.sortedArrayToBST(self.inorderTraversal(root)) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 14 - longest common prefix.py: -------------------------------------------------------------------------------- 1 | """ 2 | Write a function to find the longest common prefix string amongst an array of strings. 3 | 4 | If there is no common prefix, return an empty string "". 5 | 6 | Questions: https://leetcode.com/problems/longest-common-prefix/ 7 | 8 | """ 9 | 10 | class Solution: 11 | def longestCommonPrefix(self, strs: List[str]) -> str: 12 | res = "" 13 | n = len(strs) 14 | strs.sort() 15 | first = strs[0] 16 | last = strs[n-1] 17 | for i in range(len(first)): 18 | if first[i] != last[i]: 19 | return res 20 | else: 21 | res = res + first[i] 22 | return res 23 | 24 | 25 | 26 | # for i in range(len(strs[0])): 27 | # for s in strs: 28 | # if i == len(s) or s[i] != strs[0][i]: 29 | # return res 30 | 31 | # res += strs[0][i] 32 | 33 | # return res -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 15 - three sum.py: -------------------------------------------------------------------------------- 1 | # three sum | leetcode 15 | https://leetcode.com/problems/3sum/ 2 | # - sorted; nested loop; outer loop for first element 3 | # - inner loop for two sum on rest of list 4 | # - avoid duplicates by shifting window till last occurrence 5 | 6 | class Solution: 7 | def threeSum(self, nums: list[int]) -> list[list[int]]: 8 | nums.sort() 9 | N = len(nums) 10 | triplets = [] 11 | for i in range(N): 12 | if i > 0 and nums[i] == nums[i - 1]: 13 | continue 14 | 15 | ptrL = i + 1 16 | ptrR = N - 1 17 | while ptrL < ptrR: 18 | s = nums[i] + nums[ptrL] + nums[ptrR] 19 | if s > 0: 20 | ptrR -= 1 21 | elif s < 0: 22 | ptrL += 1 23 | else: 24 | triplets.append([nums[i], nums[ptrL], nums[ptrR]]) 25 | ptrL += 1 26 | while nums[ptrL] == nums[ptrL - 1] and ptrL < ptrR: 27 | ptrL += 1 28 | 29 | return triplets -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 162 - peak element.py: -------------------------------------------------------------------------------- 1 | # find peak element | leetcode 162 | https://leetcode.com/problems/find-peak-element/ 2 | # using binary search to determine 3 | # if the "middle" element is on a +ve / -ve slope 4 | 5 | class Solution: 6 | def findPeakElement(self, nums: list[int]) -> int: 7 | a = 0 8 | b = len(nums) - 1 9 | while a < b: 10 | k = (a + b) // 2 11 | if nums[k] > nums[k + 1]: 12 | b = k 13 | else: 14 | a = k + 1 15 | 16 | return a -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 167 - two sum II.py: -------------------------------------------------------------------------------- 1 | # two sum II - input array is sorted | leetcode 167 | https://leetcode.com/problems/two-sum-ii-input-array-is-sorted 2 | # use two pointers on sorted array; if sum > target slide window left, else slide window right 3 | 4 | class Solution: 5 | def twoSum(self, numbers: list[int], target: int) -> list[int]: 6 | ptrL = 0 7 | ptrR = 1 8 | N = len(numbers) 9 | 10 | while ptrR < N: 11 | s = numbers[ptrR] + numbers[ptrL] 12 | if s == target: 13 | return [ptrL + 1, ptrR + 1] 14 | elif s < target: 15 | ptrL += 1 16 | ptrR += 1 17 | else: 18 | ptrL -= 1 19 | 20 | # unreachable for testcases with exactly one solution 21 | return [-1, -1] -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1971 - find if path exists in a graph.py: -------------------------------------------------------------------------------- 1 | # find if path exists in a graph | leetcode 1971 | https://leetcode.com/problems/find-if-path-exists-in-graph/ 2 | # method: adjacency list, visited and toVisit lists 3 | 4 | from collections import defaultdict 5 | 6 | class Solution: 7 | def validPath(self, n: int, edges: list[list[int]], source: int, destination: int) -> bool: 8 | # edge case 9 | if n == 1 and source == destination: 10 | return True 11 | 12 | edgeMap = defaultdict(list) # adjacency list 13 | for edge in edges: 14 | edgeMap[edge[0]].append(edge[1]) 15 | edgeMap[edge[1]].append(edge[0]) 16 | 17 | visited = set() # set of visited nodes 18 | toVisit = [edgeMap[source]] # set of nodes to visit 19 | 20 | # while there are nodes to visit 21 | while toVisit: 22 | 23 | # this node is now visited 24 | nodes = toVisit.pop() 25 | 26 | # for each node in the adjacent nodes 27 | for node in nodes: 28 | if node == destination: 29 | return True 30 | 31 | # if node wasn't visited 32 | # visit its adjacent nodes 33 | elif node not in visited: 34 | visited.add(node) 35 | toVisit.append(edgeMap[node]) 36 | 37 | # if node was visited 38 | # do nothing 39 | 40 | # if no more nodes to visit 41 | # and still no path 42 | return False 43 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 1991 - find the middle index in array.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Given a 0-indexed integer array nums, find the leftmost middleIndex (i.e., the smallest amongst all the possible ones). 4 | 5 | A middleIndex is an index where nums[0] + nums[1] + ... + nums[middleIndex-1] == nums[middleIndex+1] + nums[middleIndex+2] + ... + nums[nums.length-1]. 6 | 7 | If middleIndex == 0, the left side sum is considered to be 0. Similarly, if middleIndex == nums.length - 1, the right side sum is considered to be 0. 8 | 9 | Return the leftmost middleIndex that satisfies the condition, or -1 if there is no such index. 10 | 11 | Question: https://leetcode.com/problems/find-the-middle-index-in-array/ 12 | 13 | """ 14 | 15 | 16 | class Solution: 17 | def findMiddleIndex(self, nums: List[int]) -> int: 18 | total = sum(nums) 19 | 20 | leftSum = 0 21 | for i in range(len(nums)): 22 | rightSum = total - nums[i] - leftSum 23 | if leftSum == rightSum: 24 | return i 25 | leftSum += nums[i] 26 | return -1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 20 - valid parentheses.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. 3 | 4 | An input string is valid if: 5 | 6 | Open brackets must be closed by the same type of brackets. 7 | Open brackets must be closed in the correct order. 8 | 9 | Question: https://leetcode.com/problems/valid-parentheses/ 10 | 11 | 12 | """ 13 | 14 | 15 | class Solution: 16 | def isValid(self, s: str) -> bool: 17 | para = {')':'(', ']':'[', '}':'{'} 18 | op = ['(','[', '{'] 19 | stack = [] 20 | 21 | for c in s: 22 | if c in op: 23 | stack.append(c) 24 | 25 | elif c in para: 26 | if len(stack) != 0 and stack[-1] == para[c]: 27 | stack.pop() 28 | else: 29 | return False 30 | 31 | if len(stack) == 0: 32 | return True 33 | else: 34 | return False 35 | 36 | 37 | 38 | 39 | 40 | 41 | # if c in para: 42 | # if len(stack) != 0 and stack[-1] == para[c]: 43 | # stack.pop() 44 | # else: 45 | # return False 46 | 47 | # else: 48 | # stack.append(c) 49 | 50 | # if len(stack) == 0: 51 | # return True 52 | # else: 53 | # False -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 207 - course schedule.py: -------------------------------------------------------------------------------- 1 | # course schedule | leetcode 207 | https://leetcode.com/problems/course-schedule/ 2 | # method: depth first search 3 | 4 | class Solution: 5 | def canFinish(self, numCourses: int, prerequisites) -> bool: 6 | 7 | # init prequisite map 8 | preqMap = {} 9 | for i in range(numCourses): 10 | preqMap[i] = [] 11 | 12 | # add mentioned prerequisites 13 | for crs, pre in prerequisites: 14 | preqMap[crs].append(pre) 15 | 16 | # init visit set 17 | visitSet = set() 18 | 19 | # dfs 20 | def checkPreq(crs): 21 | 22 | # if course is already visited 23 | if crs in visitSet: 24 | return False 25 | 26 | # if no prequisites left 27 | if preqMap[crs] == []: 28 | return True 29 | 30 | # visiting this course 31 | visitSet.add(crs) 32 | 33 | # checking each prerequisite 34 | for pre in preqMap[crs]: 35 | if not checkPreq(pre): return False 36 | 37 | # all prerequisites are doable 38 | visitSet.remove(crs) 39 | preqMap[crs] = [] 40 | return True 41 | 42 | # check prerequisites for each course 43 | for crs in range(numCourses): 44 | if not checkPreq(crs): return False 45 | 46 | return True 47 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 21 - merge two sorted lists.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given the heads of two sorted linked lists list1 and list2. 3 | 4 | Merge the two lists in a one sorted list. The list should be made by splicing together the nodes of the first two lists. 5 | 6 | Return the head of the merged linked list. 7 | 8 | Question: https://leetcode.com/problems/merge-two-sorted-lists/ 9 | 10 | """ 11 | 12 | 13 | class ListNode: 14 | def __init__(self, val=0, next=None): 15 | self.val = val 16 | self.next = next 17 | class Solution: 18 | def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: 19 | answer = ListNode() 20 | tail = answer 21 | while list1 and list2: 22 | if list1.val < list2.val: 23 | tail.next = list1 24 | list1 = list1.next 25 | else: 26 | tail.next = list2 27 | list2=list2.next 28 | tail = tail.next 29 | 30 | if list1: 31 | tail.next = list1 32 | elif list2: 33 | tail.next = list2 34 | 35 | return answer.next -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 217 - contains duplicates.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct. 3 | 4 | Question: https://leetcode.com/problems/contains-duplicate/ 5 | 6 | """ 7 | class Solution: 8 | def containsDuplicate(self, nums: List[int]) -> bool: 9 | duplicates = {} 10 | for i in nums: 11 | if i in duplicates: 12 | return True 13 | else: 14 | duplicates[i] = 1 15 | return False 16 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 226 - invert binary tree.py: -------------------------------------------------------------------------------- 1 | # invert a binary tree | leetcode 226 | https://leetcode.com/problems/invert-binary-tree/ 2 | # method: (dfs) keep recursively swapping left and right subtrees 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def invertTree(self, root): 13 | 14 | def dfs(root): 15 | if root is None: 16 | return 17 | 18 | if root.left is None and root.right is None: 19 | return 20 | 21 | root.left, root.right = root.right, root.left 22 | dfs(root.left) 23 | dfs(root.right) 24 | 25 | dfs(root) 26 | return root -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 2265 - count nodes equal to average of subtree.py: -------------------------------------------------------------------------------- 1 | # count nodes equal to average of subtree | leetcode 2265 | https://leetcode.com/problems/count-nodes-equal-to-average-of-subtree/ 2 | # method: dfs, update size and sum of subtree at each node and check for average 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def averageOfSubtree(self, root: list[TreeNode]) -> int: 13 | self.counter = 0 14 | def dfs(node): 15 | if node is None: 16 | return 0, 0 17 | 18 | lSize, lSum = dfs(node.left) 19 | rSize, rSum = dfs(node.right) 20 | 21 | nSize, nSum = lSize + rSize + 1, lSum + rSum + node.val 22 | if (nSum // nSize) == node.val: 23 | self.counter += 1 24 | 25 | return nSize, nSum 26 | 27 | dfs(root) 28 | return self.counter 29 | 30 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 2306 - naming a company.py: -------------------------------------------------------------------------------- 1 | # naming a company | leetcode 2306 | https://leetcode.com/problems/naming-a-company 2 | # bucket by starting character to make it n(26^2.n) and compare each set with each other 3 | 4 | class Solution: 5 | def distinctNames(self, ideas: list[str]) -> int: 6 | buckets = dict() 7 | num_distinct = 0 8 | 9 | for idea in ideas: 10 | if buckets.get(idea[0]) is None: 11 | buckets[idea[0]] = {idea[1:]} 12 | else: 13 | buckets[idea[0]].add(idea[1:]) 14 | 15 | for prefix_i, suffix_i in buckets.items(): 16 | for prefix_j, suffix_j in buckets.items(): 17 | if prefix_i == prefix_j: 18 | continue 19 | common = len(suffix_i & suffix_j) 20 | common_i = len(suffix_i) - common 21 | common_j = len(suffix_j) - common 22 | num_distinct += common_i * common_j 23 | 24 | return num_distinct -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 2331 - evaluate boolean binary tree.py: -------------------------------------------------------------------------------- 1 | # evaluate boolean binary tree | leetcode 2331 | https://leetcode.com/problems/evaluate-boolean-binary-tree/ 2 | # method: dfs, evaluate left and/or right, return node's value 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def evaluateTree(self, node): 13 | if node.left is None and node.right is None: 14 | return node.val 15 | 16 | if node.val == 2: 17 | node.val = bool(self.evaluateTree(node.left)) or bool(self.evaluateTree(node.right)) 18 | 19 | if node.val == 3: 20 | node.val = bool(self.evaluateTree(node.left)) and bool(self.evaluateTree(node.right)) 21 | 22 | return node.val 23 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 234 - palindrome linked list.py: -------------------------------------------------------------------------------- 1 | # palindrome linked list | leetcode 234 | https://leetcode.com/problems/palindrome-linked-list/ 2 | 3 | # Definition for singly-linked list. 4 | # class ListNode: 5 | # def __init__(self, val=0, next=None): 6 | # self.val = val 7 | # self.next = next 8 | class Solution: 9 | 10 | # to check if its palindrome 11 | def isPalindrome(self, head) -> bool: 12 | 13 | # if underflow, is palindrome 14 | if not head or not head.next: return True 15 | 16 | # get one before mid element 17 | # and check if number of elements are even 18 | mid, even = self.get_mid(head) 19 | second = mid.next 20 | if not even: second = second.next 21 | 22 | # reverse the first half of the linked list 23 | first = self.rev_ll(head, mid) 24 | 25 | # match the reversed 1st and normal 2nd halves 26 | while first and second: 27 | if first.val != second.val: return False 28 | first = first.next 29 | second = second.next 30 | return True 31 | 32 | 33 | # to reverse the linked list half 34 | def rev_ll(self, head, upto): 35 | prev, curr = None, head 36 | 37 | while curr and prev != upto: 38 | temp = curr.next 39 | curr.next = prev 40 | prev = curr 41 | curr = temp 42 | 43 | return prev 44 | 45 | # to get the mid element 46 | # and check for even 47 | def get_mid(self, head): 48 | prev = head 49 | slow = head 50 | fast = head.next 51 | 52 | while fast and fast.next: 53 | prev = slow 54 | slow = slow.next 55 | fast = fast.next.next 56 | 57 | if not fast: return prev, False 58 | return slow, True 59 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 235 - lowest common ancestor in bst.py: -------------------------------------------------------------------------------- 1 | # lowest common ancestor in binary search tree | leetcode 235 | https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ 2 | # method: iteration through each node, when p and q are in different subtrees, current node is LCA 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, x): 7 | self.val = x 8 | self.left = None 9 | self.right = None 10 | 11 | class Solution: 12 | def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': 13 | cur = root 14 | 15 | while cur: 16 | if p.val > cur.val and q.val > cur.val: 17 | cur = cur.right 18 | elif p.val < cur.val and q.val < cur.val: 19 | cur = cur.left 20 | else: 21 | return cur 22 | 23 | return root 24 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 238 - product of array except self.py: -------------------------------------------------------------------------------- 1 | # product of array except self | leetcode 238 | https://leetcode.com/problems/product-of-array-except-self/ 2 | # save prefixes to result array and apply postfix in reverse 3 | # (since output array doesnt increase space complexity) 4 | 5 | class Solution: 6 | def productExceptSelf(self, nums: list[int]) -> list[int]: 7 | result = [] 8 | N = len(nums) 9 | 10 | # save prefix to result array 11 | product = 1 12 | for i in range(N): 13 | product = nums[i] * product 14 | result.append(product) 15 | 16 | # update result array as per postfix 17 | postfix = 1 18 | for i in range(N - 1, 0, -1): 19 | result[i] = result[i - 1] * postfix 20 | postfix = postfix * nums[i] 21 | result[0] = postfix 22 | 23 | return result 24 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 257 - binary tree paths.py: -------------------------------------------------------------------------------- 1 | # binary tree paths | leetcode 257 | https://leetcode.com/problems/binary-tree-paths/ 2 | # method: (dfs) in-order traversal and at each node, update path. if leaf, append to list of paths. 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]: 13 | def dfs(root, path): 14 | if root is None: 15 | return 16 | 17 | if root.left is None and root.right is None: 18 | path += str(root.val) 19 | self.paths.append(path) 20 | return 21 | 22 | path += str(root.val) + '->' 23 | dfs(root.left, path) 24 | dfs(root.right, path) 25 | 26 | self.paths = [] 27 | dfs(root, "") 28 | 29 | return self.paths 30 | 31 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 26 - remove duplicates from sorted array.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. 3 | 4 | Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements. 5 | 6 | Return k after placing the final result in the first k slots of nums. 7 | 8 | Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory. 9 | 10 | Question: https://leetcode.com/problems/remove-duplicates-from-sorted-array/ 11 | 12 | """ 13 | 14 | class Solution: 15 | def removeDuplicates(self, nums: List[int]) -> int: 16 | list = 1 17 | 18 | for r in range(1, len(nums)): 19 | if nums[r] != nums[r-1]: 20 | nums[list] = nums[r] 21 | list += 1 22 | 23 | return list -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 27 - remove element.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The relative order of the elements may be changed. 3 | 4 | Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements. 5 | 6 | Return k after placing the final result in the first k slots of nums. 7 | 8 | Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory. 9 | 10 | Question: https://leetcode.com/problems/remove-element/ 11 | 12 | """ 13 | 14 | 15 | class Solution: 16 | def removeDuplicates(self, nums: List[int]) -> int: 17 | list = 1 18 | 19 | for r in range(1, len(nums)): 20 | if nums[r] != nums[r-1]: 21 | nums[list] = nums[r] 22 | list += 1 23 | 24 | return list -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 28 - implement strStr().py: -------------------------------------------------------------------------------- 1 | """ 2 | Implement strStr(). 3 | 4 | Given two strings needle and haystack, return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. 5 | 6 | Clarification: 7 | 8 | What should we return when needle is an empty string? This is a great question to ask during an interview. 9 | 10 | For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf(). 11 | 12 | Question: https://leetcode.com/problems/implement-strstr/ 13 | 14 | """ 15 | 16 | class Solution: 17 | def strStr(self, haystack: str, needle: str) -> int: 18 | if not needle: 19 | return 0 20 | 21 | for i in range(len(haystack)): 22 | if haystack[i:i+len(needle)] == needle: 23 | return i 24 | return -1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 28 - index of first occurrence.py: -------------------------------------------------------------------------------- 1 | # find the index of the first occurrence of a string | leetcode 28 | https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/ 2 | # sliding window to match each character of the haystack with the needle; no slices. 3 | 4 | class Solution: 5 | def strStr(self, haystack: str, needle: str) -> int: 6 | # ----- using regex ----- 7 | # if needle == '': 8 | # return 0 9 | 10 | # import re 11 | # match = re.search(needle, haystack) 12 | # return match.start() if match else -1 13 | 14 | # ----- using sliding windows ----- 15 | ptrL, ptrR = 0, 0 16 | N_needle, N_haystack = len(needle), len(haystack) 17 | while ptrR < N_haystack: 18 | if haystack[ptrR] == needle[ptrR - ptrL]: 19 | ptrR += 1 20 | if ptrR - ptrL > N_needle - 1: 21 | return ptrL 22 | else: 23 | ptrR = ptrL + 1 24 | ptrL += 1 25 | 26 | return -1 27 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 290 - word pattern.py: -------------------------------------------------------------------------------- 1 | # word pattern | leetcode 290 | https://leetcode.com/problems/word-pattern/ 2 | # create a vocabulary to match pattern and a seen hashset to record seen words 3 | 4 | class Solution: 5 | def wordPattern(self, pattern: str, s: str) -> bool: 6 | vocab = dict() 7 | seens = dict() 8 | sent = s.split(" ") 9 | 10 | if len(sent) != len(pattern): 11 | return False 12 | 13 | for i in range(len(pattern)): 14 | i_patt = pattern[i] 15 | i_sent = sent[i] 16 | 17 | if vocab.get(i_patt): 18 | if vocab[i_patt] != i_sent: 19 | return False 20 | else: 21 | if seens.get(i_sent): 22 | return False 23 | vocab[i_patt] = i_sent 24 | seens[i_sent] = True 25 | 26 | return True -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 347 - top k frequent elements.py: -------------------------------------------------------------------------------- 1 | # top k frequency elements | leetcode 347 | https://leetcode.com/problems/top-k-frequent-elements/ 2 | # use buckets with each bucket being the frequency of an element 3 | 4 | from collections import Counter 5 | 6 | class Solution: 7 | def topKFrequent(self, nums: list[int], k: int) -> list[int]: 8 | freq = Counter(nums) 9 | N = len(nums) 10 | 11 | # create buckets where index = frequency of element 12 | buckets = [[] for x in range(N + 1)] 13 | for f in freq: 14 | buckets[freq[f]].append(f) 15 | 16 | # get k elements starting from the end of the bucket 17 | k_mf = [] 18 | for x in buckets[::-1]: 19 | if k > 0: 20 | if x != []: 21 | k_mf += x 22 | k -= len(x) 23 | else: 24 | return k_mf 25 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 35 - search insert position.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 4 | 5 | You must write an algorithm with O(log n) runtime complexity. 6 | 7 | Question: https://leetcode.com/problems/search-insert-position/ 8 | 9 | """ 10 | 11 | class Solution: 12 | def searchInsert(self, nums: List[int], target: int) -> int: 13 | l = 0 14 | r = len(nums)-1 15 | 16 | while l <= r: 17 | mid = (l+r)//2 18 | 19 | if target == nums[mid]: 20 | return mid 21 | 22 | if target > nums[mid]: 23 | l = mid +1 24 | 25 | else: 26 | r = mid - 1 27 | 28 | return l -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 350 - intersection of two arrays II.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two integer arrays nums1 and nums2, return an array of their intersection. Each element in the result must appear as many times as it shows in both arrays and you may return the result in any order. 3 | 4 | 5 | Question: https://leetcode.com/problems/intersection-of-two-arrays-ii/ 6 | 7 | 8 | """ 9 | 10 | #solution 1 11 | class Solution: 12 | def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: 13 | c = Counter(nums1) 14 | output=[] 15 | for n in (nums2): 16 | if c[n] > 0: 17 | output.append(n) 18 | c[n]-=1 19 | 20 | return (output) 21 | 22 | #solution 2 23 | 24 | class Solution: 25 | def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]: 26 | i=0 27 | j=0 28 | output = [] 29 | nums1.sort() 30 | nums2.sort() 31 | 32 | while i nums2[j]: 36 | j = j+1 37 | else: 38 | output.append(nums1[i]) 39 | i=i+1 40 | j=j+1 41 | 42 | return output 43 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 36 - valid sudoku.py: -------------------------------------------------------------------------------- 1 | # valid sudoku | leetcode 36 | https://leetcode.com/problems/valid-sudoku/ 2 | # Determine if a n^2 x n^2 Psuedo-Sudoku board is valid. 3 | # Only the filled cells need to be validated. 4 | 5 | import collections 6 | 7 | class Solution: 8 | def isValidSudoku(self, board: list[list[str]]) -> bool: 9 | rows = collections.defaultdict(set) 10 | columns = collections.defaultdict(set) 11 | squares = collections.defaultdict(set) 12 | 13 | for i in range(len(board)): 14 | for j in range(len(board[i])): 15 | 16 | if board[i][j] == '.': 17 | continue 18 | 19 | isInRow = board[i][j] in rows[i] 20 | isInColumn = board[i][j] in columns[j] 21 | isInSquare = board[i][j] in squares[(i//3, j//3)] 22 | if (isInRow or isInColumn or isInSquare): 23 | return False 24 | 25 | rows[i].add(board[i][j]) 26 | columns[j].add(board[i][j]) 27 | squares[(i//3, j//3)].add(board[i][j]) 28 | 29 | return True 30 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 424 - longest repeating character replacement.py: -------------------------------------------------------------------------------- 1 | # longest repeating character replacement | leetcode 424 | https://leetcode.com/problems/longest-repeating-character-replacement/ 2 | # keep track of max freq in sliding window and check if size of window - max freq > k 3 | 4 | class Solution: 5 | def characterReplacement(self, s: str, k: int) -> int: 6 | ptrL = 0 7 | ptrR = 0 8 | longest = 0 9 | freq = dict() 10 | max_freq = 0 11 | w_size = 0 12 | 13 | for ptrR in range(len(s)): 14 | freq[s[ptrR]] = 1 + freq.get(s[ptrR], 0) 15 | max_freq = max(max_freq, freq[s[ptrR]]) 16 | 17 | if (ptrR - ptrL + 1) - max_freq > k: 18 | freq[s[ptrL]] -= 1 19 | ptrL += 1 20 | 21 | longest = max(longest, (ptrR - ptrL + 1)) 22 | 23 | return longest -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 427 - construct quad tree.py: -------------------------------------------------------------------------------- 1 | # construct quad tree | leetcode 427 | https://leetcode.com/problems/construct-quad-tree/ 2 | # recursively call each quad of the grid and check if each quad is uniform or not 3 | 4 | # Definition for a QuadTree node. 5 | class Node: 6 | def __init__(self, val, isLeaf, topLeft, topRight, bottomLeft, bottomRight): 7 | self.val = val 8 | self.isLeaf = isLeaf 9 | self.topLeft = topLeft 10 | self.topRight = topRight 11 | self.bottomLeft = bottomLeft 12 | self.bottomRight = bottomRight 13 | 14 | 15 | class Solution: 16 | def construct(self, grid: list[list[int]]) -> Node: 17 | def checkThisQuad(row, col, n) -> bool: 18 | for i in range(row, row + n): 19 | for j in range(col, col + n): 20 | if grid[i][j] != grid[row][col]: 21 | return False 22 | return True 23 | 24 | def quadTree(row, col, n): 25 | if checkThisQuad(row, col, n): 26 | return Node(grid[row][col], 1, None, None, None, None) 27 | 28 | 29 | return Node(grid[row][col], 0, 30 | quadTree(row, col, n//2), 31 | quadTree(row, col + n//2, n//2), 32 | quadTree(row + n//2, col, n//2), 33 | quadTree(row + n//2, col + n//2, n//2) 34 | ) 35 | 36 | return quadTree(0, 0, len(grid)) 37 | 38 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 435 - non-overlapping intervals.py: -------------------------------------------------------------------------------- 1 | # non-overlapping intervals | leetcode 435 | https://leetcode.com/problems/non-overlapping-intervals 2 | # sort by starting times; keep track of latest ending time; always keep interval with min end time 3 | 4 | class Solution: 5 | def eraseOverlapIntervals(self, intervals: list[list[int]]) -> int: 6 | min_intervals_to_remove = 0 7 | intervals.sort(key = lambda x: x[0]) 8 | latest_end = intervals[0][1] 9 | 10 | for i in range(1, len(intervals)): 11 | if intervals[i][0] < latest_end: 12 | min_intervals_to_remove += 1 13 | latest_end = min(intervals[i][1], latest_end) 14 | else: 15 | latest_end = intervals[i][1] 16 | 17 | return min_intervals_to_remove 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 438 - find all anagrams in string.py: -------------------------------------------------------------------------------- 1 | # find all anagrams in string | leetcode 438 | https://leetcode.com/problems/find-all-anagrams-in-a-string/ 2 | # sliding window to track "which" substring; add ptr2 to counter, remove ptr1 from counter 3 | 4 | 5 | from collections import Counter 6 | 7 | class Solution: 8 | def findAnagrams(self, s: str, p: str) -> list[int]: 9 | Ns, Np = len(s), len(p) 10 | ptr1 = 0 11 | ptr2 = Np - 1 12 | anagrams = [] 13 | freq_s, freq_p = Counter(s[ptr1:(ptr2 + 1)]), Counter(p) 14 | 15 | while ptr2 < Ns: 16 | if freq_s == freq_p: 17 | anagrams.append(ptr1) 18 | freq_s[s[ptr1]] -= 1 19 | ptr1 += 1 20 | ptr2 += 1 21 | if ptr2 != Ns: 22 | freq_s[s[ptr2]] = 1 + freq_s.get(s[ptr2], 0) 23 | 24 | return anagrams -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 443 - string compression.py: -------------------------------------------------------------------------------- 1 | # string compression | leetcode 443 | https://leetcode.com/problems/string-compression/ 2 | # sliding window to keep track of a char's occurence 3 | 4 | class Solution: 5 | def compress(self, chars: list[str]) -> int: 6 | ptrL, ptrR = 0, 0 7 | total = 0 8 | chars += " " 9 | 10 | while ptrR < len(chars): 11 | if chars[ptrL] != chars[ptrR]: 12 | chars[total] = chars[ptrL] 13 | total += 1 14 | group = ptrR - ptrL 15 | if group > 1: 16 | for x in str(group): 17 | chars[total] = x 18 | total += 1 19 | ptrL = ptrR 20 | ptrR += 1 21 | 22 | return total 23 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 48 - rotate image (by rotation).py: -------------------------------------------------------------------------------- 1 | # rotate image | leetcode 48 | https://leetcode.com/problems/rotate-image/ 2 | # You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise). 3 | # method: actual rotation 4 | 5 | # testcase 1 6 | # matrix: list[list[int]] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 7 | 8 | # testcase 2 9 | matrix: list[list[int]] = [[5, 1, 9, 11], [2, 4, 8, 10],[13, 3, 6, 7],[15, 14, 12, 16]] 10 | 11 | def rotate(matrix: list[list[int]]) -> None: 12 | n: int = len(matrix) # size (n x n) 13 | left: int = 0 # left pointer 14 | right: int = n - 1 # right pointer 15 | top: int = 0 # top pointer 16 | bottom: int = 0 # bottom pointer 17 | temp: int = 0 # temp variable 18 | 19 | # if left pointer is on 20 | # the right of the right pointer 21 | # stop iterating 22 | while left < right: 23 | 24 | # for each square in layer 25 | for i in range(right - left): 26 | top: int = left 27 | bottom: int = right 28 | 29 | temp = matrix[top][left + i] # save top-left 30 | matrix[top][left + i] = matrix[bottom - i][left] # bottom-left to top-left 31 | matrix[bottom - i][left] = matrix[bottom][right - i] # bottom-right to bottom-left 32 | matrix[bottom][right - i] = matrix[top + i][right] # top-right to bottom-right 33 | matrix[top + i][right] = temp # (saved) top-left to top-right 34 | 35 | # next layer 36 | left = left + 1 37 | right = right - 1 38 | 39 | # output 40 | rotate(matrix) 41 | print(matrix) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 48 - rotate image (by transpose).py: -------------------------------------------------------------------------------- 1 | # rotate image | leetcode 48 | https://leetcode.com/problems/rotate-image/ 2 | # You are given an n x n 2D matrix representing an image, rotate the image by 90 degrees (clockwise). 3 | # method: transpose + reflection 4 | 5 | # testcase 1 6 | # matrix: list[list[int]] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 7 | 8 | # testcase 2 9 | matrix: list[list[int]] = [[5, 1, 9, 11], [2, 4, 8, 10],[13, 3, 6, 7],[15, 14, 12, 16]] 10 | 11 | def rotate(matrix: list[list[int]]) -> None: 12 | n: int = len(matrix) 13 | 14 | # transpose of the matrix 15 | def transpose(matrix: list[list[int]]) -> None: 16 | for i in range(n): 17 | for j in range(i + 1, n): 18 | matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j] 19 | 20 | # reflection of the matrix 21 | def reflect(matrix: list[list[int]]) -> None: 22 | for i in range(n): 23 | for j in range(n // 2): 24 | matrix[i][j], matrix[i][n - j - 1] = matrix[i][n - j - 1], matrix[i][j] 25 | 26 | transpose(matrix) 27 | reflect(matrix) 28 | 29 | # output 30 | rotate(matrix) 31 | print(matrix) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 49 - group anagrams.py: -------------------------------------------------------------------------------- 1 | # group anagrams | leetcode 49 | https://leetcode.com/problems/group-anagrams/ 2 | # method: dictionary with char counter as key 3 | 4 | from collections import defaultdict 5 | 6 | class Solution: 7 | def groupAnagrams(self, strs): 8 | grouped = defaultdict(list) 9 | 10 | for each_word in strs: 11 | count_of_ch = [0] * 26 12 | for each_ch in each_word: 13 | count_of_ch[ord(each_ch) - ord("a")] += 1 14 | grouped[tuple(count_of_ch)].append(each_word) 15 | 16 | return grouped.values() 17 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 494 - target sum.py: -------------------------------------------------------------------------------- 1 | # target sum | leetcode 494 | https://leetcode.com/problems/target-sum/ 2 | # 0/1 knapsack to decide +/- and cache (index, total) 3 | 4 | class Solution: 5 | def findTargetSumWays(self, nums: list[int], target: int) -> int: 6 | N = len(nums) 7 | mem = dict() 8 | 9 | if N == 0: 10 | return 0 11 | 12 | def knapsack(n, s): 13 | if n == N: 14 | return 1 if s == target else 0 15 | 16 | if (n, s) in mem: 17 | return mem[(n, s)] 18 | 19 | mem[(n, s)] = knapsack(n+1, s + nums[n]) + knapsack(n+1, s - nums[n]) 20 | return mem[(n, s)] 21 | 22 | return knapsack(0, 0) 23 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 502 - ipo.py: -------------------------------------------------------------------------------- 1 | # IPO | leetcode 502 | https://leetcode.com/problems/ipo/ 2 | # min-heap to track capital and max-heap to track profits 3 | 4 | import heapq 5 | 6 | class Solution: 7 | def findMaximizedCapital(self, k: int, w: int, profits: list[int], capital: list[int]) -> int: 8 | maxHeap = [] 9 | minHeap = [(c, p) for c, p in zip(capital, profits)] 10 | heapq.heapify(minHeap) 11 | 12 | for _ in range(k): 13 | while minHeap and minHeap[0][0] <= w: 14 | _, p = heapq.heappop(minHeap) 15 | heapq.heappush(maxHeap, -1 * p) 16 | if not maxHeap: 17 | break 18 | w += -1 * heapq.heappop(maxHeap) 19 | 20 | return w 21 | 22 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 53 - maximum subarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum. 3 | 4 | A subarray is a contiguous part of an array. 5 | 6 | Question: https://leetcode.com/problems/maximum-subarray/ 7 | 8 | 9 | """ 10 | 11 | class Solution: 12 | def maxSubArray(self, nums: List[int]) -> int: 13 | maxSub = nums[0] 14 | curSum = 0 15 | 16 | for n in nums: 17 | if curSum <0: 18 | curSum = 0 19 | curSum += n 20 | maxSub = max(maxSub, curSum) 21 | return maxSub -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 530 - minimum absolute difference in BST.py: -------------------------------------------------------------------------------- 1 | # minimum absolute difference in BST | leetcode 530 | https://leetcode.com/problems/minimum-absolute-difference-in-bst/ 2 | # method: dfs, inorder traversal 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def getMinimumDifference(self, root: TreeNode): 13 | minDiff = float('inf') 14 | prevNod = None 15 | 16 | def dfs(node): 17 | nonlocal minDiff, prevNod 18 | if node is None: 19 | return 20 | 21 | dfs(node.left) 22 | 23 | if prevNod != None: 24 | minDiff = min(minDiff, abs(node.val - prevNod)) 25 | prevNod = node.val 26 | 27 | dfs(node.right) 28 | 29 | dfs(root) 30 | return minDiff 31 | 32 | 33 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 540 - single element in a sorted array.py: -------------------------------------------------------------------------------- 1 | # single element in a sorted array | leetcode 540 | https://leetcode.com/problems/single-element-in-a-sorted-array/ 2 | # binary search over sorted array; check if mid is even and mid is the first of the duplicates 3 | 4 | class Solution: 5 | def singleNonDuplicate(self, nums: list[int]) -> int: 6 | N = len(nums) 7 | if N < 2: 8 | return nums[0] 9 | low, high, mid = 0, N, 0 10 | while low <= high: 11 | mid = low + ((high - low) // 2) 12 | 13 | if mid == N - 1: 14 | return nums[mid] 15 | 16 | if nums[mid] == nums[mid - 1] or nums[mid] == nums[mid + 1]: 17 | if (mid % 2 == 0) == (nums[mid] == nums[mid + 1]): 18 | low = mid 19 | else: 20 | high = mid 21 | else: 22 | return nums[mid] 23 | 24 | return nums[mid] -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 559 - max depth of n-ary tree.py: -------------------------------------------------------------------------------- 1 | # max depth of n-ary tree | leetcode 559 | https://leetcode.com/problems/maximum-depth-of-n-ary-tree/ 2 | # method: (dfs) return 1 + max(depths) at each node, return 1 if leaf 3 | 4 | # Definition for a Node. 5 | class Node: 6 | def __init__(self, val=None, children=None): 7 | self.val = val 8 | self.children = children 9 | 10 | class Solution: 11 | def maxDepth(self, root): 12 | if root is None: 13 | return 0 14 | 15 | depths = [self.maxDepth(child) for child in root.children] 16 | 17 | if depths: 18 | return 1 + max(depths) 19 | 20 | return 1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 58 - length of last word.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a string s consisting of some words separated by some number of spaces, return the length of the last word in the string. 3 | 4 | A word is a maximal substring consisting of non-space characters only. 5 | 6 | Question: https://leetcode.com/problems/length-of-last-word/ 7 | 8 | """ 9 | 10 | #Solution usinf inbuilt fuctions : 11 | class Solution: 12 | def lengthOfLastWord(self, s: str) -> int: 13 | s = s.strip() 14 | s = s.split(" ") 15 | last = s[len(s)-1] 16 | return (len(last)) 17 | 18 | 19 | #Solution without inbuilt fuctions : 20 | class Solution: 21 | def lengthOfLastWord(self, s: str) -> int: 22 | i, length = len(s)-1, 0 23 | while s[i] == " ": 24 | i -= 1 25 | while i >= 0 and s[i] != " ": 26 | length += 1 27 | i -= 1 28 | return length 29 | 30 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 590 - n-ary tree postorder.py: -------------------------------------------------------------------------------- 1 | # n-ary tree postorder traversal | leetcode 590 | https://leetcode.com/problems/n-ary-tree-postorder-traversal/submissions/ 2 | # method: (dfs) postorder traversal is L R N, so iterate through all children and then save node 3 | 4 | # Definition for a Node. 5 | class Node: 6 | def __init__(self, val=None, children=None): 7 | self.val = val 8 | self.children = children 9 | 10 | class Solution: 11 | def postorder(self, root: Node): 12 | self.postTrv = [] 13 | def dfs(root): 14 | if root is None: 15 | return None 16 | 17 | [dfs(child) for child in root.children] 18 | self.postTrv.append(root.val) 19 | 20 | dfs(root) 21 | return self.postTrv 22 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 598 - n-ary tree preorder.py: -------------------------------------------------------------------------------- 1 | # n-ary tree postorder traversal | leetcode 590 | https://leetcode.com/problems/n-ary-tree-postorder-traversal/submissions/ 2 | # method: (dfs) postorder traversal is L R N, so iterate through all children and then save node 3 | 4 | 5 | # Definition for a Node. 6 | class Node: 7 | def __init__(self, val=None, children=None): 8 | self.val = val 9 | self.children = children 10 | 11 | class Solution: 12 | def preorder(self, root): 13 | def dfs(root): 14 | if root is None: 15 | return None 16 | 17 | self.postTrv.append(root.val) 18 | [dfs(child) for child in root.children] 19 | 20 | self.postTrv = [] 21 | dfs(root) 22 | return self.postTrv -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 617 - merge binary trees.py: -------------------------------------------------------------------------------- 1 | # merge two binary trees | leetcode 617 | https://leetcode.com/problems/merge-two-binary-trees/ 2 | # method: merge current, then merge left and right 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def mergeTrees(self, root1, root2): 13 | if root1 is None and root2 is None: 14 | return None 15 | 16 | curr = TreeNode((root1.val if root1 else 0) + (root2.val if root2 else 0)) 17 | curr.left = self.mergeTrees(root1.left if root1 else None, root2.left if root2 else None) 18 | curr.right = self.mergeTrees(root1.right if root1 else None, root2.right if root2 else None) 19 | 20 | return curr -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 637 - avg of levels in binary tree.py: -------------------------------------------------------------------------------- 1 | # average of levels in binary tree | leetcode 637 | https://leetcode.com/problems/average-of-levels-in-binary-tree/ 2 | # method: (bfs) level order traversal, but instead of appending level to a list, append its average 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def averageOfLevels(self, root): 13 | res = [] 14 | Q = [] 15 | 16 | Q.append(root) 17 | lQ = len(Q) 18 | 19 | while lQ is not 0: 20 | level = [] 21 | lQ = len(Q) 22 | for i in range(lQ): 23 | node = Q.pop(0) 24 | if node is not None: 25 | level.append(node.val) 26 | Q.append(node.left) 27 | Q.append(node.right) 28 | if level: 29 | res.append(sum(level) / len(level)) 30 | 31 | return res -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 653 - two sum with binary tree.py: -------------------------------------------------------------------------------- 1 | # two sum iv - input is a bst | leetcode 653 | https://leetcode.com/problems/two-sum-iv-input-is-a-bst/submissions/ 2 | # method: (dfs) bst inorder traversal gives a sorted array, run array two-sum. 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def twoSum(self, nums, target): 13 | prev = {} 14 | 15 | for i, num in enumerate(nums): 16 | diff = target - num 17 | if diff in prev: 18 | return [prev[diff], i] 19 | prev[num] = i 20 | 21 | def dfs(self, root): 22 | if root is None: 23 | return 24 | 25 | self.dfs(root.left) 26 | self.trv.append(root.val) 27 | self.dfs(root.right) 28 | 29 | def findTarget(self, root, k): 30 | self.trv = [] 31 | self.dfs(root) 32 | return self.twoSum(self.trv, k) 33 | 34 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 66 - plus one.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given a large integer represented as an integer array digits, where each digits[i] is the ith digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading 0's. 3 | 4 | Increment the large integer by one and return the resulting array of digits. 5 | 6 | Question: https://leetcode.com/problems/plus-one/ 7 | 8 | """ 9 | 10 | class Solution: 11 | def plusOne(self, digits: List[int]) -> List[int]: 12 | n = 0 13 | for i in range(len(digits)): 14 | n = (n*10)+digits[i] 15 | n = n+1 16 | m = map(int, str(n)) 17 | return(m) 18 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 67 - add binary.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given two binary strings a and b, return their sum as a binary string. 3 | 4 | Question: https://leetcode.com/problems/add-binary/ 5 | 6 | """ 7 | 8 | class Solution: 9 | def addBinary(self, a: str, b: str) -> str: 10 | result = "" 11 | aCount = len(a) - 1 12 | bCount = len(b) - 1 13 | 14 | carry = 0 15 | 16 | while aCount >= 0 or bCount >= 0: 17 | totalSum = carry 18 | if aCount >= 0: 19 | totalSum += int(a[aCount]) 20 | aCount -= 1 21 | if bCount >= 0: 22 | totalSum += int(b[bCount]) 23 | bCount -= 1 24 | result = str(totalSum % 2) + result 25 | carry = totalSum // 2 26 | if carry > 0: 27 | result = str(1) + result 28 | return result -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 69 - sqrt(x).py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Given a non-negative integer x, compute and return the square root of x. 4 | 5 | Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned. 6 | 7 | Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5) or x ** 0.5. 8 | 9 | Question : https://leetcode.com/problems/sqrtx/ 10 | 11 | """ 12 | 13 | # import numpy as np 14 | # class Solution: 15 | # def mySqrt(self, x: int) -> int: 16 | # return int(np.sqrt(x)) 17 | 18 | class Solution: 19 | def mySqrt(self, x: int) -> int: 20 | 21 | start = 0 22 | end = x 23 | 24 | while start + 1 < end: 25 | mid = start + (end - start) // 2 26 | 27 | if mid * mid == x: 28 | return mid 29 | elif mid * mid < x: 30 | start = mid 31 | else: 32 | end = mid 33 | 34 | if end * end == x: 35 | return end 36 | 37 | return start -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 70 - climbing stairs.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | You are climbing a staircase. It takes n steps to reach the top. 4 | 5 | Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 6 | 7 | Question: https://leetcode.com/problems/climbing-stairs/ 8 | 9 | """ 10 | 11 | class Solution: 12 | def climbStairs(self, n: int) -> int: 13 | one, two = 1,1 14 | 15 | for i in range (n-1): 16 | temp = one 17 | one = one +two 18 | two = temp 19 | 20 | return one -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 705 - hash set.py: -------------------------------------------------------------------------------- 1 | # hashset | leetcode 705 | https://leetcode.com/problems/design-hashset/ 2 | 3 | class HashSet: 4 | 5 | # constructor 6 | def __init__ (self, hash_set = None): 7 | '''initialize a hash set''' 8 | self.hash_set: dict = {} if hash_set == None else hash_set 9 | self.size: int = len(self.hash_set.keys()) 10 | 11 | # initialize iterator for __iter__ 12 | def __iter__ (self): 13 | self.n = 0 14 | return self 15 | 16 | # return next element for __next__ 17 | def __next__ (self): 18 | if self.n < self.size: 19 | result = list(self.hash_set.keys())[self.n] 20 | self.n = self.n + 1 21 | return result 22 | else: 23 | raise StopIteration 24 | 25 | def add (self, key) -> None: 26 | '''add element to hash set''' 27 | self.hash_set[key] = True 28 | self.size = self.size + 1 29 | 30 | def contains (self, key) -> bool: 31 | '''does hash set contain element''' 32 | return True if self.hash_set.get(key) else False 33 | 34 | def remove (self, key) -> None: 35 | '''remove element from hash set''' 36 | if self.contains(key): 37 | self.hash_set.pop(key) 38 | self.size = self.size - 1 39 | 40 | # initialize a new hashset 41 | hashSet = HashSet() 42 | 43 | # add values to a hash set 44 | hashSet.add('first') 45 | hashSet.add('second') 46 | hashSet.add('third') 47 | hashSet.add('fourth') 48 | 49 | # remove from a hash set 50 | hashSet.remove('fourth') 51 | 52 | # check if value exists in a hash set 53 | print(hashSet.contains('first')) 54 | print(hashSet.contains('fourth')) 55 | 56 | # iterate through a hash set 57 | for element in hashSet: 58 | print(element) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 724 - find pivot index.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given an array of integers nums, calculate the pivot index of this array. 3 | 4 | The pivot index is the index where the sum of all the numbers strictly to the left of the index is equal to the sum of all the numbers strictly to the index's right. 5 | 6 | If the index is on the left edge of the array, then the left sum is 0 because there are no elements to the left. This also applies to the right edge of the array. 7 | 8 | Return the leftmost pivot index. If no such index exists, return -1. 9 | 10 | Question : https://leetcode.com/problems/find-pivot-index/ 11 | 12 | 13 | """ 14 | 15 | class Solution: 16 | def pivotIndex(self, nums: List[int]) -> int: 17 | total = sum(nums) 18 | 19 | leftSum = 0 20 | for i in range(len(nums)): 21 | rightSum = total - nums[i] - leftSum 22 | if leftSum == rightSum: 23 | return i 24 | leftSum += nums[i] 25 | return -1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 783 - minimum distance between bst nodes.py: -------------------------------------------------------------------------------- 1 | # minimum distance between bst nodes | leetcode 783 | https://leetcode.com/problems/minimum-distance-between-bst-nodes 2 | # dfs; inorder; keep track of last traversed node and check against minimum difference 3 | 4 | 5 | # Definition for a binary tree node. 6 | class TreeNode: 7 | def __init__(self, val=0, left=None, right=None): 8 | self.val = val 9 | self.left = left 10 | self.right = right 11 | 12 | 13 | class Solution: 14 | def minDiffInBST(self, root: TreeNode) -> int: 15 | stack = [] 16 | curr = root 17 | last = None 18 | minDiff = float("inf") 19 | while True: 20 | if curr is not None: 21 | stack.append(curr) 22 | curr = curr.left 23 | elif stack: 24 | curr = stack.pop() 25 | if last is not None: 26 | minDiff = min(abs(last.val - curr.val), minDiff) 27 | last = curr 28 | curr = curr.right 29 | else: 30 | break 31 | 32 | return int(minDiff) 33 | 34 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 797 - all paths from source to target.py: -------------------------------------------------------------------------------- 1 | # all paths from source to target | leetcode 797 | https://leetcode.com/problems/all-paths-from-source-to-target/ 2 | # method: dfs 3 | 4 | class Solution: 5 | def allPathsSourceTarget(self, graph: list[list[int]]) -> list[list[int]]: 6 | possiblePaths = [] 7 | 8 | def dfs(node, visited): 9 | if node == len(graph) - 1: 10 | possiblePaths.append(visited) 11 | 12 | for neighbour in graph[node]: 13 | dfs(neighbour, [*visited, node]) 14 | 15 | dfs(0, [0]) 16 | return possiblePaths 17 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 83 - remove duplicates from sorted list.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given the head of a sorted linked list, delete all duplicates such that each element appears only once. Return the linked list sorted as well. 3 | 4 | Question: https://leetcode.com/problems/remove-duplicates-from-sorted-list/ 5 | 6 | """ 7 | 8 | # Definition for singly-linked list. 9 | # class ListNode: 10 | # def __init__(self, val=0, next=None): 11 | # self.val = val 12 | # self.next = next 13 | 14 | class Solution: 15 | def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: 16 | cur = head 17 | 18 | while cur: 19 | while cur.next and cur.next.val == cur .val: 20 | cur.next = cur.next.next 21 | cur = cur.next 22 | 23 | return head 24 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 872 - leaf-similar trees.py: -------------------------------------------------------------------------------- 1 | # leaf-similar trees | leetcode 872 | https://leetcode.com/problems/leaf-similar-trees/ 2 | # match the leaves of both trees 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def leafSimilar(self, root1, root2) -> bool: 13 | def getLeaves(root): 14 | if root is None: 15 | return 16 | 17 | getLeaves(root.left) 18 | if root.left is None and root.right is None: 19 | self.leaves.append(root.val) 20 | getLeaves(root.right) 21 | 22 | self.leaves = [] 23 | getLeaves(root1) 24 | leaves1 = self.leaves 25 | 26 | self.leaves = [] 27 | getLeaves(root2) 28 | leaves2 = self.leaves 29 | 30 | return leaves1 == leaves2 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 88 - merger sort array.py: -------------------------------------------------------------------------------- 1 | """ 2 | You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively. 3 | 4 | Merge nums1 and nums2 into a single array sorted in non-decreasing order. 5 | 6 | The final sorted array should not be returned by the function, but instead be stored inside the array nums1. To accommodate this, nums1 has a length of m + n, where the first m elements denote the elements that should be merged, and the last n elements are set to 0 and should be ignored. nums2 has a length of n. 7 | 8 | Question: https://leetcode.com/problems/merge-sorted-array/ 9 | 10 | """ 11 | 12 | class Solution: 13 | def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: 14 | """ 15 | Do not return anything, modify nums1 in-place instead. 16 | """ 17 | last = m + n - 1 18 | 19 | #merge in reverse order 20 | while m>0 and n>0: 21 | if nums1[m-1] > nums2[n-1]: 22 | nums1[last] = nums1[m-1] 23 | m = m-1 24 | else: 25 | nums1[last] = nums2[n-1] 26 | n = n-1 27 | last = last - 1 28 | 29 | #fill nums1 with leftover nums2 elements 30 | while n>0: 31 | nums1[last] = nums2[n-1] 32 | n, last = n-1, last -1 -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 897 - increasing order bst.py: -------------------------------------------------------------------------------- 1 | # increasing order search tree | leetcode 897 | https://leetcode.com/problems/increasing-order-search-tree/ 2 | # rearrange a bst with each node having only a right child, and the originally left-most leaf as the new root 3 | # method: inorder traversal to return sorted array, insert all elements as right child (since sorted array) 4 | 5 | 6 | # Definition for a binary tree node. 7 | class TreeNode: 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | class Solution: 14 | def increasingBST(self, root): 15 | self.inorderTrv = [] 16 | def inorder(root): 17 | if root is None: 18 | return None 19 | 20 | inorder(root.left) 21 | self.inorderTrv.append(root.val) 22 | inorder(root.right) 23 | 24 | inorder(root) 25 | newRoot = TreeNode(self.inorderTrv[0]) 26 | toReturn = newRoot 27 | for x in self.inorderTrv[1:]: 28 | newRoot.right = TreeNode(x) 29 | newRoot = newRoot.right 30 | 31 | return toReturn -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 94 - binary tree inorder traversal.py: -------------------------------------------------------------------------------- 1 | # binary tree inorder traversal | leetcode 94 | https://leetcode.com/problems/binary-tree-inorder-traversal/ 2 | # method: left subtree, node, right subtree recursively 3 | 4 | # Definition for a binary tree node. 5 | class TreeNode: 6 | def __init__(self, val=0, left=None, right=None): 7 | self.val = val 8 | self.left = left 9 | self.right = right 10 | 11 | class Solution: 12 | def inorderTraversal(self, root): 13 | travList = [] 14 | 15 | def traverse(root, travList): 16 | if root is None: 17 | return None 18 | 19 | traverse(root.left, travList) # traverse left subtree and add nodes 20 | travList.append(root.val) # add this node 21 | traverse(root.right, travList) # traverse right subtree and add nodes 22 | 23 | traverse(root, travList) 24 | return travList 25 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 944 - delete columns to make sorted.py: -------------------------------------------------------------------------------- 1 | # delete columns to make sorted | leetcode 944 | https://leetcode.com/problems/delete-columns-to-make-sorted/ 2 | 3 | class Solution: 4 | def minDeletionSize(self, strs: list[str]) -> int: 5 | n_cols = len(strs[0]) 6 | n_rows = len(strs) 7 | cols_d = 0 8 | 9 | for col in range(n_cols): 10 | for row in range(1, n_rows): 11 | if strs[row][col] < strs[row - 1][col]: 12 | cols_d += 1 13 | break 14 | 15 | return cols_d -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 96 - unique binary search trees.py: -------------------------------------------------------------------------------- 1 | # unique binary search trees | leetcode 96 | https://leetcode.com/problems/unique-binary-search-trees/ 2 | # method: dp, use cached results for subtrees of all possible roots 3 | 4 | class Solution: 5 | def numTrees(self, n: int) -> int: 6 | # cache of possible trees 7 | possibleTrees = [1] * (n + 1) 8 | 9 | # for each number of nodes 10 | for numNodes in range(2, n + 1): 11 | 12 | # for each possible root 13 | possibleSubTrees = 0 14 | for possibleRoot in range(1, numNodes + 1): 15 | Left = possibleRoot - 1 16 | Right = numNodes - possibleRoot 17 | possibleSubTrees += possibleTrees[Left] * possibleTrees[Right] 18 | possibleTrees[numNodes] = possibleSubTrees 19 | 20 | return possibleTrees[n] 21 | 22 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 98 - validate binary search tree.py: -------------------------------------------------------------------------------- 1 | # validate binary search tree | leetcode 98 | https://leetcode.com/problems/validate-binary-search-tree/ 2 | # Given the root of a binary tree, determine if it is a valid binary search tree (BST). 3 | # method: in-order traversal of a valid bst gives a sorted array 4 | # tip: use `prev` pointer instead of an array to keep space complexity as O(1) 5 | 6 | # Definition for a binary tree node. 7 | class TreeNode: 8 | def __init__(self, val=0, left=None, right=None): 9 | self.val = val 10 | self.left = left 11 | self.right = right 12 | 13 | 14 | class Solution: 15 | 16 | # initialise a prev pointer 17 | def __init__(self): 18 | self.prev = None 19 | 20 | # in-order traversal (L M R) 21 | # should return a sorted array 22 | def isValidBST(self, root) -> bool: 23 | 24 | # if this node is none, its a leaf 25 | if root is None: 26 | return True 27 | 28 | if not self.isValidBST(root.left): 29 | return False 30 | 31 | if self.prev is not None and self.prev.val >= root.val: 32 | return False 33 | 34 | self.prev = root 35 | 36 | return self.isValidBST(root.right) -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 989 - add to array form of integer.py: -------------------------------------------------------------------------------- 1 | # add to array form of integer | leetcode 989 | https://leetcode.com/problems/add-to-array-form-of-integer 2 | 3 | class Solution: 4 | def addToArrayForm(self, num: list[int], k: int) -> list[int]: 5 | n = len(num) - 1 6 | carry = 0 7 | while k or carry: 8 | k, digit = k // 10, k % 10 9 | each = carry + digit 10 | if n < 0: 11 | num.insert(0, each % 10) 12 | else: 13 | each = each + num[n] 14 | num[n] = each % 10 15 | carry = each // 10 16 | n -= 1 17 | 18 | return num 19 | 20 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/14. Questions/leetcode 997 - find the town judge.py: -------------------------------------------------------------------------------- 1 | # find the town judge | leetcode 997 | https://leetcode.com/problems/find-the-town-judge/submissions/ 2 | # method: decrement trust value if you trust someone, increment if someone trusts you 3 | 4 | class Solution: 5 | def findJudge(self, n: int, trust: list[list[int]]) -> int: 6 | 7 | # for each person 8 | # trust += 1 if someone trusts you 9 | # trust -= 1 if you trust someone 10 | trustValue = [0] * (n + 1) 11 | 12 | for edge in trust: 13 | trustValue[edge[0]] -= 1 14 | trustValue[edge[1]] += 1 15 | 16 | for i in range(1, n + 1): 17 | if trustValue[i] == (n - 1): 18 | return i 19 | 20 | return -1 21 | 22 | -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/DSA_Cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/DSA_Cheatsheet.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/Python_Cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/Python_Cheatsheet.pdf -------------------------------------------------------------------------------- /Data Structures and Algorithms Python/Python_Cheatsheet_2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohanmistry231/DSA-in-Python/2ebe20cb7900f4c87c7262dfb8b8f1e16387a3bd/Data Structures and Algorithms Python/Python_Cheatsheet_2.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 rohanmistry231 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Data Structures and Algorithms in Python --------------------------------------------------------------------------------