# Analysis of Algorithms - helps to compare performance of algorithms - Asymptotic Analysis - Theroritical analysis of algorithm - measure the order of growth based on input size - does not depend of machine, programming language etc - no need to implement, we can analyze algorithm ### Asumtotic analysis - all constant operations takes constant time ### Complexity Analysis - How much time - Time complexity - How much space - Space Compleixty ### Big O Notation - upper bound of complexity in worst case for large input size ### Complexities - Constant Time O(1) - Log Lograrithmic Time: O(log log(n)) ``` python for i in range(0, n, n ^ 2): pass ``` - Lograrithmic Time: O(log(n)) ``` python for i in range(0, n, n * 2): pass ``` - Linear Time: O(n) ``` python for i in range(0, n, n + 3): pass ``` - Linearithmic Time: O(nLog(n)) - Quadratic Time: O(n ^ 2) ``` python for i in range(n): for i in range(n): pass pass ``` - Cubic Time: O(n ^ 3) - Exponential Time: O(b ^ n), b > 1 - Factorial Time: O(n!) ``` O(1) < O(log log(n)) < O(log(n)) < O(n) < O(nlog(n)) < O(n ^ 2) < O(n ^ 3) < O(b ^ n) < O(n!) ``` ### Problem Complexities - Prime factorization of an integer, or checking primality or compositeness of an integer naively: O(sqrt(n)) - Iterating through all subsets of size k of the input elements: O(n^k). For example, iterating through all triplets is O(n^3). - Iterating through all subsets: O(2^n) - Iterating through all permutations: O(n!) - Sorting using Merge sort - O(nlog(n)) - Java Quick Sort - O(n ^ 2) - Iterating matrix - O(mn) ### Other concepts - P vs NP - Polynomial Time vs Non Deterministic Polynomial Time problems (exponential time O(2 ^ n and more)) - NP Complete Problems Ad-hoc problems are problems that don’t fall into any standard algorithmic category with well known solutions ### Amortized Analysis estimate the total time used to all such operations during the execution of the algorithm, instead of focusing on individual operations. What does it mean when we say that an algorithm X is asymptotically more efficient than Y? - X will always be a better choice for large inputs ### Analsysis of Loops TC: O(1) SC: O(1) ``` python for i in range(0, 1000000000): pass ``` TC: O(n) SC: O(1) ``` python for i in range(0, n, c): pass ``` TC: O(log (c) n) SC: O(1) ``` python for i in range(0, n, i * c): pass ``` TC: O(log (2) n) SC: O(1) ``` python for i in range(0, n, i * 2): pass ``` TC: O(log log (2) n) SC: O(1) ``` python for i in range(0, n, i ** 2): pass ``` TC: O(nlog (2) n) SC: O(1) ``` python for i in range (n) for i in range(0, n, i * 2): pass ``` TC: O(log (2) n) + O(n) -> O(n) SC: O(1) ``` python for i in range (n) pass for i in range(0, n, i * 2): pass ```