Professional Documents
Culture Documents
Unit1
Asymptotic notation is a mathematical tool used in the analysis of algorithms
to describe their behavior as the size of their input approaches infinity. It
allows us to understand how the performance of an algorithm scales with
increasing input size. There are three primary notations used in asymptotic
analysis: Big O (O), Omega (Ω), and Theta (Θ).
1. Big O Notation (O):
o Big O notation describes the upper bound or the worst-case scenario of an
algorithm's time or space complexity.
o It represents the maximum rate of growth of a function.
o Formally, for a function f(n), O(g(n)) represents an upper bound if there exist
constants c and n₀ such that |f(n)| ≤ c * |g(n)| for all n > n₀.
o In simpler terms, it provides an estimate of the worst-case running time of an
algorithm as a function of the input size.
2. Omega Notation (Ω):
o Omega notation describes the lower bound or the best-case scenario of an
algorithm's time or space complexity.
o It represents the minimum rate of growth of a function.
o Formally, for a function f(n), Ω(g(n)) represents a lower bound if there exist
constants c and n₀ such that |f(n)| ≥ c * |g(n)| for all n > n₀.
o In simpler terms, it provides an estimate of the best-case running time of an
algorithm as a function of the input size.
3. Theta Notation (Θ):
o Theta notation provides both upper and lower bounds, essentially giving a
tight bound on an algorithm's time or space complexity.
o It represents the exact growth rate of a function.
o Formally, for a function f(n), Θ(g(n)) represents a tight bound if there exist
constants c₁, c₂, and n₀ such that c₁ * |g(n)| ≤ |f(n)| ≤ c₂ * |g(n)| for all n > n₀.
o In simpler terms, it provides an estimate of both the best and worst-case
running time of an algorithm as a function of the input size.
Long integer multi 11. swap arr[i] with arr[largest] graphs, determining connectivity, and solving problems where you need
12. MaxHeapify(arr,largest)
• Otherwise, split both A and B into two equal-sized parts: to explore nodes level by level.
DFS(graph, start_node): Johnson-Trotter algorithm: The fake coin problem, also known as the counterfeit coin
problem, is a classic problem in mathematics and computer science. The
Initialize an empty set to keep track of visited nodes 1. Initialize an array representing the permutation, with elements problem is to find a counterfeit coin among a set of coins using a balance scale,
from 1 to n arranged in ascending order. which can only compare the weights of two sets of coins.Divide and Conquer:
Call the recursive dfs_util function with the start_node and the 2. Initialize an array to keep track of the directions of each Divide the set of coins into two equal (or nearly equal) subsets.
visited set element. If an element is pointing left (denoted by -1) it moves 1. Weigh the Two Sets: Use the balance scale to compare the weights of
dfs_util(graph, node, visited): left in the permutation, and if it's pointing right (denoted by 1) it the two sets of coins:
Add the current node to the visited set moves right. o If the two sets have equal weights, the fake coin must be in the
remaining unweighed coins.
Process the current node (e.g., print it, perform some operation) 3. Find the largest mobile element in the permutation. A mobile o If one set is heavier than the other, the fake coin must be in that set.
element is an element that is greater than its adjacent element in 2. Recursively Repeat: Recursively repeat steps 1 and 2 with the subset
For each neighbor of the current node: the direction it is pointing. containing the fake coin until the fake coin is found.
4. Swap the mobile element with the element it is pointing to
If the neighbor has not been visited: def find_fake_coin(coins):
(adjacent) in the direction it is pointing.
Recursively call dfs_util with the neighbor and the visited set 5. Reverse the direction of all elements greater than the swapped if len(coins) == 1:
element.
BFS(graph, start_node): 6. Repeat steps 3-5 until there are no mobile elements left. return coins[0] # Base case: only one coin left, it must
be the fake one
Initialize an empty set to keep track of visited nodes The Josephus problem is a theoretical problem related to a # Weigh the two subsets
certain counting-out game. In this problem, a group of n people
Initialize an empty queue and enqueue the start_node (numbered from 1 to n) are standing in a circle. Starting from person 1, middle_index = len(coins) // 2
every kth person is eliminated from the circle until only one person
Add the start_node to the visited set
remains. The problem is to find the position of the last remaining person. weight_left = sum(coins[:middle_index])
while the queue is not empty:
function josephus(n, k): weight_right = sum(coins[middle_index:])
Dequeue a node from the queue
if n == 1:
Process the dequeued node (e.g., print it, perform some
return 1 // Base case: only one person remains, so their # Recursively find the fake coin in the heavier subset
operation)
position is 1
For each neighbor of the dequeued node: if weight_left == weight_right:
else:
If the neighbor has not been visited: return find_fake_coin(coins[middle_index:])
// Recursively find the position of the survivor for a circle
Add the neighbor to the visited set with n-1 people else:
Enqueue the neighbor into the queue return (josephus(n - 1, k) + k - 1) % n + 1 return find_fake_coin(coins[:middle_index])
for j from 0 to n-1: // Update key values and parent pointers of adjacent
vertices of u
// If vertex k is included in the shortest path from i to j,
update the distance for each vertex v adjacent to u:
if dist[i][k] + dist[k][j] < dist[i][j]: if v is not yet visited and weight of edge u-v is less
dist[i][j] = dist[i][k] + dist[k][j] than key[v]:
4. **NP-Hard**: