Understanding the time and space complexity of an algorithm is crucial. Big - O notation is used to describe the upper bound of an algorithm’s time or space complexity. For example, an algorithm with a time complexity of $O(n)$ means that the running time of the algorithm grows linearly with the size of the input $n$.
class Graph:
def __init__(self):
self.adj_list = {}
def add_vertex(self, vertex):
if vertex not in self.adj_list:
self.adj_list[vertex] = []
def add_edge(self, vertex1, vertex2):
if vertex1 in self.adj_list and vertex2 in self.adj_list:
self.adj_list[vertex1].append(vertex2)
self.adj_list[vertex2].append(vertex1)
# Example usage
g = Graph()
g.add_vertex(1)
g.add_vertex(2)
g.add_edge(1, 2)
print(g.adj_list)
import heapq
# Python's heapq module implements a min - heap, so we use negative values for max - heap
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
max_heap = [-i for i in data]
heapq.heapify(max_heap)
print(-heapq.heappop(max_heap))
import heapq
from collections import defaultdict
def dijkstra(graph, start):
distances = {node: float('inf') for node in graph}
distances[start] = 0
priority_queue = [(0, start)]
while priority_queue:
current_distance, current_node = heapq.heappop(priority_queue)
if current_distance > distances[current_node]:
continue
for neighbor, weight in graph[current_node].items():
distance = current_distance + weight
if distance < distances[neighbor]:
distances[neighbor] = distance
heapq.heappush(priority_queue, (distance, neighbor))
return distances
# Example graph
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'))
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
arr = [1, 3, 5, 7, 9]
print(binary_search(arr, 5))
def solve_n_queens(n):
def is_safe(board, row, col):
for i in range(row):
if board[i][col] == 1:
return False
if col - (row - i) >= 0 and board[i][col - (row - i)] == 1:
return False
if col + (row - i) < n and board[i][col + (row - i)] == 1:
return False
return True
def backtrack(board, row):
if row == n:
solutions.append([row[:] for row in board])
return
for col in range(n):
if is_safe(board, row, col):
board[row][col] = 1
backtrack(board, row + 1)
board[row][col] = 0
solutions = []
board = [[0] * n for _ in range(n)]
backtrack(board, 0)
return solutions
print(solve_n_queens(4))
sum()
instead of a manual loop to calculate the sum of a list.range()
instead of creating a full list for large sequences.Advanced DSA techniques in Python are essential for writing efficient and optimized code. By understanding fundamental concepts such as advanced data structures and algorithm complexity, implementing them using proper usage methods, following common practices like searching and sorting, and adhering to best practices in code optimization and memory management, you can take your Python programming skills to the next level. These techniques will not only help you solve complex problems more efficiently but also make your code more maintainable.