[go: up one dir, main page]

0% found this document useful (0 votes)
338 views30 pages

Competitive Programming in Python Handbook

Uploaded by

attastudy7
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
338 views30 pages

Competitive Programming in Python Handbook

Uploaded by

attastudy7
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 30

COMPETITIVE PROGRAMMING IN PYTHON HANDBOOK 1 and 2

Certainly! Below is a concise handbook that covers frequently used algorithms and data structures in
competitive programming, with explanations and Python implementations.

# Competitive Programming Handbook

## Table of Contents

1. Introduction

2. Data Structures

- Arrays

- Linked Lists

- Stacks

- Queues

- Trees

- Graphs

- Hash Tables

3. Algorithms

- Sorting Algorithms

- Searching Algorithms

- Dynamic Programming

- Greedy Algorithms

- Graph Algorithms

- String Algorithms

4. Conclusion

---

## 1. Introduction
Competitive programming requires a solid understanding of algorithms and data structures to solve
problems efficiently. This handbook provides an overview of the most commonly used structures and
algorithms, along with Python implementations.

---

## 2. Data Structures

### Arrays

A collection of elements identified by index. Used for storing data in contiguous memory locations.

**Python Example:**

```python

arr = [1, 2, 3, 4, 5]

print(arr[2]) # Output: 3

```

### Linked Lists

A data structure consisting of nodes, where each node contains data and a reference to the next node.

**Python Example:**

```python

class Node:

def __init__(self, value):

self.value = value

self.next = None

class LinkedList:

def __init__(self):
self.head = None

```

### Stacks

A collection of elements that follows Last In First Out (LIFO) principle. Supports `push` and `pop`
operations.

**Python Example:**

```python

stack = []

stack.append(1)

stack.append(2)

print(stack.pop()) # Output: 2

```

### Queues

A collection of elements that follows First In First Out (FIFO) principle. Supports `enqueue` and
`dequeue` operations.

**Python Example:**

```python

from collections import deque

queue = deque()

queue.append(1)

queue.append(2)

print(queue.popleft()) # Output: 1

```
### Trees

A hierarchical data structure with nodes connected by edges. Each tree has a root and can have children.

**Binary Tree Node Example:**

```python

class TreeNode:

def __init__(self, value):

self.value = value

self.left = None

self.right = None

```

### Graphs

A collection of nodes connected by edges. Can be directed or undirected.

**Adjacency List Example:**

```python

graph = {

0: [1, 2],

1: [2],

2: [0, 3],

3: [3]

```

### Hash Tables

A data structure that maps keys to values for efficient lookups, insertions, and deletions.

**Python Example:**
```python

hash_table = {}

hash_table['key'] = 'value'

print(hash_table['key']) # Output: value

```

---

## 3. Algorithms

### Sorting Algorithms

1. **Bubble Sort**: Repeatedly swap adjacent elements if they are in the wrong order.

2. **Quick Sort**: Divide and conquer algorithm selecting a 'pivot'.

3. **Merge Sort**: Divide the array into halves, sort and merge.

**Python Example (Merge Sort):**

```python

def merge_sort(arr):

if len(arr) > 1:

mid = len(arr) // 2

left_half = arr[:mid]

right_half = arr[mid:]

merge_sort(left_half)

merge_sort(right_half)

i=j=k=0

while i < len(left_half) and j < len(right_half):

if left_half[i] < right_half[j]:


arr[k] = left_half[i]

i += 1

else:

arr[k] = right_half[j]

j += 1

k += 1

while i < len(left_half):

arr[k] = left_half[i]

i += 1

k += 1

while j < len(right_half):

arr[k] = right_half[j]

j += 1

k += 1

# Example usage:

arr = [38, 27, 43, 3, 9, 82, 10]

merge_sort(arr)

print(arr) # Output: [3, 9, 10, 27, 38, 43, 82]

```

### Searching Algorithms

1. **Linear Search**: Check each element until the target is found.

2. **Binary Search**: Efficiently find an item in a sorted array.

**Python Example (Binary Search):**

```python
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

# Example usage:

arr = [1, 2, 3, 4, 5]

print(binary_search(arr, 3)) # Output: 2

```

### Dynamic Programming

A method for solving complex problems by breaking them down into simpler subproblems, storing
results to avoid recomputation.

**Fibonacci Sequence Example:**

```python

def fibonacci(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]
# Example usage:

print(fibonacci(10)) # Output: 55

```

### Greedy Algorithms

A method for solving problems by making a sequence of choices, each of which looks best at the
moment.

**Activity Selection Example:**

```python

def activity_selection(start, finish):

n = len(start)

activities = sorted(zip(start, finish), key=lambda x: x[1])

count = 1

last_finish_time = activities[0][1]

for i in range(1, n):

if activities[i][0] >= last_finish_time:

count += 1

last_finish_time = activities[i][1]

return count

# Example usage:

start = [1, 3, 0, 5, 8, 5]

finish = [2, 4, 6, 7, 9, 9]

print(activity_selection(start, finish)) # Output: 4

```
### Graph Algorithms

1. **Depth First Search (DFS)**: Traverses the graph by exploring as far as possible along each branch.

2. **Breadth First Search (BFS)**: Explores all neighbors at the present depth prior to moving on to
nodes at the next depth level.

3. **Dijkstra’s Algorithm**: Finds the shortest path from a source to all vertices in a weighted graph.

**Python Example (BFS):**

```python

from collections import deque

def bfs(graph, start):

visited = set()

queue = deque([start])

visited.add(start)

while queue:

vertex = queue.popleft()

print(vertex, end=" ")

for neighbor in graph[vertex]:

if neighbor not in visited:

visited.add(neighbor)

queue.append(neighbor)

# Example usage:

graph = {

0: [1, 2],

1: [0, 3, 4],

2: [0],
3: [1],

4: [1]

bfs(graph, 0) # Output: 0 1 2 3 4

```

### String Algorithms

1. **KMP Algorithm**: Efficient string searching algorithm.

2. **Rabin-Karp Algorithm**: Uses hashing for searching.

**Python Example (KMP):**

```python

def kmp_pattern_search(text, pattern):

lps = [0] * len(pattern)

j = 0 # length of previous longest prefix suffix

compute_lps_array(pattern, lps)

i = 0 # index for text

while i < len(text):

if pattern[j] == text[i]:

i += 1

j += 1

if j == len(pattern):

print(f"Pattern found at index {i - j}")

j = lps[j - 1]

elif i < len(text) and pattern[j] != text[i]:

if j != 0:

j = lps[j - 1]
else:

i += 1

def compute_lps_array(pattern, lps):

length = 0

i=1

while i < len(pattern):

if pattern[i] == pattern[length]:

length += 1

lps[i] = length

i += 1

else:

if length != 0:

length = lps[length - 1]

else:

lps[i] = 0

i += 1

# Example usage:

text = "ABABDABACDABABCABAB"

pattern = "ABABCABAB"

kmp_pattern_search(text, pattern) # Output: Pattern found at index 10

```

---

## 4. Conclusion
This handbook provides a solid foundation for understanding the data structures and algorithms
commonly used in competitive programming. Mastering these concepts will significantly improve your
problem-solving skills and performance in contests.

Practice implementing these algorithms and structures to build your proficiency!

Feel free to expand upon this handbook with more advanced topics or additional algorithms based on
your needs!

Great! Here’s a more detailed version of the competitive programming handbook, expanding on the
previous sections and including more advanced topics and algorithms.

# Competitive Programming Handbook

## Table of Contents

1. Introduction

2. Data Structures

- Arrays

- Linked Lists

- Stacks

- Queues

- Trees

- Binary Trees

- Binary Search Trees

- Heaps

- Segment Trees

- Fenwick Trees (Binary Indexed Trees)

- Graphs

- Hash Tables

3. Algorithms
- Sorting Algorithms

- Searching Algorithms

- Dynamic Programming

- Greedy Algorithms

- Graph Algorithms

- String Algorithms

- Number Theory

- Combinatorial Algorithms

4. Conclusion

---

## 1. Introduction

Competitive programming is a mental sport that involves solving algorithmic and mathematical problems
within a limited time frame. This handbook aims to equip you with the essential data structures and
algorithms frequently encountered in contests.

---

## 2. Data Structures

### Arrays

- **Definition**: A collection of elements stored at contiguous memory locations.

- **Time Complexity**: Access: O(1), Search: O(n), Insert/Delete: O(n).

**Example**:

```python

arr = [1, 2, 3, 4, 5]

print(arr[2]) # Output: 3
```

### Linked Lists

- **Definition**: A linear data structure where elements are stored in nodes, with each node containing
a reference to the next.

- **Types**: Singly Linked List, Doubly Linked List, Circular Linked List.

**Example**:

```python

class Node:

def __init__(self, value):

self.value = value

self.next = None

class LinkedList:

def __init__(self):

self.head = None

def append(self, value):

new_node = Node(value)

if not self.head:

self.head = new_node

return

last = self.head

while last.next:

last = last.next

last.next = new_node

```
### Stacks

- **Definition**: A collection of elements with Last In First Out (LIFO) access.

- **Operations**: Push, Pop, Peek.

**Example**:

```python

stack = []

stack.append(1)

stack.append(2)

print(stack.pop()) # Output: 2

```

### Queues

- **Definition**: A collection of elements with First In First Out (FIFO) access.

- **Operations**: Enqueue, Dequeue, Peek.

**Example**:

```python

from collections import deque

queue = deque()

queue.append(1)

queue.append(2)

print(queue.popleft()) # Output: 1

```

### Trees

#### Binary Trees

- **Definition**: A tree where each node has at most two children.


**Example**:

```python

class TreeNode:

def __init__(self, value):

self.value = value

self.left = None

self.right = None

```

#### Binary Search Trees (BST)

- **Definition**: A binary tree where for each node, the left child’s value is less, and the right child’s
value is greater.

**Insertion Example**:

```python

class BST:

def __init__(self):

self.root = None

def insert(self, value):

if not self.root:

self.root = TreeNode(value)

else:

self._insert_recursive(self.root, value)

def _insert_recursive(self, node, value):

if value < node.value:

if node.left is None:
node.left = TreeNode(value)

else:

self._insert_recursive(node.left, value)

else:

if node.right is None:

node.right = TreeNode(value)

else:

self._insert_recursive(node.right, value)

```

#### Heaps

- **Definition**: A complete binary tree that maintains the heap property (max-heap or min-heap).

- **Time Complexity**: Insert: O(log n), Extract: O(log n).

**Example (Min-Heap)**:

```python

import heapq

min_heap = []

heapq.heappush(min_heap, 5)

heapq.heappush(min_heap, 3)

print(heapq.heappop(min_heap)) # Output: 3

```

#### Segment Trees

- **Definition**: A tree used for storing intervals or segments, allowing efficient range queries and
updates.

**Example** (Range Sum Query):


```python

class SegmentTree:

def __init__(self, data):

self.n = len(data)

self.tree = [0] * (2 * self.n)

for i in range(self.n):

self.tree[self.n + i] = data[i]

for i in range(self.n - 1, 0, -1):

self.tree[i] = self.tree[i << 1] + self.tree[i << 1 | 1]

def update(self, idx, value):

idx += self.n

self.tree[idx] = value

while idx > 1:

idx >>= 1

self.tree[idx] = self.tree[idx << 1] + self.tree[idx << 1 | 1]

def query(self, left, right):

result = 0

left += self.n

right += self.n

while left < right:

if left & 1:

result += self.tree[left]

left += 1

if right & 1:

right -= 1

result += self.tree[right]

left >>= 1
right >>= 1

return result

# Example usage:

data = [1, 3, 5, 7, 9, 11]

seg_tree = SegmentTree(data)

print(seg_tree.query(1, 4)) # Output: 15

```

#### Fenwick Trees (Binary Indexed Trees)

- **Definition**: A data structure that provides efficient methods for cumulative frequency tables and
point updates.

**Example**:

```python

class FenwickTree:

def __init__(self, size):

self.size = size

self.tree = [0] * (size + 1)

def update(self, index, delta):

while index <= self.size:

self.tree[index] += delta

index += index & -index

def query(self, index):

sum = 0

while index > 0:

sum += self.tree[index]
index -= index & -index

return sum

# Example usage:

fenwick = FenwickTree(10)

fenwick.update(1, 5)

fenwick.update(2, 3)

print(fenwick.query(2)) # Output: 8

```

### Graphs

- **Definition**: A collection of vertices connected by edges. Can be directed or undirected.

#### Representations:

1. **Adjacency List**:

```python

graph = {

0: [1, 2],

1: [2],

2: [0, 3],

3: [3]

```

2. **Adjacency Matrix**:

```python

n=4

adj_matrix = [[0] * n for _ in range(n)]

adj_matrix[0][1] = 1
adj_matrix[0][2] = 1

```

---

## 3. Algorithms

### Sorting Algorithms

1. **Bubble Sort**: O(n²) complexity.

2. **Quick Sort**: Average O(n log n), worst O(n²).

3. **Merge Sort**: O(n log n).

4. **Heap Sort**: O(n log n).

**Example (Quick Sort)**:

```python

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)

# Example usage:

arr = [3, 6, 8, 10, 1, 2, 1]

print(quick_sort(arr)) # Output: [1, 1, 2, 3, 6, 8, 10]

```
### Searching Algorithms

1. **Linear Search**: O(n).

2. **Binary Search**: O(log n), requires sorted array.

**Example (Binary Search)**:

```python

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

# Example usage:

arr = [1, 2, 3, 4, 5]

print(binary_search(arr, 3)) # Output: 2

```

### Dynamic Programming

- **Definition**: A method to solve problems by breaking them into simpler subproblems and storing
their solutions.

**Fibonacci Example**:

```python
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]

# Example usage:

print(fibonacci(10)) # Output: 55

```

### Greedy Algorithms

- **Definition**: A method for solving optimization problems by selecting the best option at each step.

**Example (Activity Selection)**:

```python

def activity_selection(start, finish):

activities = sorted(zip(start, finish), key=lambda x: x[1])

count = 1

last_finish_time = activities[0][1]

for i in range(1, len(activities)):

if activities[i][0] >= last_finish_time:

count += 1

last_finish_time = activities[i][1]
return count

# Example usage:

start = [1, 3, 0, 5, 8, 5]

finish = [2, 4, 6, 7, 9, 9]

print(activity_selection(start, finish)) # Output: 4

```

### Graph Algorithms

1. **Depth First Search (DFS)**:

```python

def dfs(graph, start, visited=None):

if visited is None:

visited = set()

visited.add(start)

for neighbor in graph[start]:

if neighbor not in visited:

dfs(graph, neighbor, visited)

return visited

# Example usage:

graph = {

0: [1, 2],

1: [0, 3],

2: [0],

3: [1]

print(dfs(graph, 0)) # Output: {0, 1, 2, 3}


```

2. **Breadth First Search (BFS)**:

```python

from collections import deque

def bfs(graph, start):

visited = set()

queue = deque([start])

visited.add(start)

while queue:

vertex = queue.popleft()

print(vertex, end=" ")

for neighbor in graph[vertex]:

if neighbor not in visited:

visited.add(neighbor)

queue.append(neighbor)

# Example usage:

bfs(graph, 0) # Output: 0 1 2 3

```

3. **Dijkstra’s Algorithm**:

```python

import heapq

def dijkstra(graph, start):

queue = []
distances = {vertex: float('infinity') for vertex in graph}

distances[start] = 0

heapq.heappush(queue, (0, start))

while queue:

current_distance, current_vertex = heapq.heappop(queue)

if current_distance > distances[current_vertex]:

continue

for neighbor, weight in graph[current_vertex].items():

distance = current_distance + weight

if distance < distances[neighbor]:

distances[neighbor] = distance

heapq.heappush(queue, (distance, neighbor))

return distances

# Example usage:

graph = {

'A': {'B': 1, 'C': 4},

'B': {'A': 1, 'C': 2, 'D': 5},

'C': {'A': 4, 'B': 2, 'D': 1},

'D': {'B': 5, 'C': 1}

print(dijkstra(graph, 'A')) # Output: {'A': 0, 'B': 1, 'C': 3, 'D': 4}

```

### String Algorithms


1. **KMP Algorithm**: Efficient substring search.

2. **Rabin-Karp Algorithm**: Uses hashing for searching.

**Example (KMP)**:

```python

def kmp_pattern_search(text, pattern):

lps = compute_lps(pattern)

i = j = 0 # index for text and pattern

while i < len(text):

if pattern[j] == text[i]:

i += 1

j += 1

if j == len(pattern):

print(f"Pattern found at index {i - j}")

j = lps[j - 1]

elif i < len(text) and pattern[j] != text[i]:

if j != 0:

j = lps[j - 1]

else:

i += 1

def compute_lps(pattern):

lps = [0] * len(pattern)

length = 0

i=1

while i < len(pattern):

if pattern[i] == pattern[length]:

length += 1

lps[i] = length
i += 1

else:

if length != 0:

length = lps[length - 1]

else:

lps[i] = 0

i += 1

return lps

# Example usage:

text = "ABABDABACDABABCABAB"

pattern = "ABABCABAB"

kmp_pattern_search(text, pattern) # Output: Pattern found at index 10

```

### Number Theory

1. **GCD (Greatest Common Divisor)**:

```python

def gcd(a, b):

while b:

a, b = b, a % b

return a

# Example usage:

print(gcd(48, 18)) # Output: 6

```

2. **Prime Factorization**:

```python
def prime_factors(n):

factors = []

for i in range(2, int(n**0.5) + 1):

while n % i == 0:

factors.append(i)

n //= i

if n > 1:

factors.append(n)

return factors

# Example usage:

print(prime_factors(100)) # Output: [2, 2, 5, 5]

```

### Combinatorial Algorithms

1. **Permutations**:

```python

from itertools import permutations

def get_permutations(elements):

return list(permutations(elements))

# Example usage:

print(get_permutations([1, 2, 3])) # Output: [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

```

2. **Combinations**:

```python

from itertools import combinations


def get_combinations(elements, r):

return list(combinations(elements, r))

# Example usage:

print(get_combinations([1, 2, 3, 4], 2)) # Output: [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

```

---

## 4. Conclusion

This expanded handbook provides a comprehensive overview of essential data structures and algorithms
commonly used in competitive programming. Mastery of these topics will greatly enhance your
problem-solving abilities and performance in coding contests. Practice implementing these concepts and
tackling a variety of problems to solidify your understanding!

Feel free to adapt or expand upon this handbook based on your own experiences and needs! If you need
further details or specific topics, let me know!

You might also like