
Explore data structures and algorithms in Python, including recursion, Big-O notation, nine data structures, eight sorting algorithms, and learn through 12 chapters with visual animations.
Learn how computers store and process data using bits and binary, encoding characters with ASCII and Unicode, and how transistors enable 32- and 64-bit architectures.
Define algorithms as finite, well defined sequences of steps that take inputs and produce outputs. Emphasize correct order, efficiency, and practical steps from understanding the problem to testing and refactoring.
Explore how data structures organize data, relationships, and operations—from arrays and dictionaries to trees and graphs—and optimize access, updates, and problem solving.
Explore how to measure algorithm efficiency using big-O and computational complexity, comparing time and memory and focusing on growth rates as input size changes.
Learn constant time complexity (O(1)) in data structures and algorithms, where runtime and memory stay fixed regardless of input size, shown via simple first-element operations.
Learn how o(n) complexity represents linear time, where a constant-time operation processes every element in the input via for or while loops.
Learn about quadratic time, O(n^2), where nested loops cause n squared operations for large inputs. Compare with O(n) and discover how redesigning solutions avoids excessive nested loops.
Clarifies logarithmic time by defining logarithms and showing how binary search achieves O(log n) growth, highlighting base independence and efficiency for large inputs.
Discover space complexity by focusing on auxiliary memory beyond input. See how a for loop uses O(1) space, a new list yields O(n), and logarithmic search uses O(log n).
explore how to determine asymptotic complexity by identifying dominant terms, discarding constants, and applying big-o rules to linear, quadratic, and logarithmic growth in algorithms.
Explore how function calls create private stack frames on the call stack, storing locals, arguments, and return values, and how last-in, first-out execution drives nested calls and recursion.
Explore recursion through the factorial example, where a function calls itself on a smaller input, and learn the base and recursive cases managed by the runtime stack.
Explore how a correct base case and a proper recursive step prevent infinite recursion and stack overflow in Python, and analyze the Fibonacci example for overlapping subproblems.
Explore recursion vs iteration with an array product example, compare performance and readability, and learn when to choose each approach based on language and data structures.
Explore how recursion affects time and space complexity, deriving O(n), O(log n), and exponential growth from recursive calls, base cases, and stack frames.
Learn how arrays, or lists in Python, store values and grow as needed with dynamic arrays, comparing capacity and size, memory allocation, and the cost of resizing.
Explore how Python dictionaries operate as hash tables, mapping unique keys to values with a hash function, and resolve collisions through separate chaining or open addressing.
Discover how Python dictionaries achieve o(1) operations for add, update, access, and remove, and how hash functions, collisions, and memory usage influence performance and views like keys, values, items.
Introduce singly linked lists as a node-based data structure where each element resides in its own node connected by next pointer. Head marks the first node; tail points to none.
Implement the append method for a singly linked list by creating a node, attaching it to the tail, updating head and tail for empty lists, and analyzing complexity.
Learn how to prepend elements to a singly linked list in Python, creating a new node, updating head (and tail for empty lists), and achieving constant time and space complexity.
Implement pop left to remove the leftmost node: save the head, update head to the next, detach the old head, adjust length, and raise an exception on empty lists.
Discover the pop right method: remove the last element of a singly linked list by updating the tail to the second to last node and returning the removed value.
Learn to remove a node by value from a singly linked list using two pointers, handling the head, tail, not found cases, and first occurrence while preserving integrity.
Learn to reverse a linked list in place using three pointers and a forward traversal that rewires next pointers, achieving O of N time and O of one space.
Recap the linked list memory model, where head and tail pointers connect nodes, and compare operations and complexities with arrays, covering append, traverse, search, and access.
Learn how adding a previous pointer converts singly linked lists into doubly linked lists, enabling bidirectional traversal and simpler tail removal, with changes to node and list structures.
Implement the append method for a doubly linked list by creating a new node, linking it to the tail with next and previous pointers, and updating the tail.
Prepend adds a new node to a doubly linked list and links it to the old head. It updates the head, increments length, and maintains the previous pointers.
Implement pop left for a doubly linked list by updating the head, breaking the old connections, handling empty and single-element cases, and decrementing length to return the removed value.
Learn to implement pop right on a doubly linked list by updating the tail to its previous node, severing tail, and updating length in O(1) for empty or single-element lists.
Remove a node by value in a doubly linked list by updating the previous and next pointers, handling empty lists and head/tail removals, with O(n) time and O(1) space.
Explore doubly linked lists, compare with singly linked lists and arrays, and understand fast end insertions and removals, linear-time search, and memory trade-offs in Python data structures.
Stacks are linear data structures defined by interaction with data, not storage. They use a last in, first out rule from a single end, with push and pop operations.
Use the end of a regular array to implement a stack, pushing with append and popping from the end for O(1) operations, avoiding costly beginning operations.
Build a stack from a singly linked list, using the head as the top, achieving constant time push and pop, with optional capacity, and helpers like peek, clear, and size.
Explore how stacks manage function calls with the runtime stack and support delimiter matching in expressions, while the compiler uses a stack for syntactic checks and backtracking in traversals.
Explore queues as a first in, first out data structure with enqueue and dequeue, distinct ends for adding and removing, and implementations using arrays or linked lists for efficient performance.
Build a queue using a singly linked list with head, tail, and size, enabling enqueue and dequeue. Understand queueing theory and uses like messaging queues, cloud services, and call centers.
Explore Python's deque from the collections module, a double-ended queue with fast appends and pops on both ends, suitable for stacks and queues.
Master the binary search tree: each node has at most two children; left values are smaller, right values greater; duplicates are avoided, enabling efficient insertion, searching, and deletion.
Insert adds a new node to a binary search tree, traversing from the root to left or right. Handle empty trees and duplicates, and cover time and space complexity.
Use a contains method for a binary search tree that returns true when the value is found and false otherwise, traversing from the root with a while loop.
Explore implementing a tree remove method by locating the target node and its parent, and handling leaf, single-child, and two-child cases with start and parent tracking.
Remove a leaf node from a binary tree by detaching it from its parent and setting the correct child to None, including the root-as-only-node case, in Python.
Learn how to remove a node with one child in a tree by updating the parent to point to the node's existing child, preserving the branch and handling root.
Remove a node with two children by replacing it with its successor, found by moving right once and then left as far as possible, then recursively removing the old successor.
Explore how to traverse a binary tree by visiting each node once, using breadth-first or depth-first methods, with depth-first variants in-order, pre-order, and post-order, implemented with recursion or iteration.
Learn breadth-first traversal of a binary tree, visiting each level left to right (or right to left) using a queue and a visited list, with O(n) time and space.
Perform preorder iterative depth-first traversal using a stack to visit a node before its children, with time and space complexity O(n) in worst case, and memory proportional to tree depth.
Explore preorder depth-first traversal using recursion in Python, implementing a traverse function, visiting nodes, left then right, with base cases and O(n) time and space.
Learn the iterative in-order traversal of a binary tree with a stack, visiting left, then node, then right, and analyze its O(n) time and space.
Switch to in order traversal by visiting the node after traversing the left child, implemented recursively, highlighting simplicity versus iterative methods.
Master post-order traversal and its iterative implementation using a stack. Learn how the left, right, then parent order is achieved, tracking current and previous nodes to visit and record nodes.
Explore the recursive postorder traversal for binary trees, visiting the node after traversing left and right, and see how the call stack clarifies the left-right-node pattern.
Recap of breadth-first and depth-first tree traversals, comparing memory usage and performance, and describing preorder, inorder, and postorder variations for practical applications.
Learn how heaps, a binary tree, use an array to enforce max-heap order, with parent and child indices computed via simple formulas.
Insert into a max binary heap stored as an array by appending at end, and swap with its parent to maintain heap property, with O(log N) time and O(1) space.
Remove max explains how to delete the heap's top element by swapping with the end, popping, and moving down to restore the heap property, achieving O(log n) time.
Learn Floyd's bottom-up heapify method to rearrange an array in place into a heap, starting from the last non-leaf and moving down, achieving O(n) time.
Building reliable and highly performant software requires knowledge that goes beyond a certain programming language or framework. It requires a solid understanding of how data is organized in memory, how it can be manipulated, sorted or searched into. There’s a reason why all the big tech companies such as Google, Amazon or Netflix focus their technical interviews on those topics. Whether you do mobile apps, websites, games, machine learning or any other work that involves coding, you need a good grasp of Data Structures and Algorithms.
Many self taught developers and aspiring engineers often feel they lack the knowledge when having to decide on the right data structure or the right approach for solving a problem. If you ever felt that way, this material is the right choice for you. This course packs months of Computer Science subject matter to get you on the same level of proficiency as someone with a Computer Science degree.
What sets us apart ?
Every video begins with an in depth analysis of the topic at hand. At this stage we won’t write any code yet, but rather learn how to approach the problem, think of ways we could solve it and build a mental model of the solution.
We then go on to code the algorithm step by step. But we don’t stop there. We take one or more examples and walk through the code line by line. And we mean that literally. You will see how the code runs from top to bottom and how data flows and changes during execution. We find this method the absolute best way to really understand the inner workings of an algorithm.
We’ll also analyze the time performance and space utilization of every algorithm and method we write using the Big O Notation. We’ll talk about the strengths and weaknesses of each data structure and discuss their real world usage. Apart from all of that, you’ll also learn things like recursion, how computers work under the hood, problem solving techniques, common programming patterns and much more.
What does this course cover ?
How computers work under the hood
What a data structure is
What an algorithm is
Problem solving techniques
Big O Notation - how to analyze the time performance and space utilization of algorithms. This is done for every single function/algorithm we write.
Gain a deeper understanding of how code works
Recursion
Data Structures:
Arrays
Hash Tables
Singly Linked Lists
Doubly Linked Lists
Stacks
Queues
Binary Search Trees
Tree Traversal
Heaps
Graphs
Sorting Algorithms:
Insertion Sort
Selection Sort
Bubble Sort
Shell Sort
Heap Sort
Merge Sort
Quick Sort
Radix Sort
Thanks for considering, and I hope this course will help you in your journey. Happy learning!