PYTHON PROGRAMMING NOTES: BEGINNER TO ADVANCED
==============================================
COMPREHENSIVE TABLE OF CONTENTS
================================
SECTION 1: GETTING STARTED WITH PYTHON
1.1 What is Python?
1.2 Your First Program
1.3 Comments in Python
1.4 Running Python Code
SECTION 2: BASIC DATA TYPES
2.1 Understanding Data Types
2.2 Integer (int)
2.3 Float (float)
2.4 String (str)
2.5 Boolean (bool)
2.6 None
2.7 Type Conversion
SECTION 3: VARIABLES AND OPERATIONS
3.1 Creating Variables
3.2 Arithmetic Operations
3.3 Assignment Operations
3.4 Comparison Operations
3.5 Logical Operations
3.6 Input from User
SECTION 4: CONTROL FLOW STATEMENTS
4.1 If Statement
4.2 If-Else Statement
4.3 If-Elif-Else Statement
4.4 Ternary Operator
4.5 While Loop
4.6 For Loop
4.7 Range Function
4.8 Break Statement
4.9 Continue Statement
4.10 Nested Loops
SECTION 5: FUNCTIONS
5.1 Creating Functions
5.2 Functions with Parameters
5.3 Functions with Multiple Parameters
5.4 Default Parameters
5.5 Return Statement
5.6 Returning Multiple Values
5.7 Variable-Length Arguments (*args)
5.8 Keyword Arguments (**kwargs)
5.9 Scope of Variables
5.10 Lambda Functions (Anonymous Functions)
5.11 Map Function
5.12 Filter Function
5.13 Reduce Function
SECTION 6: DATA STRUCTURES
6.1 List
6.1.1 Accessing elements
6.1.2 List Operations
6.1.3 List Slicing
6.1.4 List Comprehension
6.2 Tuple
6.2.1 Accessing elements
6.2.2 Tuple operations
6.2.3 Unpacking
6.3 Set
6.3.1 Creating sets
6.3.2 Adding and Removing elements
6.3.3 Set operations
6.4 Dictionary
6.4.1 Creating dictionaries
6.4.2 Accessing values
6.4.3 Modifying and Adding
6.4.4 Removing pairs
6.4.5 Checking and Iterating
6.4.6 Dictionary Comprehension
6.5 Nested Data Structures
SECTION 7: STRING MANIPULATION
7.1 Creating Strings
7.2 String Concatenation
7.3 String Repetition
7.4 String Formatting
7.4.1 Using f-strings
7.4.2 Using format method
7.5 String Methods
7.5.1 Converting case
7.5.2 Removing whitespace
7.5.3 Replacing characters
7.5.4 Finding substrings
7.5.5 Splitting and Joining
7.5.6 Checking string properties
7.6 String Slicing
SECTION 8: OBJECT-ORIENTED PROGRAMMING
8.1 Classes and Objects
8.2 Attributes and Methods
8.3 Constructor (__init__)
8.4 Class Variables vs Instance Variables
8.5 Inheritance
8.6 Polymorphism
8.7 Encapsulation
8.8 Static Methods
8.9 Class Methods
SECTION 9: FILE HANDLING
9.1 Reading Files
9.1.1 Reading entire file
9.1.2 Reading line by line
9.1.3 Reading all lines
9.2 Writing Files
9.2.1 Writing (overwrites)
9.2.2 Appending (adds to end)
9.3 File Modes
9.4 Working with CSV Files
9.4.1 Reading CSV
9.4.2 Writing CSV
9.5 Working with JSON Files
9.5.1 Reading JSON
9.5.2 Writing JSON
9.6 File Path Operations
SECTION 10: EXCEPTION HANDLING
10.1 Try-Except Block
10.2 Multiple Exception Types
10.3 Else Clause
10.4 Finally Clause
10.5 Raising Exceptions
10.6 Common Exceptions
SECTION 11: ADVANCED CONCEPTS
11.1 Decorators
11.2 Generators
11.3 List Comprehensions (Review)
11.4 Dictionary Comprehensions
11.5 Set Comprehensions
11.6 Modules and Packages
11.6.1 Importing modules
11.6.2 Commonly Used Modules
11.7 Sorting
11.8 Enumerate
11.9 Zip
SECTION 12: ALGORITHMS AND PROBLEM-SOLVING
12.1 Linear Search
12.2 Binary Search
12.3 Sorting Algorithms
12.3.1 Bubble Sort
12.3.2 Selection Sort
12.3.3 Quick Sort
12.3.4 Merge Sort
12.4 Two Pointer Technique
12.5 Sliding Window
12.6 Depth-First Search (DFS)
12.7 Breadth-First Search (BFS)
12.8 Recursion
12.9 Dynamic Programming
12.10 Greedy Algorithm
SECTION 13: LEETCODE TIPS AND TRICKS
13.1 Common Interview Patterns
13.1.1 Two Pointer Technique
13.1.2 Hash Map (Dictionary)
13.1.3 Sliding Window
13.1.4 Stack
13.1.5 Queue
13.1.6 Binary Search
13.1.7 DFS and BFS
13.1.8 Dynamic Programming
13.2 Problem-Solving Approach
13.2.1 Step 1: Understand the Problem
13.2.2 Step 2: Identify the Pattern
13.2.3 Step 3: Think of Brute Force
13.2.4 Step 4: Optimize
13.2.5 Step 5: Code
13.2.6 Step 6: Test
13.3 Important Data Structures for Interviews
13.3.1 Array/List
13.3.2 Dictionary/Hash Map
13.3.3 Set
13.3.4 Stack
13.3.5 Queue
13.3.6 Tree
13.3.7 Graph
13.4 Quick Reference for LeetCode
13.4.1 Reversing strings and lists
13.4.2 Checking palindromes
13.4.3 Converting between types
13.4.4 Finding min/max
13.4.5 Sorting
13.4.6 Removing duplicates
13.4.7 Counting occurrences
13.4.8 String operations
13.5 Time and Space Complexity Tips
13.5.1 Complexity Classes
13.5.2 General Rules
13.6 Debugging Strategies
13.6.1 Print debugging
13.6.2 Edge cases to test
13.6.3 Testing approach
13.7 Code Quality Tips
13.8 Common Mistakes to Avoid
13.9 Final Tips
SECTION 1: GETTING STARTED WITH PYTHON
======================================
What is Python?
Python is a simple, readable, and powerful programming language used for web development, data
science, automation, and problem-solving.
Your First Program
```
print("Hello, World!")
```
Comments in Python
```
# This is a single line comment
"""
This is a multi-line comment
used for longer explanations
"""
```
Running Python Code
- Save your code in a file with .py extension
- Open terminal and run: python [Link]
- Or use Python interactive shell by typing: python
SECTION 2: BASIC DATA TYPES
===========================
Understanding Data Types
Data types define what kind of data a variable can store. Python has several basic types.
Integer (int)
- Whole numbers without decimal points
- Example: 5, -10, 0, 1000
```
num = 42
print(type(num)) # Output: <class 'int'>
```
Float (float)
- Numbers with decimal points
- Example: 3.14, -2.5, 0.0
```
price = 9.99
print(type(price)) # Output: <class 'float'>
```
String (str)
- Text enclosed in single or double quotes
- Example: "Hello", 'Python', "123"
```
name = "Alice"
message = 'Welcome'
combined = "Hello" + " " + "World"
```
Boolean (bool)
- Only two values: True or False
- Used for conditions and logic
```
is_active = True
is_empty = False
```
None
- Represents absence of value or null
```
result = None
```
Type Conversion
```
num_string = "123"
num_int = int(num_string) # Convert string to integer
num_float = float(num_string) # Convert to float
num_back_to_string = str(num_int) # Convert back to string
```
SECTION 3: VARIABLES AND OPERATIONS
===================================
Creating Variables
- Variable names should be descriptive
- Start with letter or underscore, not number
- Use lowercase with underscores (snake_case)
```
age = 25
first_name = "John"
_private_variable = 100
count = 0
```
Arithmetic Operations
```
a = 10
b=3
addition = a + b # 13
subtraction = a - b #7
multiplication = a * b # 30
division = a / b # 3.333...
floor_division = a // b # 3 (rounds down)
modulo = a % b # 1 (remainder)
exponent = a ** b # 1000 (a to power b)
```
Assignment Operations
```
x=5
x += 3 # x = x + 3, result: 8
x -= 2 # x = x - 2, result: 6
x *= 2 # x = x * 2, result: 12
x /= 3 # x = x / 3, result: 4.0
```
Comparison Operations
```
a=5
b = 10
equal = a == b # False (is equal to)
not_equal = a != b # True (is not equal to)
less_than = a < b # True
greater_than = a > b # False
less_or_equal = a <= b # True
greater_or_equal = a >= b # False
```
Logical Operations
```
condition1 = True
condition2 = False
result1 = condition1 and condition2 # False (both must be true)
result2 = condition1 or condition2 # True (at least one is true)
result3 = not condition1 # False (inverts boolean)
```
Input from User
```
name = input("Enter your name: ")
age = int(input("Enter your age: "))
```
SECTION 4: CONTROL FLOW STATEMENTS
==================================
If Statement
```
age = 18
if age >= 18:
print("You are an adult")
```
If-Else Statement
```
age = 15
if age >= 18:
print("You are an adult")
else:
print("You are a minor")
```
If-Elif-Else Statement
```
score = 75
if score >= 90:
print("Grade A")
elif score >= 80:
print("Grade B")
elif score >= 70:
print("Grade C")
else:
print("Grade F")
```
Ternary Operator (Conditional Expression)
```
age = 20
status = "Adult" if age >= 18 else "Minor"
print(status) # Output: Adult
```
While Loop
Repeats code while condition is True
```
count = 1
while count <= 5:
print(count)
count += 1
# Output: 1 2 3 4 5
```
For Loop
Repeats code for each item in a sequence
```
for i in range(5):
print(i)
# Output: 0 1 2 3 4
for letter in "Python":
print(letter)
# Output: P y t h o n
```
Range Function
```
range(5) # 0, 1, 2, 3, 4
range(2, 8) # 2, 3, 4, 5, 6, 7
range(0, 10, 2) # 0, 2, 4, 6, 8 (step of 2)
```
Break Statement
Exits the loop immediately
```
for i in range(10):
if i == 5:
break
print(i)
# Output: 0 1 2 3 4
```
Continue Statement
Skips current iteration and goes to next
```
for i in range(5):
if i == 2:
continue
print(i)
# Output: 0 1 3 4
```
Nested Loops
```
for i in range(3):
for j in range(2):
print(f"i={i}, j={j}")
```
SECTION 5: FUNCTIONS
===================
Creating Functions
```
def greet():
print("Hello, World!")
greet() # Calling the function
```
Functions with Parameters
```
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # Output: Hello, Alice!
```
Functions with Multiple Parameters
```
def add(a, b):
return a + b
result = add(5, 3)
print(result) # Output: 8
```
Default Parameters
```
def greet(name="Guest"):
print(f"Hello, {name}!")
greet() # Output: Hello, Guest!
greet("Alice") # Output: Hello, Alice!
```
Return Statement
```
def multiply(a, b):
return a * b
result = multiply(4, 5)
print(result) # Output: 20
```
Returning Multiple Values
```
def get_coordinates():
return 10, 20
x, y = get_coordinates()
print(x, y) # Output: 10 20
```
Variable-Length Arguments (*args)
Used when you don't know how many arguments will be passed
```
def sum_all(*numbers):
total = 0
for num in numbers:
total += num
return total
print(sum_all(1, 2, 3)) # Output: 6
print(sum_all(1, 2, 3, 4, 5)) # Output: 15
```
Keyword Arguments (**kwargs)
Used when you want to pass named arguments
```
def print_info(**info):
for key, value in [Link]():
print(f"{key}: {value}")
print_info(name="Alice", age=25, city="New York")
```
Scope of Variables
```
global_var = 10 # Global scope
def my_function():
local_var = 20 # Local scope (only available inside function)
print(global_var)
print(local_var)
my_function()
```
Lambda Functions (Anonymous Functions)
Short functions without def keyword
```
square = lambda x: x ** 2
print(square(5)) # Output: 25
add = lambda a, b: a + b
print(add(3, 4)) # Output: 7
```
Map Function
Applies function to each item in a list
```
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # Output: [1, 4, 9, 16, 25]
```
Filter Function
Keeps items that satisfy a condition
```
numbers = [1, 2, 3, 4, 5, 6]
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(even_numbers) # Output: [2, 4, 6]
```
Reduce Function
Combines items to produce single result
```
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda a, b: a * b, numbers)
print(product) # Output: 120
```
SECTION 6: DATA STRUCTURES
==========================
List
Ordered, mutable collection of items
```
fruits = ["apple", "banana", "cherry"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "two", 3.0, True]
Creating lists
empty_list = []
list_from_range = list(range(5)) # [0, 1, 2, 3, 4]
Accessing elements
first = fruits[0] # "apple" (first element)
last = fruits[-1] # "cherry" (last element)
```
List Operations
```
fruits = ["apple", "banana"]
Modifying elements
fruits[0] = "orange"
Adding elements
[Link]("cherry") # Add to end
[Link](1, "blueberry") # Add at index
Removing elements
[Link]("apple") # Remove by value
popped = [Link]() # Remove last element and return it
popped = [Link](0) # Remove at index 0
Checking membership
if "apple" in fruits:
print("Found")
Length of list
length = len(fruits)
```
List Slicing
```
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
subset = numbers[2:5] # [2, 3, 4] (index 2 to 4)
from_start = numbers[:3] # [0, 1, 2] (first 3 elements)
to_end = numbers[7:] # [7, 8, 9] (from index 7 to end)
step = numbers[::2] # [0, 2, 4, 6, 8] (every 2nd element)
reverse = numbers[::-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (reversed)
```
List Comprehension
Concise way to create lists
```
squares = [x ** 2 for x in range(5)] # [0, 1, 4, 9, 16]
with condition
even_squares = [x ** 2 for x in range(10) if x % 2 == 0] # [0, 4, 16, 36, 64]
```
Tuple
Ordered, immutable collection (cannot be changed)
```
coordinates = (10, 20)
person = ("Alice", 25, "Engineer")
Accessing elements
x = coordinates[0] # 10
Tuple operations
length = len(person)
if "Alice" in person:
print("Found")
Unpacking
x, y = coordinates
name, age, job = person
```
Set
Unordered, mutable collection with unique elements
```
Creating sets
numbers = {1, 2, 3, 4, 5}
unique_letters = set("hello") # {'h', 'e', 'l', 'o'}
Adding elements
[Link](6)
Removing elements
[Link](5) # No error if not found
[Link](5) # Error if not found
Set operations
set1 = {1, 2, 3}
set2 = {3, 4, 5}
union = set1 | set2 # {1, 2, 3, 4, 5}
intersection = set1 & set2 # {3}
difference = set1 - set2 # {1, 2}
```
Dictionary
Unordered, mutable collection of key-value pairs
```
Creating dictionaries
student = {"name": "Alice", "age": 25, "grade": "A"}
scores = {1: 95, 2: 87, 3: 92}
Accessing values
name = student["name"] # "Alice"
age = [Link]("age") # 25 (safer, returns None if not found)
Modifying values
student["age"] = 26
Adding new key-value pairs
student["city"] = "New York"
Removing key-value pairs
del student["city"]
[Link]("age")
Checking keys
if "name" in student:
print("Found")
Getting all keys, values, items
keys = [Link]() # dict_keys(['name', 'age', 'grade'])
values = [Link]() # dict_values(['Alice', 25, 'A'])
items = [Link]() # dict_items([('name', 'Alice'), ...])
Iterating through dictionary
for key, value in [Link]():
print(f"{key}: {value}")
```
Dictionary Comprehension
```
squares = {x: x ** 2 for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
```
Nested Data Structures
```
person = {
"name": "Alice",
"age": 25,
"hobbies": ["reading", "gaming", "coding"],
"address": {"city": "New York", "zip": "10001"}
}
accessing nested data
hobby = person["hobbies"][0] # "reading"
city = person["address"]["city"] # "New York"
```
SECTION 7: STRING MANIPULATION
=============================
Creating Strings
```
single_quote = 'Hello'
double_quote = "World"
multi_line = """This is
a multi-line
string"""
```
String Concatenation
```
first = "Hello"
second = "World"
combined = first + " " + second # "Hello World"
```
String Repetition
```
word = "Ha"
repeated = word * 3 # "HaHaHa"
```
String Formatting
Using f-strings (modern and recommended)
```
name = "Alice"
age = 25
message = f"My name is {name} and I am {age} years old"
with expressions
price = 19.99
formatted = f"Price: ${price:.2f}" # Price: $19.99
```
Using format method
```
message = "Hello, {}!".format("World")
message = "I have {} apples and {} oranges".format(5, 3)
```
String Methods
```
text = " Hello World "
Converting case
upper = [Link]() # " HELLO WORLD "
lower = [Link]() # " hello world "
title_case = [Link]() # " Hello World "
Removing whitespace
stripped = [Link]() # "Hello World"
left = [Link]() # "Hello World "
right = [Link]() # " Hello World"
Replacing characters
replaced = [Link]("World", "Python") # " Hello Python "
Finding substrings
index = [Link]("World") #8
contains = "World" in text # True
Splitting strings
words = [Link]() # ["Hello", "World"]
parts = "a,b,c".split(",") # ["a", "b", "c"]
Joining strings
joined = "-".join(["a", "b", "c"]) # "a-b-c"
Checking string properties
is_digit = "123".isdigit() # True
is_alpha = "abc".isalpha() # True
is_alphanumeric = "abc123".isalnum() # True
```
String Slicing
```
text = "Python"
first_three = text[:3] # "Pyt"
last_two = text[-2:] # "on"
reversed_text = text[::-1] # "nohtyP"
```
SECTION 8: OBJECT-ORIENTED PROGRAMMING
======================================
Classes and Objects
```
class Dog:
def __init__(self, name, age):
[Link] = name
[Link] = age
def bark(self):
print(f"{[Link]} says Woof!")
Creating object
my_dog = Dog("Buddy", 3)
my_dog.bark() # Output: Buddy says Woof!
```
Attributes and Methods
```
class Car:
def __init__(self, brand, color):
[Link] = brand # Attribute
[Link] = color
def drive(self): # Method
print(f"{[Link]} {[Link]} is driving")
my_car = Car("Toyota", "red")
print(my_car.brand) # red
my_car.drive()
```
Constructor (__init__)
Special method called when creating an object
```
class Person:
def __init__(self, name, age):
[Link] = name
[Link] = age
person = Person("Alice", 30)
```
Class Variables vs Instance Variables
```
class Student:
school = "State University" # Class variable (shared)
def __init__(self, name):
[Link] = name # Instance variable (unique to each object)
student1 = Student("Alice")
student2 = Student("Bob")
print([Link]) # "State University"
print([Link]) # "Alice"
print([Link]) # "Bob"
```
Inheritance
Creating new class from existing class
```
class Animal:
def __init__(self, name):
[Link] = name
def sound(self):
print("Some sound")
class Dog(Animal):
def sound(self):
print(f"{[Link]} says Woof!")
class Cat(Animal):
def sound(self):
print(f"{[Link]} says Meow!")
dog = Dog("Buddy")
[Link]() # Output: Buddy says Woof!
```
Polymorphism
Different objects responding to same method differently
```
animals = [Dog("Buddy"), Cat("Whiskers")]
for animal in animals:
[Link]()
```
Encapsulation
Hiding internal details
```
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private attribute (double underscore)
def get_balance(self):
return self.__balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
account = BankAccount(1000)
print(account.get_balance()) # 1000
[Link](500)
print(account.get_balance()) # 1500
```
Static Methods
Methods that don't need access to instance data
```
class MathHelper:
@staticmethod
def add(a, b):
return a + b
result = [Link](5, 3) # 8
```
Class Methods
Methods that work with class variables
```
class Person:
count = 0
def __init__(self, name):
[Link] = name
[Link] += 1
@classmethod
def get_count(cls):
return [Link]
person1 = Person("Alice")
person2 = Person("Bob")
print(Person.get_count()) # 2
```
SECTION 9: FILE HANDLING
=======================
Reading Files
```
opening and reading entire file
with open("[Link]", "r") as file:
content = [Link]() # Read entire file as string
reading line by line
with open("[Link]", "r") as file:
for line in file:
print([Link]())
reading all lines into list
with open("[Link]", "r") as file:
lines = [Link]()
```
Writing Files
```
writing to file (overwrites if exists)
with open("[Link]", "w") as file:
[Link]("Hello, World!")
appending to file (adds to end)
with open("[Link]", "a") as file:
[Link]("\nNew line")
```
File Modes
r: Read (default)
w: Write (overwrites)
a: Append (adds to end)
x: Exclusive creation (fails if exists)
b: Binary mode (rb, wb, ab)
t: Text mode (default)
Working with CSV Files
```
import csv
Reading CSV
with open("[Link]", "r") as file:
csv_reader = [Link](file)
for row in csv_reader:
print(row)
Writing CSV
with open("[Link]", "w") as file:
csv_writer = [Link](file)
csv_writer.writerow(["Name", "Age"])
csv_writer.writerow(["Alice", 25])
```
Working with JSON Files
```
import json
Reading JSON
with open("[Link]", "r") as file:
data = [Link](file) # Converts JSON to Python dict
Writing JSON
with open("[Link]", "w") as file:
[Link](data, file)
```
File Path Operations
```
import os
checking if file exists
exists = [Link]("[Link]")
getting file size
size = [Link]("[Link]")
getting current directory
current_dir = [Link]()
creating directory
[Link]("new_folder", exist_ok=True)
```
SECTION 10: EXCEPTION HANDLING
=============================
Try-Except Block
Catches and handles errors
```
try:
num = int("abc")
except ValueError:
print("Cannot convert string to integer")
```
Multiple Exception Types
```
try:
file = open("[Link]")
content = [Link]()
except FileNotFoundError:
print("File not found")
except IOError:
print("IO Error occurred")
```
Else Clause
Runs if no exception occurs
```
try:
num = int("10")
except ValueError:
print("Invalid number")
else:
print(f"Number: {num}")
```
Finally Clause
Always runs regardless of exception
```
try:
file = open("[Link]")
content = [Link]()
except FileNotFoundError:
print("File not found")
finally:
print("Cleanup operations")
```
Raising Exceptions
```
def divide(a, b):
if b == 0:
raise ValueError("Divisor cannot be zero")
return a / b
```
Common Exceptions
ValueError: Invalid value for data type
TypeError: Wrong data type
IndexError: Index out of range
KeyError: Dictionary key not found
FileNotFoundError: File doesn't exist
ZeroDivisionError: Division by zero
AttributeError: Attribute doesn't exist
SECTION 11: ADVANCED CONCEPTS
=============================
Decorators
Function that modifies another function
```
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Output:
Before function call
Hello!
After function call
```
Generators
Functions that yield values one at a time
```
def count_up_to(max):
count = 1
while count <= max:
yield count
count += 1
for num in count_up_to(5):
print(num) # Output: 1 2 3 4 5
```
List Comprehensions (Review)
```
simple comprehension
squares = [x ** 2 for x in range(5)]
with condition
even_numbers = [x for x in range(10) if x % 2 == 0]
nested
pairs = [(x, y) for x in range(3) for y in range(2)]
```
Dictionary Comprehensions
```
squares_dict = {x: x ** 2 for x in range(5)}
```
Set Comprehensions
```
unique_squares = {x ** 2 for x in range(10)}
```
Modules and Packages
Importing modules
```
import math
result = [Link](16) # 4.0
from math import sqrt
result = sqrt(16)
import math as m
result = [Link](16)
```
Commonly Used Modules
```
math: Mathematical functions
import math
[Link](16)
[Link](3.2)
[Link](3.8)
random: Generate random numbers
import random
[Link](1, 10)
[Link]([1, 2, 3])
[Link](list)
datetime: Date and time
import datetime
today = [Link]()
now = [Link]()
collections: Specialized data structures
from collections import Counter
counts = Counter("hello") # Counts each character
```
Sorting
```
sorting lists
numbers = [3, 1, 4, 1, 5]
sorted_asc = sorted(numbers) # [1, 1, 3, 4, 5]
sorted_desc = sorted(numbers, reverse=True) # [5, 4, 3, 1, 1]
sorting with key
words = ["apple", "pie", "a"]
sorted_by_length = sorted(words, key=len) # ['a', 'pie', 'apple']
sorting dictionaries
students = [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 20}]
sorted_by_age = sorted(students, key=lambda x: x["age"])
```
Enumerate
Get index and value while iterating
```
fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
Output:
0: apple
1: banana
2: cherry
```
Zip
Combines multiple lists
```
names = ["Alice", "Bob", "Charlie"]
ages = [25, 20, 30]
for name, age in zip(names, ages):
print(f"{name}: {age}")
combined = list(zip(names, ages))
```
SECTION 12: ALGORITHMS AND PROBLEM-SOLVING
==========================================
Linear Search
Finding element by checking each one
```
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
result = linear_search([1, 3, 5, 7, 9], 5) # 2
```
Binary Search
Fast search in sorted array (divide and conquer)
```
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
left = mid + 1
else:
right = mid - 1
return -1
result = binary_search([1, 3, 5, 7, 9], 5) # 2
```
Sorting Algorithms
Bubble Sort
```
def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
return arr
```
Selection Sort
```
def selection_sort(arr):
n = len(arr)
for i in range(n):
min_idx = i
for j in range(i + 1, n):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i]
return arr
```
Quick Sort
```
def quick_sort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quick_sort(left) + middle + quick_sort(right)
```
Merge Sort
```
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i=j=0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
[Link](left[i])
i += 1
else:
[Link](right[j])
j += 1
[Link](left[i:])
[Link](right[j:])
return result
```
Two Pointer Technique
Useful for problems involving pairs or sequences
```
def find_pair_sum(arr, target):
left, right = 0, len(arr) - 1
while left < right:
current_sum = arr[left] + arr[right]
if current_sum == target:
return [arr[left], arr[right]]
elif current_sum < target:
left += 1
else:
right -= 1
return None
```
Sliding Window
Useful for subarray/substring problems
```
def max_sum_subarray(arr, k):
if k > len(arr):
return None
window_sum = sum(arr[:k])
max_sum = window_sum
for i in range(k, len(arr)):
window_sum = window_sum - arr[i - k] + arr[i]
max_sum = max(max_sum, window_sum)
return max_sum
```
Depth-First Search (DFS)
```
def dfs(graph, node, visited=None):
if visited is None:
visited = set()
[Link](node)
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
dfs(graph, neighbor, visited)
graph = {
'A': ['B', 'C'],
'B': ['A', 'D'],
'C': ['A', 'E'],
'D': ['B'],
'E': ['C']
}
dfs(graph, 'A')
```
Breadth-First Search (BFS)
```
from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
[Link](start)
while queue:
node = [Link]()
print(node)
for neighbor in graph[node]:
if neighbor not in visited:
[Link](neighbor)
[Link](neighbor)
bfs(graph, 'A')
```
Recursion
Function calling itself
```
def factorial(n):
if n == 0 or n == 1:
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(6)) # 8
```
Dynamic Programming
Solving overlapping subproblems efficiently
```
fibonacci with memoization
def fib(n, memo={}):
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fib(n - 1, memo) + fib(n - 2, memo)
return memo[n]
```
Greedy Algorithm
Making locally optimal choice at each step
```
def coin_change(coins, amount):
[Link](reverse=True)
count = 0
for coin in coins:
count += amount // coin
amount %= coin
return count
```
SECTION 13: LEETCODE TIPS AND TRICKS
====================================
Common Interview Patterns
1. Two Pointer Technique
Used for: Finding pairs, removing elements, sorted arrays
Pattern:
```
left, right = 0, len(arr) - 1
while left < right:
# Process and move pointers
```
2. Hash Map (Dictionary)
Used for: Counting, mapping relationships, quick lookup
```
char_count = {}
for char in string:
char_count[char] = char_count.get(char, 0) + 1
```
3. Sliding Window
Used for: Subarray/substring problems, max/min in window
```
for i in range(k, len(arr)):
window_sum = window_sum - arr[i - k] + arr[i]
```
4. Stack
Used for: Parenthesis matching, undo operations, next greater element
```
stack = []
[Link](item)
top = [Link]()
```
5. Queue
Used for: BFS, level-order traversal, scheduling
```
from collections import deque
queue = deque()
[Link](item)
item = [Link]()
```
6. Binary Search
Used for: Sorted arrays, finding insertion position, peak element
Always remember: O(log n) time complexity
7. DFS and BFS
Used for: Tree and graph traversal, connected components
DFS uses stack (recursion or explicit)
BFS uses queue
8. Dynamic Programming
Recognize when: Problem has overlapping subproblems
Solution: Store results to avoid recalculation
Problem-Solving Approach
Step 1: Understand the Problem
Read carefully, identify inputs and outputs
Ask yourself: What is given? What to find?
Step 2: Identify the Pattern
Is this a problem about arrays, strings, trees, graphs?
Have you seen similar problems?
Step 3: Think of Brute Force
Start simple, even if inefficient
Helps you understand the problem
Step 4: Optimize
Can you use a data structure?
Can you reduce time or space complexity?
Step 5: Code
Write clean, readable code
Handle edge cases
Step 6: Test
Test with provided examples
Test edge cases (empty, single element, large numbers)
Important Data Structures for Interviews
Array/List
Time: Access O(1), Search O(n), Insert O(n), Delete O(n)
Use when: Ordered data, need random access
Dictionary/Hash Map
Time: Access O(1), Search O(1), Insert O(1), Delete O(1) on average
Use when: Need fast lookup, mapping
Set
Time: All operations O(1) on average
Use when: Unique elements, membership checking
Stack
Time: Push O(1), Pop O(1), Peek O(1)
Use when: LIFO (Last In First Out)
Queue
Time: Enqueue O(1), Dequeue O(1)
Use when: FIFO (First In First Out)
Tree
Time: Balanced operations O(log n)
Use when: Hierarchical data
Graph
Time: Depends on traversal (DFS/BFS O(V + E))
Use when: Connected nodes, relationships
Quick Reference for LeetCode
Reversing a string or list
reversed_str = string[::-1]
reversed_list = list[::-1]
Checking if palindrome
is_palindrome = string == string[::-1]
Converting between types
list_to_string = "".join(list)
string_to_list = list(string)
string_to_int = int(string)
Finding min/max
min_val = min(arr)
max_val = max(arr)
Sorting
sorted_arr = sorted(arr)
sorted_desc = sorted(arr, reverse=True)
Removing duplicates
unique = list(set(arr))
Counting occurrences
from collections import Counter
counts = Counter(arr)
String operations
substring in string -> "sub" in "substring"
replace -> [Link](old, new)
split -> [Link](delimiter)
join -> [Link](list)
Time and Space Complexity Tips
O(1): Constant - fastest, best case
O(log n): Logarithmic - very good, binary search
O(n): Linear - acceptable, loops
O(n log n): Linearithmic - good for sorting
O(n^2): Quadratic - slower, nested loops
O(n^3): Cubic - very slow
O(2^n): Exponential - extremely slow
O(n!): Factorial - extremely slow
General Rules
Minimize nested loops
Use hash maps for O(1) lookups instead of O(n) search
Use sorting wisely (O(n log n) is usually acceptable)
Consider space-time tradeoffs
Debugging Strategies
Print debugging
Add print statements at key points
Check variable values
Edge cases to test
Empty input
Single element
Large numbers
Negative numbers
Duplicate values
All same values
Testing approach
Try given examples first
Test edge cases
Test common wrong answers
Code Quality Tips
Use meaningful variable names
Keep functions focused and short
Add comments for complex logic
Handle all edge cases
Avoid unnecessary complexity
Common Mistakes to Avoid
Off-by-one errors in loops
Not checking array bounds
Modifying list while iterating
Not initializing variables
Integer overflow (less relevant in Python)
Not handling empty input
Assuming input format (sort order, duplicates)
Final Tips
Practice regularly
Start with easy problems, move to medium, then hard
Understand solutions, don't just memorize
Learn from every problem
Review and refactor your code
Time yourself to improve speed
Remember: LeetCode is about problem-solving patterns, not memorization. Focus on understanding
the approach, and you will be able to solve many similar problems.
END OF NOTES
============
These notes cover Python from basics to advanced topics with focus on LeetCode preparation. Study
each section systematically, practice the code examples, and you will be well-prepared for coding
interviews and competitive programming challenges.