Basic Python Tips
Fast I/O operations are crucial for competitive programming.
# Fast Input
from sys import stdin, stdout
input = stdin.readline # Faster input
print = stdout.write # Faster output
# Multiple inputs on one line
a, b = map(int, input().split())
# List input on one line
arr = list(map(int, input().split()))
# Multiple lines input
n = int(input())
matrix = [list(map(int, input().split())) for _ in range(n)]
# Output formatting
print(f"{answer}\n") # Don't forget \n when using stdout.write
Python One-Liners
Common Python one-liners that are frequently used in coding interviews.
# List comprehension
squares = [x*x for x in range(10)]
matrix = [[0]*m for _ in range(n)] # n×m matrix
# Conditional comprehension
evens = [x for x in range(10) if x % 2 == 0]
# Generate combinations
from itertools import combinations
combs = list(combinations([1,2,3], 2)) # [(1,2), (1,3), (2,3)]
# Generate permutations
from itertools import permutations
perms = list(permutations([1,2,3]))
# Flatten 2D list
flattened = [item for sublist in matrix for item in sublist]
# Count elements
from collections import Counter
counts = Counter([1,1,2,3,3,3]) # Counter({3:3, 1:2, 2:1})
Data Structures
Lists (Arrays)
Lists are the most commonly used data structure in Python.
# Basic operations
arr = []
arr.append(x) # Add to end: O(1)
arr.pop() # Remove from end: O(1)
arr.insert(i, x) # Insert at index i: O(n)
arr.remove(x) # Remove first occurrence: O(n)
del arr[i] # Delete at index: O(n)
# Useful methods
arr.sort() # In-place sort
arr.sort(reverse=True) # Descending sort
arr.sort(key=lambda x: x[1]) # Sort by custom key
sorted_arr = sorted(arr) # Return new sorted list
arr.reverse() # Reverse in-place
reversed_arr = arr[::-1] # Return new reversed list
# Slicing [start:end:step]
arr[2:5] # Elements from index 2 to 4
arr[::-1] # Reverse array
arr[::2] # Every second element
Using Lists as Queues
For efficient queue operations, use collections.deque.
from collections import deque
queue = deque([1, 2, 3])
queue.append(4) # Add to right
queue.appendleft(0) # Add to left
queue.pop() # Remove from right
queue.popleft() # Remove from left
Dictionaries (Hash Maps)
Dictionaries provide O(1) average case operations.
# Creation
d = {}
d = dict()
d = {key: value for key, value in zip(keys, values)}
# Default dictionary
from collections import defaultdict
d = defaultdict(int) # Default value 0
d = defaultdict(list) # Default value []
d = defaultdict(set) # Default value set()
# Counter
from collections import Counter
c = Counter([1,1,2,3,3,3])
c.most_common(2) # Two most common elements
c.update([1,2,3]) # Add more elements
# Operations
d[key] = value
value = d.get(key, default) # Returns default if key not found
d.setdefault(key, default) # Set default if key not found
d.pop(key, default) # Remove and return, optional default
d.update(other_dict) # Merge dictionaries
# Iteration
for key in d: # Iterate keys
for key, value in d.items(): # Iterate key-value pairs
for value in d.values(): # Iterate values
Sets
Sets are useful for maintaining unique elements and set operations.
# Creation
s = set()
s = {1, 2, 3}
s = set([1, 2, 3])
# Operations
s.add(x) # Add element
s.remove(x) # Remove element (raises KeyError if not found)
s.discard(x) # Remove element (no error if not found)
s.pop() # Remove and return arbitrary element
# Set operations
a | b # Union
a & b # Intersection
a - b # Difference
a ^ b # Symmetric difference
a <= b # Subset
a < b # Proper subset
Heaps (Priority Queues)
Python’s heapq implements a min-heap.
import heapq
# Min heap
heap = []
heapq.heappush(heap, 1) # Add element
min_val = heapq.heappop(heap) # Remove and return smallest
min_val = heap[0] # Peek at smallest
# Max heap (negate values)
heap = []
heapq.heappush(heap, -1) # Add element
max_val = -heapq.heappop(heap) # Remove and return largest
# Heapify list
arr = [3, 1, 4, 1, 5]
heapq.heapify(arr) # Convert to min heap in-place
# k largest elements
k_largest = heapq.nlargest(k, arr)
# k smallest elements
k_smallest = heapq.nsmallest(k, arr)
Algorithms
Binary Search
Binary search is a fundamental algorithm for searching in sorted arrays.
# Basic binary search
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
# Binary search on answer (FFFTTT pattern)
def binary_search_answer(low, high, condition):
while low < high:
mid = (low + high) // 2
if condition(mid):
high = mid
else:
low = mid + 1
return low
Graph Algorithms
Essential graph traversal and shortest path algorithms.
# DFS
def dfs(graph, start, visited=None):
if visited is None:
visited = set()
visited.add(start)
for next_node in graph[start]:
if next_node not in visited:
dfs(graph, next_node, visited)
# BFS
from collections import deque
def bfs(graph, start):
visited = {start}
queue = deque([start])
while queue:
node = queue.popleft()
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
# Dijkstra's Algorithm
def dijkstra(graph, start):
distances = {node: float('inf') for node in graph}
distances[start] = 0
pq = [(0, start)]
while pq:
curr_dist, curr = heapq.heappop(pq)
if curr_dist > distances[curr]:
continue
for neighbor, weight in graph[curr].items():
distance = curr_dist + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(pq, (distance, neighbor))
return distances
Dynamic Programming
Dynamic programming solutions using memoization and tabulation.
# Top-down (Memoization)
def fibonacci(n, memo=None):
if memo is None:
memo = {}
if n in memo:
return memo[n]
if n <= 1:
return n
memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo)
return memo[n]
# Bottom-up (Tabulation)
def fibonacci(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
Common Patterns
Two Pointers Technique
The two-pointer technique is commonly used for array and string problems.
# Two pointers from ends
def two_sum(arr, target):
left, right = 0, len(arr) - 1
while left < right:
curr_sum = arr[left] + arr[right]
if curr_sum == target:
return [left, right]
elif curr_sum < target:
left += 1
else:
right -= 1
return []
# Fast and slow pointers
def find_cycle(head):
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
return True
return False
Sliding Window Pattern
Sliding window patterns for substring and subarray problems.
# Fixed size window
def max_sum_subarray(arr, k):
window_sum = sum(arr[:k])
max_sum = window_sum
for i in range(len(arr) - k):
window_sum = window_sum - arr[i] + arr[i + k]
max_sum = max(max_sum, window_sum)
return max_sum
# Variable size window
def longest_substring_k_distinct(s, k):
char_count = {}
max_length = start = 0
for end, char in enumerate(s):
char_count[char] = char_count.get(char, 0) + 1
while len(char_count) > k:
left_char = s[start]
char_count[left_char] -= 1
if char_count[left_char] == 0:
del char_count[left_char]
start += 1
max_length = max(max_length, end - start + 1)
return max_length
Time Complexity Reference
Understanding time complexity is crucial for optimizing solutions.
Common Operations
# O(1): Constant Time
dict.get(key)
set.add(item)
list[index]
# O(log n): Logarithmic Time
binary_search(sorted_list)
heap operations
# O(n): Linear Time
for loop
list.index(item)
max(list)
min(list)
# O(n log n): Linearithmic Time
sorted(list)
list.sort()
# O(n²): Quadratic Time
nested for loops
# O(2ⁿ): Exponential Time
recursive fibonacci
generating all subsets
# O(n!): Factorial Time
generating all permutations
Built-in Functions and Libraries
Essential Python Functions
# Math operations
abs(-5) # Absolute value
pow(2, 3) # Power
round(3.14159, 2) # Round to decimals
float('inf') # Infinity
float('-inf') # Negative infinity
# String operations
s.strip() # Remove whitespace
s.lower() # Convert to lowercase
s.upper() # Convert to uppercase
s.split(',') # Split by delimiter
''.join(list) # Join list to string
Common Libraries
# Binary Search operations
from bisect import bisect_left, bisect_right
# Collections
from collections import deque, defaultdict, Counter
# Heap operations
from heapq import heappush, heappop, heapify
# Itertools
from itertools import permutations, combinations
# Memoization
from functools import lru_cache # Memoization decorator
Best Practices for Interviews
Code Organization
- Write clean, readable code
- Use meaningful variable names
- Add comments for complex logic
- Break down complex problems into smaller functions
Problem-Solving Approach
- Understand the problem completely
- Work through examples
- Consider edge cases
- Start with brute force solution
- Optimize the solution
- Test your code
Common Pitfalls to Avoid
- Off-by-one errors in array indexing
- Not handling edge cases
- Forgetting to handle null/None inputs
- Not considering integer overflow
- Modifying collections while iterating