
Explore how algorithms and software engineering apply across domains, from signal processing to cryptography and graph databases, and master core concepts through nine sections, practical coding exercises, and interview-focused practice.
Explore iterations and transformations on sequences through counting loops and factorial examples, compare iterative and recursive approaches in Java, and examine nested loops, streams, and triangle patterns.
Count up from 0 to 10 with a conditional block to form a triangle apex, highlighting a shift from decrementing loops while discussing recursion and Java collections.
Explore Java iterations by examining fixed-size arrays, dynamic collections, and safe iterator usage, plus how streams and lambdas transform the underlying sequence.
Investigate unsafe iteration on queues using a linked list; compare get on the underlying sequence with iterators, and study performance and Java streaming API considerations for maps.
Create and populate a Java map with integer keys and string values, then iterate the map. Use streams and collectors to transform, project, reduce, and group data, including binary gaps.
Compare two iterations for pattern sequences: a string-based solution finds the largest binary gap. A stream-based approach counts zeros between ones without creating new strings.
Compare string-based subsequences with a memory-efficient numeric stream for finding the largest sequence of zeros in binary data. Highlight streaming methods, genetic and bioinformatics applications, and sequence alignment in Java.
Explore time complexity with Big-O notation, limits, and common time classes such as constant, linear, and polynomial time. Analyze code examples to compare running times and recognize reusable patterns.
Explore how big O calculations relate sequence expressions to time complexities—from constant to quadratic—and compare linear and polynomial times.
Analyze time complexity by identifying the dominating term in factorial growth and expressing it as a polynomial-time pattern, then use a sine power series to generate and compare results.
Explore coding a sequence solution using odd numbers and alternating signs, compute the series sum, and analyze time complexity from linear to logarithmic terms.
Explore Big-O time complexities and array operations by implementing a linear equilibrium index algorithm that uses a running left sum and total sum to compare left and right.
Demonstrate an optimum index operation that minimizes the absolute difference between left and right sums in an array, using constant time access for efficient optimization.
Explore how arrays provide constant access and how sorting works, focusing on selection sort, its nested loops and swaps, and finding a missing element in an arithmetic sequence.
Analyze a time complexity lab for an array task that computes the difference between two sums and achieves linear worst-case time, highlighting constant-time array access and data structure tradeoffs.
Learn how space complexity measures an algorithm’s memory usage from constant to recursive memory, and distinguish it from time complexity, including upper-bound and tight-bound notions such as big-O.
analyze selection sort and bubble sort, their constant space versus polynomial time, and the potential best-case improvement for bubble sort.
Explore time and space complexity in sorting algorithms and how program flow and Java virtual machine optimizations affect timing. Compare quicksort with bubble sort and selection sort using a pivot.
Explore a partition-based sorting approach using a pivot and upper bound. Compare quicksort's performance with selection sort on random data and note JVM effects on timing.
Explore counting concepts, optimization, and dynamic programming in algorithms, then apply sliding window methods to find maxima and minima in discrete subsequences.
Explore how to compute sliding window minima and maxima for all windows of a fixed size, using left and right passes and two arrays for constant-time lookups.
Learn to use a sliding window to compute running minimums and maximums in time series and extend it to locate the maximum index, a core time series segmentation technique.
Apply a sliding window over a binary time series using a bitmap to track 0/1 values, enabling a space-efficient segmentation of time series and counting unique values within the window.
Explore counting patterns in algorithms by analyzing combinations, permutations, and mutations, and distinguish their distinct arrangements and formulas. Learn to implement simple algorithms that count these patterns.
Analyze counting combinations, address overflow and time complexity, and compare brute force, recursion, and big integer approaches for handling large numbers.
Explore how to count permutations through a recursive algorithm while managing time complexity and overflow risks, and compare Java collections with arrays for fast lookup.
Demonstrates counting to find the missing number in a permutation using a sliding window and hash set, with input validation to confirm the sequence is a permutation.
Apply the counting theorem, or pigeonhole principle, to reduce memory usage and boost efficiency in algorithms while weighing readability and performance in Java implementations of permutations and combinations.
Compare two counting sort implementations, one using Java collections and one with static arrays, and explain the counts array built from the input's maximum value.
learn pigeonhole sort and counting sort to organize complex objects like ordered pairs into keys, holes, and slots, and tackle practical tasks such as finding a missing integer.
Explore counting and optimization techniques to identify a missing number using binary decomposition, recursive shifting, and bitwise operations, comparing zero and one lists to locate the anomaly.
Explore sorting concepts and time complexity across algorithms such as insertion sort, quicksort, merge sort, and radix sort. Learn how counting and the pigeonhole principle enable efficient sorting of tuples.
Learn to implement insertion sort using generics and a comparator, sorting any type that implements comparable, by inserting elements via temporary storage and comparing with a compare method.
Explore insertion sort through Java generics and interfaces, analyze inversions and time complexity, and practice counting distinct values in an integer array using standard collections.
Count the number of distinct integers in an array by iterating the sequence and inserting elements into a set, then return the set's size, using hash tables for constant-time lookups.
Break the quadratic time barrier by applying shell sort with progressively shrinking gaps, swapping distant elements to outperform insertion sort through gap-based comparisons.
Learn how heapsort uses an array-based heap, with parent and child indices, to repeatedly remove the root, update the heap, and produce a sorted array.
Learn to compute the maximum value obtainable from a subsequence of integers by iteratively updating a three-slot max tuple through compare and swap operations, handling positive and negative values.
Explore quicksort as a divide and conquer sorting algorithm with pivot and partitioning. Learn how insertion sort is used for small subarrays, and how median-of-three pivot selection optimizes performance.
Learn merge sort through recursive splitting of arrays into subarrays, then merging them to a sorted sequence, while analyzing space and time complexity and practical implementation details.
Explore radix sort, a non-comparative sorting algorithm using digits and a base k to bucket and sort integers or strings by least significant digits.
Implement radix sort for strings using 256 buckets and a count-based bucket approach, handling odd input lengths with a buffer and swapping input and output arrays across passes.
Explore practical radix sort on string arrays by implementing counting buckets and a counting array, sorting by character codes with Unicode representations for linear-time, non-comparative performance.
Explore stack concepts, including push, pop, and top, and compare stacks with queues, examining time and space complexity, array versus list implementations, and linked list stack designs.
Explore how a linked-list stack uses nodes with payloads and a next pointer for traversal and dynamic insertions. Compare its memory costs to an array-based stack with push and pop.
Explore stack-based reverse Polish notation to build a simple calculator, pushing operands and applying operators, using a linked list stack and postfix evaluation.
Count distinct integers by inserting elements into a set that enforces uniqueness, and compare hash set performance with arrays through constant-time lookups and linear space.
Explore queue concepts, including enqueue and dequeue, first-in, first-out ordering, and how pipes, operating systems, and high-velocity data streams use queues in diverse applications.
Implement a queue using a linked list in Java, preserving insertion order, with front and back pointers, enqueue and dequeue operations, and proper empty queue handling.
Explore practical queue concepts in Java, comparing queue implementations, operations like poll, remove, element, and peek, and building a simple message queue with a topic and content payload.
Explore a stacks and queues lab 2 practical application of a queue, implementing a FIFO with a linked list: push arrivals to back, remove from front, print to standard output.
Explore parsing concepts using stacks and queues to evaluate postfix expressions with reverse Polish notation, build grammars and abstract syntax trees, and distinguish well-formed expressions from semantically invalid ones.
Implement a simple AST parser that builds a compilation unit, uses stacks and queues to extract identifiers and declarations, and verify well-formed expressions with matching opening and closing characters.
demonstrate parsing well-formed expressions using a plain Java stack, pushing openings, matching closings, and returning 1 for well-formed and 0 for malformed expressions.
Explore slice operations on sequences, including non-consecutive and contiguous slices, subarrays, and streaming data, with a focus on maximum subarray problems and applications like heart-rate monitoring.
Implement Kadane's algorithm to find the maximum contiguous subarray sum by iterating the input, tracking running and maximum sums, and recording the start and end indices.
Determine the maximum double-slice value by handling a missing element in a contiguous slice with a modified dynamic approach using forward and reverse passes.
Explore slice operations and their role in binary image representation, using indices to store slices efficiently. Apply a maximum sum approach to determine the best profit from day-to-day price changes.
Explore slice operations on arrays to compute maximum profit or loss, track the lowest price, and verify transactions, while analyzing slice origins and efficient representations for data analysis.
Explore divisibility operations by partitioning sequences into slices and partitions, comparing fixed-size and dynamic approaches, and implementing partitioning with array copies and iterative lists of partitions.
Explore the Euclidean algorithm for computing the greatest common divisor of two integers, its efficiency over prime factorization, and its role in cryptography, with a worked example.
Implement a primality test by checking divisibility up to the square root, ignoring 0 and 1, and testing odd divisors for primes used in cryptography.
Explore slice-based analysis of a binary heart-rate signal to detect peaks and intervals, using time slices and maximum subarray techniques to assess heart rate variability and stress signals.
Demonstrates a lab approach to simple peak detection by slicing a sequence into sizes 9, 3, and 1, storing peak indices, and validating each slice for a peak.
Explore how prime numbers underpin cryptography and security, and apply efficient primality tests using modular division and the square root bound to distinguish primes from composites.
Learn the sieve approach to generating primes up to a bound by marking multiples of each prime as non-prime, using the square root bound for efficiency.
Explore Rabin primality tests for large primes, using multiple random-base rounds and modular exponentiation, and implement the approach with Java's BigInteger for practical testing.
In slice operations lab 3, explore probabilistic primality testing for large primes using random trials, modular exponentiation, and repeated iterations to assess primality with high probability, relevant to encryption keys.
Explore how search algorithms improve data retrieval by moving from linked lists to indexed structures like hash tables and binary search trees, achieving constant or logarithmic times.
Implement a binary search on arrays using low, high, and mid indices to compare the target and adjust bounds until you find it or return -1, achieving log n time.
Explore how a hash table delivers constant time lookups via a hash function indexing an underlying array and handling collisions with a simple scheme storing key-value pairs in buckets.
Explore how to apply binary search to optimization problems by evaluating midpoints, partitioning sequences into nonempty and empty blocks, and minimizing the maximum sum.
Learn how binary search trees extend binary trees with left and right children to preserve a sorting relationship, enabling on-average log n search times and recursion-based traversal; worst-case remains linear.
Explore how a binary search tree stores comparable elements with a root, left, and right children, using insert and lookup. Recursively print the tree to verify structure.
Explore binary search tree operations with randomized inserts, including printing, lookup, and measuring height, size, and max depth, and extend the API to return the maximum value in the tree.
Extend the binary tree api by implementing a non-recursive max value finder that traverses the right branch. Leverage insertion ordering for efficient lookups, and compare non-recursive and recursive approaches.
Explore AVL trees by balancing binary search trees with rotations to keep subtree heights differing by at most one. Learn how rotations preserve ordering while rebalancing for efficient search.
Implement an AVL tree using a binary search tree API, inserting nodes and then balancing with height-based rotations, including left and right rotations and double rotations.
Study subtree height and balance that drive rotations to maintain a binary search tree's ordering. Print all possible paths via recursion and verify rotations with debugging operations.
Explore a tree-based path traversal using recursion to print paths from the root node. Analyze left and right branching, increasing and decreasing sequences, balance, and how input ordering guides debugging.
Learn core graph concepts: vertices and edges, undirected and directed graphs, adjacency, degree, paths and cycles, connectivity, planar and non-planar graphs, and Euler's formula; plus graph databases and path queries.
Implement a graph as an abstract data type using an array of adjacency sets, where each vertex stores edges in a hash set and reads input via a scanner.
Implement a depth-first search on a graph using recursion, mark vertices as searched, traverse adjacent nodes, and determine connectivity and whether a path exists.
Explore path search in a directed graph using depth-first search, storing edges in arrays, marking visited nodes, and tracing a route from source to target with a stack.
Explore graph search techniques by implementing depth-first search and breadth-first search, distinguishing directed and undirected graphs, marking discovered vertices, and finding the shortest path from source to target.
Implement a directed graph as an ADT with ordered edge pairs, tracking in-degree and out-degree, building adjacency sets, and providing constructors and a pretty print method from input data.
Implement a breadth-first search on a directed graph to find the shortest path. Use a queue, a distance array, and a visited mark to explore adjacent nodes.
Demonstrates breadth-first search on a directed graph to find the shortest path from source to target, highlighting the 2-5-6 route over 2-3-4-5-6, using a queue-based traversal.
Explore topological sort on directed acyclic graphs, using zero in-degree nodes to form an order. See how cyclic dependencies cause memory leaks and why graph shape, not numbers, drives order.
Master topological sort by performing a depth-first search on a directed graph, using a stack to reverse the visit order based on vertex in-degrees and visited status.
Develop and test an optimized shortest path search to find the smallest directed cycle in a graph by cloning the graph, computing distances, and selecting the minimal cycle length.
Learn greedy programming concepts, making local decisions to reach local optima for efficiency, while noting potential failure to reach global optimum; compare with dynamic programming and divide-and-conquer.
Apply a greedy design to select the widest non-overlapping segments on a number line, using start and end arrays and a stored previous end to reach a local optimum.
Learn a greedy approach to identifying non-overlapping segments by sorting endpoints, preserving segment identities, and iterating to print the maximal non-overlapping set.
Explore dynamic programming as a global, structure-driven approach that contrasts with greedy local optimizations, using substructure thinking to achieve global optimum in problems such as text justification and sequence analysis.
Explore text justification by comparing a dynamic solution with a greedy approach, using hash maps and recursive techniques to build lines and measure efficiency.
Explore dynamic programming techniques to optimize text justification and stock trade decisions, using tokenization, start-point arrays, recursion, and cost-based minimization.
Explore dynamic programming approaches to optimize stock trades, comparing local decisions to global optima, and illustrating how to compute maximum values using arrays, streams, and simple greedy contrasts.
Explore divide and conquer algorithms, focusing on recursive, multi-branched structures to exploit multi-processor machines and parallelism, with applications like counting inversions and merging to sort arrays.
Implement a divide-and-conquer solution to count inversions using merge-sort style recursion. Split the sequence at the midpoint, recurse on halves, and merge while counting inversions and handling repeats.
Learn how to count inversions using a divide-and-conquer approach with recursive merge sort, handling two-branch recursion, base cases, and extreme values for efficient algorithm design.
In order to build something, you must start from the ground up. It is always important to understand the basics and the core of a concept and this ideology also holds true for software programming. Data structures and algorithms are the basic building blocks for Software Engineering, that determine how the system will operate.
Data structures and algorithms are two common concepts that can be found in Software Engineering and are imperative to mastering any programming language or technology within the software technology landscape. In order to master any programming language, functional or objective, one must first understand the basic concept behind it, which includes algorithms.
Data in software engineering are represented in data structures such as maps, lists, trees, etc. and is in the constant need of being sorted and merged, transformed and matched in some way. For this reason, software engineers devised algorithms as a solution for this task, which is consistent, repeatable and testable with a set of metrics to quantify performance.
However, for data structures to work seamlessly with your system, you need to understand the basics to creating clean, efficient and powerful algorithms that reduces the amount of work required by the engineer. This is where this course can help.
Our comprehensive course has been designed to help you understand algorithms and data structures from scratch. This course covers important concepts related to data structures and algorithms including the five major categories of algorithms: Cryptography, Compiler Theory, Signal Processing, Data Analysis, and Graph Databases. This is a course for the Big Boys.
It also includes understanding other primary concepts such as recursion and its relationship to concurrency and ADT’s like Trees and Graphs; relationship between trees and rotation operations used in balancing, operations with Primes, Fermat's theorem, parsing grammars with Stacks and Queues and related tools like AST based parsers the beginning step on the road to Compiler theory.
In addition to covering the theoretical concepts, the course also is packed with examples of practical applications. It is important to not only understand what the concept it, but also how to use it. You will definitely get the best of both worlds in this algorithm and data structure tutorial.
This course will also help you ace the theoretical intensive tech interviews. So if you plan to apply for a tech job, this course will act as a great refresher.
With this course, you will not only be able to understand algorithms, but actually write better algorithms to help simplify your programming life. With this much power waiting for you, what are you waiting for? Let’s get started.