Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
5 views

DSA Python (1)

Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

DSA Python (1)

Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 21

Data Structures and Algorithms (DSA)

Guide Source: https://www.youtube.com/watch?v=mGJusQ7iBwc

Data Structures
 Data structures are ways of organizing and storing data in a computer so that it can be
accessed and modified efficiently.
 Storing data in such manners so the operations on data can work efficiently.
 Every Integer in memory store in:
 C/C++: 2/4bytes (1byte=8bits)
 Java: 4bytes
 Python: 28bytes
 Data Structure: Organizing data Temporarily in Ram/Memory. (RAM have linear
architecture)
 Data Base: Organizing Data Permanently in Storage/Cloud etc.

Classification of Data Structures:


Criteria Type Definition Examples
Primitive vs Primitive Basic data types supported by the int, float, double, char,
Non- language. bool, complex (String,
Primitive Array, List, Tuple), null
Non- Derived data types built from Array, Linked List, Tree,
Primitive primitive types. Graph, Stack, Queue,
Map/Hash
Table/Dictionary
Linear vs Linear  Data is arranged sequentially, Array, Linked List,
Non-Linear one after another. Stack, Queue
 Data may has no relation.
e.g. Age [24, 23, 33, 28, 30]
 Access all element one by one.
 Easy implementation.
 Less Memory Utilization.

Non-Linear  Data is arranged hierarchically Tree, Graph


or in a network structure.
 Hard implementation.
 More memory Efficient.

Static vs Static Fixed size, defined during compile Array


Dynamic time.
Dynamic Size can change during runtime. Linked List, Tree, Graph
Homogeneo Homogeneo Contains elements of the same Array, Stack, Queue
us vs us data type.
Heterogene Heterogene Contains elements of different data Structure, Dictionary,
ous ous types. List, Tuple
Persistent Persistent Retains previous versions after Immutable Linked List
vs Non- modifications.
Persistent Non- Does not retain previous versions Standard Array, Linked
Persistent after modifications. List
Mutable vs Mutable  Allow changes to their content List, Dictionary
Immutable after they are created.
 Like type & size can change.
 Operations like insertion,
deletion, or modification.
Immutable  Don’t allow changes to their String, Frozen set,
content once they are created. Tuple
 Like type & size can’t change.
Data Types:
Data types specify the type of data a variable can hold and the operations that can be
performed on it.
DT: Value/Data +Operation/Function.

1) Simple Data Types (Primitive Data Types):


These are the most basic data types provided by a programming language.
Type Description Examples
Integer Represents whole numbers int
Float Represents real numbers with float, double
decimals
Charact Represents a single character char
er
Boolean Represents logical values bool
(True/False)
2) Complex Data Types (Non-Primitive Data Types):
These are more advanced data types derived from simple data types.
Type Description Examples
Array A collection of elements of the same [1, 2, 3]
type.
String A sequence of characters. "hello"
List A dynamic collection of elements, can [1, "hello",
be of different types. 3.5]
Set An unordered collection of unique {1, 2, 3}
elements.
Dictionary A collection of key-value pairs. {"key":
"value"}
User- Custom types created by the user class, struct
Defined (e.g., classes, structures).
Types
3) User-Defined Data Types:
Created by programmers to represent complex real-world entities by combining multiple
primitive or complex data types.
UDDT: OOP (Class/Objects), Stack
Type Description Purpose
A user-defined blueprint for
Used for creating complex data
creating objects. It combines
Class structures and implementing
data (attributes) and methods
object-oriented design.
(functions) into a single unit.
A simplified way to define classes Used for creating data models
Data that store data. It automatically where the main purpose is
class generates special methods like storing and accessing structured
__init__, __repr__, and __eq__ data.
Used for variables with a fixed set
A set of named constants that
Enum of valid values (e.g., colors,
represent fixed possible values.
states).
Named An extension of a tuple that Used for representing immutable,
Tuple associates field names with structured data in a readable
values, making the code more manner.
readable and self-documenting.
Custom A user-defined error type created Used for defining application-
Excepti by inheriting from the built-in specific error types to improve
on Exception class. error handling.

4) Abstract Data Types (ADT):


Defines what operations are allowed on the data, but it does not specify how these
operations are implemented.
ADT Description Operations Example
Implementation
Stack A collection that follows Last-In- push(item), Implemented using an
First-Out (LIFO) order. Elements pop(), peek(), array or linked list.
are added and removed from the is_empty() Example: push(),
same end (top). pop()
Queu A collection that follows First-In- enqueue(item), Implemented using an
e First-Out (FIFO) order. Elements dequeue(), array or linked list.
are added at the back and removed front(), Example: enqueue(),
from the front. is_empty() dequeue()
Priorit A collection where each element insert(item, Implemented using a
y has a priority. Elements are priority), heap (binary heap).
Queu removed in order of their priority. remove(), Example: insert(),
e peek() remove()
List A collection of ordered elements insert(), Can be implemented
where each element has a position. delete(), find(), using arrays or linked
get() lists. Example: insert(),
find()
Set A collection of unique elements insert(), Implemented using
where order doesn't matter. remove(), hash tables or binary
contains(), search trees. Example:
union(), insert(), contains()
intersection()

Abstraction in Programming:
Refers to the concept of hiding complex implementation details and exposing only the
necessary and essential features of an object or system. It allows developers to focus on
what an object does rather than how it does it.
Example:
 When you use a print () function, you don’t need to know how the underlying printing
mechanism works; you only need to know how to call the function.
1. Abstraction Mechanisms:
2. Types of Abstraction:
1. Data Abstraction
Focuses on hiding the internal representation of data and exposing only the operations.
Example: Encapsulation in classes hides internal attributes while providing public methods to
interact with them.
2. Control Abstraction
Focuses on abstracting control flow (e.g., loops, conditional statements).
Example: High-level constructs like for loops or if-else hide the underlying machine-level
instructions.

3. Interfaces:
Type Definition Purpose Example
Construct Initializes the ADT, To create and initialize def __init__(self): self.items =
or setting up its internal an instance of the ADT. [] for a Stack.
state.
Accessor Retrieves data from To read or access the def peek(self): return
the ADT without data from the ADT. self.items[-1] in a Stack.
modifying it.
Mutator Modifies the data To modify the contents def push(self, item):
inside the ADT. or state of the ADT. self.items.append(item) in a
Stack.
Iterator Provides a way to To iterate through or def __iter__(self): return
traverse the elements access elements iter(self.items) for a Stack.
of the ADT. sequentially.

4. Real-World Example:
Think of a car as an abstraction:
 You interact with the car through a simple interface: steering wheel, pedals, and
buttons.
 You don’t need to understand the complexities of how the engine works, how fuel is
injected, or how the braking system functions.
5. Advantages of ADTs
 Modularity: By abstracting away the internal implementation details, ADTs allow
changes to the data structure implementation without affecting the rest of the
program.
 Maintainability: Since the user interacts with a well-defined interface, maintaining or
updating the implementation becomes easier.
 Reusability: ADTs can be reused across different programs without worrying about
their underlying implementation
d

 Basic Data Structures:


o Arrays, Strings
o Stacks, Queues (using collections.deque)
o Linked Lists (Singly, Doubly, Circular)

Arrays:
Aspect Low-Level Arrays Referential Arrays
Definition Stores primitive data directly in Stores references (pointers) to data.
memory.
Storage Continuous memory allocation for Stores addresses of data located
elements. elsewhere.
Access Faster due to direct indexing. Slower due to pointer dereferencing.
Time
Memory More memory-efficient (no Higher memory usage (stores
Usage indirection). references).
Data Type Primitive and homogeneous types. Can store objects and heterogeneous
types.
Flexibility Fixed size. Dynamic size and flexible.
Example int arr[5] = {1, 2, 3, 4, 5}; arr = [obj1, obj2, obj3]
Pros Fast access, lower memory overhead. Can store complex or dynamic data
types.
Cons Rigid in size and type. Slower access and higher memory
overhead.

Here’s a detailed comparison between Arrays and Lists in a table format:


Aspect Arrays Lists
Definition A collection of elements of the same An ordered collection of elements that
data type stored in contiguous memory can be of different data types. Its
locations. Referential Array.
Data Type Homogeneous (all elements must be of Heterogeneous (elements can be of
the same type). different types).
Storage Continuous memory allocation. Memory allocation is dynamic (not
necessarily contiguous).
Size Fixed (size is defined at creation and Dynamic (size can grow or shrink as
cannot be changed). needed).
Access Time Faster (direct indexing with contiguous Slower (due to dynamic memory
memory). management).
Flexibility Less flexible (requires homogeneous More flexible (can store any type and
elements and fixed size). grow dynamically).
Insertion/ Expensive (requires shifting elements). Easier (elements can be
Deletion inserted/removed dynamically).
Indexing Supports indexing (O(1) time Supports indexing (O(1) time
complexity). complexity).
Memory More memory efficient (no overhead Less efficient due to dynamic memory
Efficiency for type). and type handling overhead.
Use Cases Used when size and type are fixed, and Used when the collection requires
fast access is required (e.g., numerical flexibility in size or types (e.g., general-
computations). purpose collections).
Example import array; arr = array.array('i', [1, 2, lst = [1, "Hello", 3.5, True]
(Python) 3])
Pros Faster, more memory-efficient for large Flexible, easy to use, and supports
datasets of the same type. heterogeneous data.
Cons Fixed size, less flexible, requires type Higher memory overhead, slightly
declaration. slower.

Array ADT:

There are two types of arrays based on implementation:

1. Predefined Array ADT

2. User-defined Array ADT (***imp)

Constructor

Forward & Reverse Traversing (***imp)

Updating

Adding

Deletion

Searching

Array Traversing: (***imp)

Core Data Structures


 Advanced Linked Lists:
o Merge two sorted linked lists
o Detect and remove cycles in a linked list (Floyd’s Cycle Detection Algorithm)
o Flatten a multilevel linked list
 Hashing:
o Hash tables (dict in Python)
o Collision resolution techniques (Chaining, Open addressing)
o Practice problems: Two Sum, Subarray with given sum, Longest Consecutive
Sequence
 Binary Trees:
o Traversals: Preorder, Inorder, Postorder, Level Order
o Binary Search Tree (BST): Insert, Delete, Search
o Advanced problems: Lowest Common Ancestor (LCA), Diameter of a tree,
Balanced Binary Tree
 Heaps:
o Min Heap and Max Heap (using heapq)
o Kth largest/smallest element
o Applications: Merge K sorted arrays, Top K frequent elements
 Tries:
o Trie implementation (prefix trees)
o Applications: Autocomplete, Word Search, Longest prefix matching

Pseudocode
 Pseudocode is a high-level description of an algorithm using a mix of natural language and
programming language constructs.
 It is not meant to be executed by a computer but helps in understanding and designing
algorithms before writing actual code.
 Pseudocode abstracts away specific syntax, focusing on the logic and flow of the
algorithm.
Why Use Pseudocode?
1. Simplicity: It conveys the essence of an algorithm without getting bogged down in
syntax.
2. Portability: Pseudocode can be easily translated into any programming language.
3. Clarity: It helps developers, regardless of their coding language, understand the
approach.
4. Problem-solving: It aids in breaking down complex problems into manageable steps.

Algorithms
Algorithms are step-by-step procedures for solving problems or performing tasks. Best
approach is, it must be as shorter as it can be.
Properties of Algo:
 Input (optional)
 Output (compulsory)
 Definiteness
 Finiteness

Parameters of Analysis:
The analysis of algorithms is the process of finding the computational complexity of the
algorithms.
 Amount of time
 Storage
 Other resources (files, software, hardware) etc.
 Computational complexity of algo must be less

Complexity:
a) Time Complexity:
TC: Time Complexity
TS.O: Simple Operation Time
TK.O: Key Operation Time
TC = TS.O + TK.O
Let’s make TS.O constant (K), Now
TC = K + TK.O
TC  TK.O
Key Operations (K.O):
1. Assignment
2. Loops
3. Nested Loops
4. Conditional
5. Expression Evaluate (Equations etc.)

Scode = Code Space


b) Space Complexity:

Sdata = Data Space


Sc = Scode + Sdata
Let’s make Scode constant (K), Now
Sc = K + Sdata
Sc  Sdata

Example: Let say we have a program here to add two numbers

Ways to Analyze Complexity:


1. Experimental Study (Practical Aspect)
This involves measuring the actual running time and memory usage of an algorithm by
executing it on different input sizes.
Steps:
 Implement the algorithm.
 Run it on various input sizes.
 Record the running time and memory usage.
 Plot the results (e.g., time vs. input size graph).
Pros:
 Easy to understand and visualize.
 Provides real-world performance data.
Cons:
 Depends on hardware and compiler optimizations.
 Does not provide theoretical guarantees for large inputs.

a) Time Complexity:
from time import time
start_time=time()
PROGRAM
end_time()
duration_time=end_time-start_time
Example:
# Sum of n numbers
from time import time
# Function
def sumofN(n):
total = 0
for i in range(1, n + 1):
total = total + i
return total
# Program
start_time = time()
X = sumofN(100000)
end_time = time()
duration_time = end_time - start_time
print("Sum:", X)
print("Duration:", duration_time, "seconds")

b) Space Complexity:
from tracemalloc as tm
tm.start()
PROGRAM
current, peak = tm.get_traced_memory() # will give peak & current memory
tm.stop()
Example
# Sum of n numbers with memory tracking
import tracemalloc as tm
# Function
def sumofN(n):
total = 0
for i in range(1, n + 1):
total = total + i
return total
# Start memory tracking
tm.start()
X = sumofN(100000)
current, peak = tm.get_traced_memory() # will give peak & current memory
tm.stop()
# Output results
print("Sum:", X)
print("Current memory usage:", current / 1024, "KB") # divide to get in Kilobyte
print("Peak memory usage:", peak / 1024, "KB")

2. Functional Study (Theoretical Aspect)


Understanding how the algorithm behaves by examining its input, output, operations, and
transformations at each step. This type of analysis helps in determining both the
correctness and efficiency of the algorithm without immediately delving into time and
space complexity.
Steps:
1. Understanding the Problem
 Clearly define the problem the algorithm is trying to solve.
 Identify the type and constraints of the input and the desired form of the output.
2. Input Description
 Specify the type and size of the input the algorithm takes.
 Example: For a sorting algorithm, the input might be a list of n integers.
3. Functional Flow Analysis
 Break down the algorithm into logical steps or stages.
 Identify key operations performed on the input at each step.
 Example: In a sorting algorithm, typical operations include comparisons, swaps,
or merges.
4. Output Description
 Describe the output produced by the algorithm and its relationship to the input.
 Ensure that the output meets the problem’s requirements (e.g., sorted order,
correct sum).
5. Behavioral Analysis
 Analyze how the algorithm behaves under different input conditions:
 Best case: The simplest scenario where the algorithm performs minimal
work.
 Worst case: The most complex scenario requiring maximum effort.
 Average case: The expected behavior for a typical input.
6. Correctness Verification
 Ensure that the algorithm correctly solves the problem for all possible inputs.
 Use formal or informal proofs (e.g., induction, invariants) to validate correctness.
 Example: In a sorting algorithm, prove that the final array is in non-decreasing
order.
7. Identify Functional Subunits (if applicable)
 If the algorithm is complex, identify sub-algorithms or helper functions.
 Study the input-output behavior of each subunit independently.

a) Time Complexity: (through functional analysis)


 We’ll give,
 Single operation---cost=1
 Repetition operation---cost=n
Program Single Reptati Reason
Cost on
def sumofN(n):
total = 0 1 1 We have single op so
for i in range(1, 1+1 n+1 cost=1
n + 1): 1+1 n Rep+single op, cost=n+1
total = total + 1 1 Rep op, cost=n
i Single op, cost=1
return total Total: f(n)=2n+3

def sumofN(n):
return (n*(n+1))/2 1+1+1+1 Single ops
Total: f(n)= 4
 So;
 Program01: f(n)=2n+2  n | time
 Program02: f(n)= 4  as we increase ‘n’ time remains more stable.

b) Space Complexity: (through functional analysis)


 Consider only data, not code.
 Every Integer in memory store in:
C/C++:2/4bytes 1byte=8bits
Java:4bytes
Python:28bytes
Program Space
def sumofN(n): We have 2 data’s here:
sum = 0 sum, i
for i in range(1, sum=28bytes
n + 1): i=28bytes
sum = sum + i so,
return sum Total:28+28=56

f(n)=56
let’s assume;
f(n)=C
def sumofN(n): N=28byts
return (n*(n+1))/2 So,
total=28

f(n)=28
let’s assume;
f(n)=C

Order of Growth:
Asymptotic Analysis in Algorithms:
Asymptotic analysis is a method to describe the behavior of an algorithm as the
input size grows. It provides a high-level understanding of an algorithm’s efficiency in
terms of time complexity and space complexity, ignoring constant factors and
lower-order terms. This allows us to focus on the dominant factors that impact the
algorithm's performance for large inputs.

Key Concepts
1. Input Size (n)
o The size of the input data affects the performance of an algorithm. It can
be measured in various ways, depending on the problem:
 Number of elements in an array
 Length of a string
 Number of vertices and edges in a graph
2. Growth Rate
o The rate at which the resource consumption (time or space) increases as
the input size grows.
o Asymptotic analysis focuses on the dominant term of a function because,
for large inputs, this term has the greatest impact.
Let’s say we have the function of two Algo’s/Programs:

Algo01: 100n+1

Algo02: n2+n+1

So, in order of growth: is increasing number of inputs (n)

We had the function of two Algo’s:

Instead of taking whole function f(n), we can take highest order ‘n’ for analysis.

Now, how to represent properly:


Order of growth is represented with big ‘O’, like O(n) or O(n 2) etc.
Asymptotic Analysis and Notation Analysis
Asymptotic analysis is a method to describe the behavior of an algorithm as the input size
grows. It provides a high-level understanding of an algorithm’s efficiency in terms of time
complexity and space complexity, ignoring constant factors and lower-order terms. This
allows us to focus on the dominant factors that impact the algorithm's performance for large
inputs.

Key Concepts

1. Input Size (n)

o The size of the input data affects the performance of an algorithm. It can be
measured in various ways, depending on the problem:

 Number of elements in an array

 Length of a string

 Number of vertices and edges in a graph

2. Growth Rate

o The rate at which the resource consumption (time or space) increases as the
input size grows.

o Asymptotic analysis focuses on the dominant term of a function because, for


large inputs, this term has the greatest impact.

Is Asymptotic
Analysis best?
NO
Less Accuracy

How Asymptotic Analysis is less accurate?


Let’s say we have the functions of an algo:
Here, when we apply Asymptotic Analysis on these two functions, the answer will
be same for these two different functions.

Asymptotic Notations

We mostly do Big-
O (Worst Case)
Asymptotic
Analysis

Common Asymptotic Notations


1. Big-O Notation (O(f(n))) -------------Worst Case
Calculating Big-O:
Let’s say we have function of an algo: f(n)=n 2+2n+1
What is g(n) in c.g(n)
g(n) is the output of Asymptotic Notations which is n 2 in case of f(n)= n2+2n+1

So, the valve of ‘c’ should be greater than or equal to 4.


Let’s initially take;

So, the Big-O of f(n) is:

2. Omega Notation (Ω(f(n)))--------------------Best Case


Calculating Omega(Ω):
Let’s say we have function of an algo: f(n)=n 2+2n+1
What is g(n) in c.g(n)
g(n) is the output of Asymptotic Notations which is n 2 in case of f(n)= n2+2n+1
|
|
|
After calculations, we got:
4 ≥c

3. Theta Notation (Θ(f(n)))-----------------------Avg Case

Types of Time Complexity (Asymptotic Behavior)


Types of Time Complexity and Their Practical Impact
Why Use Asymptotic Analysis?
1. Platform Independence
o It abstracts away hardware and system-specific details, focusing only on the
inherent efficiency of the algorithm.
2. Scalability
o Asymptotic analysis helps understand how an algorithm scales with larger input
sizes.
3. Comparison of Algorithms
o It provides a standard way to compare algorithms in terms of their time and
space complexity.
Time-Space Tradeoff or Space-Time Tradeoff:

a) Sorting Algorithms
1. Bubble Sort – Repeatedly swaps adjacent elements if they are in the wrong order.
2. Selection Sort – Selects the smallest element and places it in the correct position.
3. Insertion Sort – Builds the sorted array one item at a time.
4. Merge Sort – Divides the array into halves, sorts, and merges them.
5. Quick Sort – Picks a pivot and partitions the array around the pivot.
b) Searching Algorithms
1. Linear Search – Sequentially checks each element.
2. Binary Search – Works on sorted arrays by repeatedly dividing the search interval in
half.
c) Graph Algorithms
1. Breadth-First Search (BFS) – Explores all neighbors before moving to the next level.
2. Depth-First Search (DFS) – Explores as far as possible along a branch before
backtracking.
3. Dijkstra’s Algorithm – Finds the shortest path in a weighted graph.
4. Kruskal’s & Prim’s Algorithms – Used for finding the Minimum Spanning Tree (MST).
d) Dynamic Programming
A method for solving complex problems by breaking them into smaller subproblems and
storing solutions to avoid redundant computations.
 Example problems: Fibonacci sequence, Longest Common Subsequence (LCS),
Knapsack problem.

Data Structures and Algorithms (DSA) Roadmap

Complete Advanced DSA Roadmap with Python

1. Pre-requisites: Building the Foundation


Before diving into advanced DSA topics, ensure you have a good understanding of basic
concepts.
 Python Basics:
o Data types, Loops, Conditionals
o Functions, Recursion
o List, Dictionary, Set, Tuple
o Comprehensions, Lambda functions
 Basic Data Structures:
o Arrays, Strings
o Stacks, Queues (using collections.deque)
o Linked Lists (Singly, Doubly, Circular)
 Problem-Solving Practice:
Solve 50–100 problems on basic data structures from platforms like LeetCode, HackerRank,
or Codeforces.

2. Core Data Structures


 Advanced Linked Lists:
o Merge two sorted linked lists
o Detect and remove cycles in a linked list (Floyd’s Cycle Detection Algorithm)
o Flatten a multilevel linked list
 Hashing:
o Hash tables (dict in Python)
o Collision resolution techniques (Chaining, Open addressing)
o Practice problems: Two Sum, Subarray with given sum, Longest Consecutive
Sequence
 Binary Trees:
o Traversals: Preorder, Inorder, Postorder, Level Order
o Binary Search Tree (BST): Insert, Delete, Search
o Advanced problems: Lowest Common Ancestor (LCA), Diameter of a tree,
Balanced Binary Tree
 Heaps:
o Min Heap and Max Heap (using heapq)
o Kth largest/smallest element
o Applications: Merge K sorted arrays, Top K frequent elements
 Tries:
o Trie implementation (prefix trees)
o Applications: Autocomplete, Word Search, Longest prefix matching

3. Core Algorithms
 Sorting Algorithms:
o Quick Sort, Merge Sort, Heap Sort
o Counting Sort, Radix Sort
 Searching Algorithms:
o Binary Search and its applications (Search in a rotated sorted array, Median of
two sorted arrays)
 Divide and Conquer:
o Matrix Multiplication using Divide and Conquer
o Closest pair of points problem
 Recursion and Backtracking:
o Subset Sum, Permutations, Combinations
o N-Queens Problem, Sudoku Solver
o Generate all valid parentheses
 Dynamic Programming (DP):
o Types of DP problems:
1. 1D DP: Fibonacci, Climbing Stairs, House Robber
2. 2D DP: Longest Common Subsequence (LCS), Longest Palindromic Substring
3. Knapsack Variations: 0/1 Knapsack, Unbounded Knapsack, Rod Cutting
4. DP on Trees: Diameter of a tree, Maximum path sum
5. DP on Graphs: Shortest path in a grid, Unique paths

4. Graph Theory
 Graph Representation:
o Adjacency List and Adjacency Matrix
o Weighted and Unweighted Graphs
 Graph Traversal:
o Breadth-First Search (BFS)
o Depth-First Search (DFS)
 Topological Sorting:
o Kahn’s Algorithm (BFS approach)
o DFS-based Topological Sorting
 Shortest Path Algorithms:
o Dijkstra’s Algorithm (Using priority queue)
o Bellman-Ford Algorithm
o Floyd-Warshall Algorithm
 Minimum Spanning Tree (MST):
o Prim’s Algorithm
o Kruskal’s Algorithm
 Advanced Graph Algorithms:
o Tarjan’s Algorithm (Strongly Connected Components)
o Kosaraju’s Algorithm (SCC)
o Bridges and Articulation Points in a graph

5. Advanced Topics
 Bit Manipulation:
o Basic operations: AND, OR, XOR, NOT
o Applications: Check if a number is a power of 2, Count set bits
o Advanced problems: Subsets using bitmasking, Find the missing number
 Segment Trees:
o Range Queries (Sum, Min, Max)
o Lazy Propagation
 Fenwick Tree (Binary Indexed Tree):
o Point update and range query
o Applications: Range Sum Queries, Inversion Count
 Disjoint Set Union (DSU):
o Union by rank, Path compression
o Applications: Cycle detection in an undirected graph, Kruskal’s Algorithm
 String Algorithms:
o KMP Algorithm (Pattern Matching)
o Rabin-Karp Algorithm
o Z-Algorithm
o Suffix Arrays and LCP

6. Competitive Programming Practice


 Start participating in contests on platforms like:
o Codeforces
o AtCoder
o LeetCode Weekly Contest
o HackerRank and CodeChef
 Solve problems by difficulty levels:
o Easy → Medium → Hard
o Focus on solving problems from different categories (DP, Graphs, Strings, etc.)

7. Additional Resources
 Books:
o Introduction to Algorithms by Cormen (CLRS)
o The Algorithm Design Manual by Steven S. Skiena
 Online Courses:
o Data Structures and Algorithms Specialization – Coursera
o Algorithmic Toolbox – Coursera
o MIT OpenCourseWare – Introduction to Algorithms

8. Python Libraries for DSA


 collections: deque, Counter, defaultdict
 heapq: For implementing heaps
 bisect: Binary search utilities
 itertools: Permutations, combinations, Cartesian products
 functools: lru_cache for memoization
 math: gcd, lcm, factorial, etc.

9. Building DSA Projects


1. Pathfinding Visualizer: Implement BFS, DFS, A* algorithms
2. Autocomplete System: Using Tries
3. Social Network Graph Analysis: Using Graph algorithms
4. Memory-efficient Text Search: Using Suffix Trees and KMP
5. Custom Heap Implementation: Build your own Min/Max heap

You might also like