View all files | ||||
Breakdown the problem with any possible number of smaller problem
Problem: clearly defined input satisfying any pre-condition, and a clearly defined output
Correctness: Part of any possible input the algorithm should always terminate or end. If the condition is not true then our algorithm is incorrect.
Efficiency: It helps to solve problem faster, and deliver better user experience. Measuring efficiency we always use worse case scenario as the benchmark because it can never perform worse than the worst case.
Two Major Efficiency: Time and space - Good algorithm need to balance between these two measures to be useful.
Big-O Complexity Chart
Input is sorted list of values and output is the position in the list of the target value we are searching. Or some sort of values indicates that the target does not exist in the list.
Example: Search 20 in list of 100 like [1, 2,3,4 so on]. Target is 5 here.
Growth rate: different algorithm grow at different rate abd by evaluating growth rate we get a much better picture of their performance because we know how the algorithm will hold up as n grows larger.
To represent complexity (time or space) there is asymptotic notation. A mathematical tool to represent time and space complexity
Order of magnitude of complexity - O(n). A function of the size. Big O measures complexity as the input size grows. Big O refer to as the upper bound of the algorithm. Here n means numbers of operations.
Big O is a useful notation for understanding both time and space complexity but only when comparing amongst algorithms that solve the same problem.
A function of the size: Big O measure the complexity as the input size grows because it's not important to understand how an algorithm performs in a single dataset but in all possible data sets.
Also, big O refer to upper bound of the algorithm. big O measure how the algorithm performs in the worst case scenario.
linear search big O = O(n), Binary search big o = O(log n)
Constant time: input size doesn't matter. regardless of the size of n since this takes the same amount of time in any given case then runtime is constant time it doesn't change. In big O notation it looks like O(1)
Exponent 2^3=8 and inverse of exponent called logarithm log _2 8 = 3
Logarithmic : or sub-linear runtimes are preferred to linear because they are more efficient but in practice linear search has its own search of advantages
Quadratic runtime : (square or to the power): For any given value of n carry out n squared number of operation. ex- n = 4, n^2 = 16, 4 x 4 grid = O(n^2)
Cubic runtime : n^3 . This are as common as quadratic runtime.
Quasi-linear : Quasi-linear runtime are written out as big o of n times log n. ex: O(n log n). For every value of n need to execute a log n number of operations hence the runtime of n times log n.
Polynomial Runtime : An algorithm is considered to have a polynomial runtime if for a given value of n its worst case runtime is in the form of n raised to the k power where k just means some value. ex: k = 2, O(n^k)
Algorithm with an upper bound or a runtime with a big O value that is polynomial are considered efficient algorithms.
Exponential runtime : N increases slidly, number of operation increases exponentially. O(x^n). The range of value we have to go to is 00 to 99 ant this can be generalized as 10^2. Searching though each individual until stumnle to the right one is a strategy call brute force and brute force algorithm have exponential runtime.
Factorial runtime : n! = n(n-1)(n-2)...(2)(1) . For example factorial of 3 is 3! = 3 x 2 x 1 = 6, factorial of 4 is !4 = 4 x 3 x 2 x 1. In solving the traveling salesman problem the most efficient algorithm is factorial runtime of a combinatorial runtime.
Space complexity: The algorithm does not need extra memory or the memory needed does not depend on the input size the space complexity is.
Data structure is a way of storing data in programming. It's not just collection of value and formant they are stored in but the relationship between the values in the collection as well as the operations applied on the data stored in the structure.
Examples:
Built in data structure in python,
Use built in data structure to create custom data structure
Array - can be used to represent a collection of values where each value is referanced using an index or a key.Arrays are also used in building block to create even more custom data types and structures.
Advantages of contiguous memory: since the values are stored beside each other accessing the values happens in almost constant time so this is a characteristic we want. The way python gets around this is by allocating contiguous memory and storing in it not the value we want to store but a reference or a pointer to the value that is stored somewhere else in memory
Common operations to execute on an array: All data structure expected to cary out 4 kinds of operations at minimum
String - Text are represented as string type and under the hood strings are just a bunch of charecters stored in a particular order in an array
Build Data Structure - Each data structure solves a particular problem. Arrays are particularly goot at accessing, reading values happen in constant time but Arrays are pretty bar at inserting and deleting both of which run in linear time. Linkedlist on the other hand are somewhat better at this although there are some caveats and if we are trying to solve a problem involves far more inserts and deletes than accessing a linkedlist can be a better tool than array.
Linkedlist - Linkedlist is a linear data structure where each element in the list is contained in a separate object called a node, a node models two pieces of information an individual item of the data we want to and a reference to the next node in the list
Sort Algorithm - merge [03:03:00]
Goal is to get an array sorted in ascending order
Merge sort work like binary sort by splitting up the problem into sub problems
Merge sort algorithm works backwards repeatedly merging the single element array and sorting them at the same time
Since we start at the bottom by merging to single element arrays, we only need to make a single comparison to sort the result
By starting the smaller array that are sorted as they grow merge sort has to execute fewer sort operations than if it sorted the entire array at once
Solving a problem like this by recursively breaking down the problem into subpart until it is easily solved is an algorithmic strategy known as divide and conquer
https://www.youtube.com/watch?v=Fo2Qnw5pMGo&list=PLC3y8-rFHvwiRYB4-HHKHblh3_bQNJTMa&index=3
https://github.com/twitter/the-algorithm https://github.com/trekhleb/javascript-algorithms/issues