DAA Laboratory
Practical Assessment Index
| Sr. No. | Experiment Title | Algorithmic Paradigm | Time Complexity | Space Complexity |
|---|---|---|---|---|
| 1 | Prime Number Detection | Trial Division / Math | ||
| 2 | Search Insert Position | Binary Search | ||
| 3 | Candy Distribution Problem | Greedy (Two-Pass Traversal) | ||
| 4 | Aggressive Cows | Binary Search on Answer + Greedy | ||
| 5 | Cycle Detection in Undirected Graph | Depth-First Search (DFS) | ||
| 6 | Critical Connections in a Network (Bridges) | Tarjan's Algorithm (DFS + Discovery Times) | ||
| 7 | Number of Islands | 8-Directional Graph Traversal (DFS) | ||
| 8 | Rotting Oranges | Multi-Source Breadth-First Search (BFS) | ||
| 9 | Minimum Edit Distance | Dynamic Programming (2D Table) | ||
| 10 | Minimum Path Sum | Dynamic Programming (Grid Tabulation) | ||
| 11 | Remove K Digits | Greedy Strategy + Monotonic Stack | ||
| 12 | Unique Paths | Dynamic Programming (Grid Paths) |
Practical 1: Primality Testing
1.1 Aim
- Write a program to determine whether the given number is prime or not.
1.2 Theory & Core Concepts
- Prime Number Definition: A natural number greater than 1 that possesses exactly two distinct positive divisors: 1 and itself (e.g., 2, 3, 5, 7, 11).
- Divisibility Testing:
- Any number is immediately non-prime.
- To test primality, check divisibility for factors in the interval .
- If for any integer in this range, is composite (not prime).
- If no factor is encountered across all candidates, is certified prime.
- Key Java Components:
Scannerclass for interactive console input.forloop to iterate across prospective divisors.ifconditional statements for immediate termination.
1.3 Algorithm
- Start.
- Read an integer from the user.
- If :
- Print "Not a prime number."
- Stop.
- Iterate with index from 2 up to :
- If :
- Print "Not a prime number."
- Stop.
- If :
- Print "Prime number."
- End.
1.4 Java Implementation
import java.util.Scanner;
class prime {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
if (n <= 1) {
System.out.println("Not a prime number.");
return;
}
for (int i = 2; i <= n / 2; i++) {
if (n % i == 0) {
System.out.println("Not a prime number.");
return;
}
}
System.out.println("Prime number.");
}
}
1.5 Sample Input & Output
- Input:
8
- Output:
Not a prime number.
1.6 Complexity & Frequency Analysis
| Statement / Operation | Frequency |
|---|---|
Input: Scanner sc = new Scanner(System.in); | |
Loop Header: for (int i = 2; i <= n / 2; i++) | |
Loop Body: if (n % i == 0) | |
| Total Operations |
- Time Complexity:
- Best Case: when is an even number greater than 2.
- Worst Case: when is prime, requiring full traversal up to .
- Space Complexity: auxiliary space.
1.7 Conclusion
- The program demonstrates elementary primality testing via trial division up to . Loop execution confirms that testing up to half the input provides a deterministic answer within runtime.
2. Practical 2: Search Insert Position (Binary Search)
2.1 Aim
- Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
2.2 Theory & Core Concepts
- Binary Search Paradigm: Exploits monotonic order by iteratively halving the search space.
- Search Mechanics:
- Maintain boundary pointers:
low = 0andhigh = n - 1. - Compute midpoint:
mid = (low + high) / 2. - If
arr[mid] == target, target exists atmid. - If
arr[mid] < target, discard left half (low = mid + 1). - If
arr[mid] > target, discard right half (high = mid - 1).
- Maintain boundary pointers:
- Insertion Guarantee: If target is absent, the search terminates with
low > high. The variablelowstrictly points to the correct insertion rank preserving ascending order.
2.3 Algorithm
- Start.
- Read array size , the sorted array elements, and search key.
- Initialize
low = 0,high = n - 1. - While
low <= high:- Set
mid = (low + high) / 2. - If
arr[mid] == key:- Print
midas target index. - Stop.
- Print
- Else if
arr[mid] < key:- Set
low = mid + 1.
- Set
- Else:
- Set
high = mid - 1.
- Set
- Set
- When
low > high, printlowas insertion index. - End.
2.4 Java Implementation
import java.util.Scanner;
class binary {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter the size of array: ");
int n = sc.nextInt();
int[] arr = new int[n];
System.out.println("\nEnter the array");
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
}
System.out.println("\nEnter the key to find: ");
int key = sc.nextInt();
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] == key) {
System.out.println("\nElement found at " + mid);
return;
} else if (arr[mid] < key) {
low = mid + 1;
} else {
high = mid - 1;
}
}
System.out.println("\nElement must be inserted at " + low);
}
}
2.5 Sample Input & Output
- Input:
Enter the size of array: 4Enter the array131441451333Enter the key to find:23
- Output:
Element must be inserted at 1
2.6 Complexity & Frequency Analysis
| Search Iteration () | Remaining Array Size |
|---|---|
| 1 | |
| 2 | |
| 3 | |
- Derivation of Max Steps ():
- Complexity Breakdown:
- Best Case Time Complexity: (target matches middle element on initial comparison).
- Worst Case Time Complexity: (element absent or at boundary).
- Average Case Time Complexity: .
- Space Complexity: in-place iterative pointers.
2.7 Conclusion
- Binary search optimizes search and insertion rank detection from linear to logarithmic , providing scalability for large ordered datasets.
3. Practical 3: Candy Distribution Problem (Greedy Two-Pass)
3.1 Aim
- There are children standing in a line with rating values. Distribute the minimum number of candies such that:
- Each child receives at least one candy.
- Children with higher ratings than their immediate neighbours receive more candies than them.
3.2 Theory & Core Concepts
- Greedy Strategy: Instead of attempting to simultaneously reconcile left and right neighbours, decompose the problem into two monotonic passes.
- Two-Pass Algorithm:
- Initialization: Assign 1 candy to every child: .
- Left-to-Right Pass: Ensure rightward consistency:
- Right-to-Left Pass: Ensure leftward consistency without invalidating the first pass:
- Summation: Aggregate all values in the candy array.
3.3 Algorithm
- Start.
- If total children , output 0 and stop.
- Allocate arrays
ratingandcandyof size . Initialize all entries ofcandyto 1. - Forward Pass: For from 1 to :
- If
rating[i] > rating[i - 1], setcandy[i] = candy[i - 1] + 1.
- If
- Backward Pass: For from down to 0:
- If
rating[i] > rating[i + 1]andcandy[i] < candy[i + 1] + 1:- Set
candy[i] = candy[i + 1] + 1.
- Set
- If
- Compute sum of all elements in
candy. - Output total candies and stop.
3.4 Java Implementation
import java.util.Scanner;
class rate {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int[] rating = new int[N];
int[] candy = new int[N];
for (int i = 0; i < N; i++) {
rating[i] = scanner.nextInt();
candy[i] = 1;
}
for (int i = 1; i < N; i++) {
if (rating[i] > rating[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
for (int i = N - 2; i >= 0; i--) {
if (rating[i] > rating[i + 1] && candy[i] < candy[i + 1] + 1) {
candy[i] = candy[i + 1] + 1;
}
}
int total = 0;
for (int i = 0; i < N; i++) {
total = total + candy[i];
}
System.out.println("Minimum candies: " + total);
scanner.close();
}
}
3.5 Sample Input & Output
- Input:
31 0 5
- Output:
Minimum candies: 5
3.6 Complexity & Frequency Analysis
| Operation / Step | Execution Frequency |
|---|---|
| Input and candy initialization | |
| Left-to-right forward traversal | |
| Right-to-left backward traversal | |
| Total candy summation | |
| Total Operations |
- Time Complexity: where is the number of children.
- Space Complexity: auxiliary memory for the candy assignment buffer.
3.7 Conclusion
- Decoupling bi-directional relative ranking constraints into two independent passes guarantees local optimality at each step, yielding the global minimum candy allocation in linear time.
4. Practical 4: Aggressive Cows (Binary Search on Answer)
4.1 Aim
- There are stalls and cows. Stalls are located on a straight line at coordinates (). Assign cows to stalls such that the minimum distance between any two cows is maximized.
4.2 Theory & Core Concepts
- Paradigm: Binary Search on Answer combined with Greedy Feasibility Checking.
- Monotonicity Property: If it is possible to place cows with at least distance , then any distance is also feasible. Conversely, if distance fails, any is impossible.
- Search Interval:
low = 0high = stall[N - 1] - stall[0](after sorting stall coordinates)
- Greedy Placement Subroutine (
canplace):- Always place the first cow in stall 0.
- Sequentially scan stalls; place the next cow in stall as soon as .
- Return
trueif cow count placed .
4.3 Algorithm
- Start.
- Read stall count , stall positions array, and cow count .
- Sort stall positions in ascending order.
- Set
low = 0,high = stall[N - 1] - stall[0]. - While
low < high:- Compute
mid = (low + high + 1) / 2. - Test feasibility using
canplace(stall, cows, mid). - If feasible, update
low = mid. - Else, update
high = mid - 1.
- Compute
- Print
lowas the optimal maximum minimum gap. - Stop.
4.4 Java Implementation
import java.util.Scanner;
import java.util.Arrays;
class cow {
static boolean canplace(int[] a, int cows, int d) {
int count = 1, last = a[0];
for (int i = 1; i < a.length; i++) {
if (a[i] - last >= d) {
count++;
last = a[i];
}
}
return count >= cows;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] stall = new int[n];
for (int i = 0; i < n; i++)
stall[i] = sc.nextInt();
int cows = sc.nextInt();
Arrays.sort(stall);
int l = 0, r = stall[n - 1] - stall[0];
while (l < r) {
int mid = (l + r + 1) / 2;
if (canplace(stall, cows, mid))
l = mid;
else
r = mid - 1;
}
System.out.println("Minimum Gap: " + l);
sc.close();
}
}
4.5 Sample Input & Output
- Input:
51 200000000 4000000 8000000 9000000003
- Output:
Minimum Gap: 199999999
4.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Sorting stall coordinates | 1 | |
| Binary search over coordinate range | ||
Greedy placement check (canplace) | per iteration | |
| Overall Time Complexity | — |
- .
- Space Complexity: auxiliary space beyond input arrays.
4.7 Conclusion
- Transforming an optimization problem into a decision problem via Binary Search on Answer reduces exponential search spaces to logarithmic evaluations, handling coordinate magnitudes up to within milliseconds.
5. Practical 5: Cycle Detection in Undirected Graph (DFS)
5.1 Aim
- Given an undirected graph with vertices and edges, check whether it contains any cycle or not.
5.2 Theory & Core Concepts
- Cycle Condition: An undirected graph contains a cycle if and only if Depth-First Search encounters an adjacent visited vertex that is not the parent from which the current vertex was entered.
- Back-Edge Detection:
visited[]array prevents infinite looping across cycles.- Passing
parentnode in recursive calls prevents false cycle detection back to the immediate caller. - An edge to an already visited non-parent node indicates a cycle (back-edge).
- Disconnected Graphs: Outer loop iterating across all vertices from to ensures disconnected components are fully explored.
5.3 Algorithm
- Start.
- Initialize
visited[V] = false. - Read edges and populate adjacency representation.
- For each vertex from 0 to :
- If
!visited[i]:- Run
dfs(graph, visited, i, -1). - If
dfsreturnstrue, report "Cycle Detected" and terminate.
- Run
- If
- In
dfs(node, parent):- Mark
visited[node] = true. - For every adjacent vertex :
- If is connected:
- If
!visited[j]:- If
dfs(graph, visited, j, node)returnstrue, returntrue.
- If
- Else if :
- Return
true(cycle detected).
- Return
- If
- If is connected:
- Return
false.
- Mark
- Print "No Cycle Detected" if all components are acyclic.
- Stop.
5.4 Java Implementation
import java.util.Scanner;
public class Main {
static boolean dfs(int[][] graph, boolean[] visited, int node, int parent) {
visited[node] = true;
for (int i = 0; i < graph.length; i++) {
if (graph[node][i] == 1) {
if (!visited[i]) {
if (dfs(graph, visited, i, node))
return true;
} else if (i != parent) {
return true;
}
}
}
return false;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter number of vertices: ");
int V = sc.nextInt();
System.out.print("Enter number of edges: ");
int E = sc.nextInt();
int[][] graph = new int[V][V];
System.out.println("Enter the edges (u v):");
for (int i = 0; i < E; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
graph[u][v] = 1;
graph[v][u] = 1;
}
boolean[] visited = new boolean[V];
boolean cycle = false;
for (int i = 0; i < V; i++) {
if (!visited[i]) {
if (dfs(graph, visited, i, -1)) {
cycle = true;
break;
}
}
}
if (cycle) System.out.println("Cycle Detected");
else System.out.println("No Cycle Detected");
sc.close();
}
}
5.5 Sample Input & Output
- Input:
5 40 20 10 30 4
- Output:
No Cycle Detected
5.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Construct adjacency matrix | ||
| Initialize visited array | ||
| DFS exploration (matrix checking) | ||
| Total Complexity (Adjacency Matrix) | — | |
| Total Complexity (with Adjacency List) | — |
- Space Complexity: for adjacency matrix storage, plus recursive call stack depth.
5.7 Conclusion
- Graph traversal with explicit parent tracking detects cyclic dependencies by isolating non-trivial back-edges, achieving complete verification across all forest components.
6. Practical 6: Critical Connections in a Network (Tarjan's Bridges)
6.1 Aim
- There are servers numbered 0 to connected by undirected server-to-server connections. Find all critical connections (bridges) that, if removed, disconnect some servers from the rest of the network.
6.2 Theory & Core Concepts
- Bridge Definition: An edge whose removal strictly increases the number of connected components.
- Tarjan's DFS Parameters:
disc[u]: Discovery time of node .low[u]: Lowest discovery time reachable from via tree edges and at most one back-edge.
- Bridge Condition: An edge is a bridge if and only if: If , node possesses an alternative path/back-edge reaching or an ancestor of ; hence removing does not disconnect .
6.3 Algorithm
- Start.
- Read vertices and edges . Construct adjacency list
graph. - Initialize
disc[n],low[n],visited[n] = false,timer = 0. - For to , if
!visited[i], calldfs(i, -1). - Inside
dfs(u, parent):- Mark
visited[u] = true. - Set
disc[u] = low[u] = ++timer. - For each neighbour in
graph[u]:- If , continue.
- If
!visited[v]:- Recursively call
dfs(v, u). low[u] = Math.min(low[u], low[v]).- If
low[v] > disc[u], append edge to bridge list.
- Recursively call
- Else:
low[u] = Math.min(low[u], disc[v]).
- Mark
- Print bridge list, or "No Bridges".
- Stop.
6.4 Java Implementation
import java.util.*;
class Main {
static ArrayList<Integer>[] graph;
static boolean[] visited;
static int[] disc;
static int[] low;
static int timer = 0;
static ArrayList<String> bridges = new ArrayList<>();
static void dfs(int u, int parent) {
visited[u] = true;
disc[u] = low[u] = ++timer;
for (int v : graph[u]) {
if (v == parent)
continue;
if (!visited[v]) {
dfs(v, u);
low[u] = Math.min(low[u], low[v]);
if (low[v] > disc[u]) {
bridges.add(u + " " + v);
}
} else {
low[u] = Math.min(low[u], disc[v]);
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); // Number of vertices
int m = sc.nextInt(); // Number of edges
graph = new ArrayList[n];
for (int i = 0; i < n; i++)
graph[i] = new ArrayList<>();
for (int i = 0; i < m; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
graph[u].add(v);
graph[v].add(u);
}
visited = new boolean[n];
disc = new int[n];
low = new int[n];
for (int i = 0; i < n; i++)
if (!visited[i])
dfs(i, -1);
if (bridges.size() == 0) {
System.out.println("No Bridges");
} else {
System.out.println("Bridges:");
for (String s : bridges)
System.out.println(s);
}
}
}
6.5 Sample Input & Output
- Input:
5 50 11 22 01 33 4
- Output:
Bridges:3 41 3
6.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Build adjacency list | ||
| DFS vertex visits | ||
| Edge traversal and bridge checks | ||
| Total Running Time |
- Brute Force Comparison: Naive edge removal takes . Tarjan's single-pass DFS reduces this to optimal linear time .
- Space Complexity: for adjacency lists, plus arrays (
disc,low, recursion stack).
6.7 Conclusion
- Tarjan's algorithm computes subtree reachability metrics (
lowanddisc) in a single DFS pass, finding all single points of network failure in time.
7. Practical 7: Number of Islands (8-Directional DFS)
7.1 Aim
- Given an grid consisting of
'0'(Water) and'1'(Land), find the number of disconnected islands (connected land cells in all 8 directions).
7.2 Theory & Core Concepts
- Graph Modeling: Treat every grid cell as a vertex. An island is a connected component of land cells (
1) connected horizontally, vertically, or diagonally (8 adjacent neighbours). - Flood Fill Strategy:
- Sequentially iterate over every grid cell .
- When encountering an unvisited
1, increment the island counter. - Trigger recursive DFS to sink/visit all reachable cells across all 8 offset directions:
7.3 Algorithm
- Start.
- Read grid dimensions and populate
grid[N][M]. - Initialize
visited[N][M] = falseandcount = 0. - Loop through row from 0 to :
- Loop through col from 0 to :
- If
grid[i][j] == 1and!visited[i][j]:- Increment
count++. - Execute
dfs(grid, visited, i, j, N, M).
- Increment
- If
- Loop through col from 0 to :
- Inside
dfs(row, col):- If
row < 0 || row >= N || col < 0 || col >= M, return. - If
grid[row][col] == 0 || visited[row][col], return. - Mark
visited[row][col] = true. - Recursively call
dfson all 8 neighbours:- Top-Left, Up, Top-Right, Left, Right, Bottom-Left, Down, Bottom-Right.
- If
- Print
countas total islands. - End.
7.4 Java Implementation
import java.util.Scanner;
public class Main {
static void dfs(int[][] grid, boolean[][] visited, int row, int col, int n, int m) {
if (row < 0 || row >= n || col < 0 || col >= m)
return;
if (grid[row][col] == 0 || visited[row][col])
return;
visited[row][col] = true;
dfs(grid, visited, row - 1, col - 1, n, m);
dfs(grid, visited, row - 1, col, n, m);
dfs(grid, visited, row - 1, col + 1, n, m);
dfs(grid, visited, row, col - 1, n, m);
dfs(grid, visited, row, col + 1, n, m);
dfs(grid, visited, row + 1, col - 1, n, m);
dfs(grid, visited, row + 1, col, n, m);
dfs(grid, visited, row + 1, col + 1, n, m);
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] grid = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
boolean[][] visited = new boolean[n][m];
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == 1 && !visited[i][j]) {
count++;
dfs(grid, visited, i, j, n, m);
}
}
}
System.out.println(count);
sc.close();
}
}
7.5 Sample Input & Output
- Input:
4 40 1 0 10 1 0 10 1 0 10 1 0 1
- Output:
2
7.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Scanning all grid cells | ||
| Exploring 8 neighbours per land cell | ||
| Marking visited states | ||
| Island increment count () | ||
| Total Operations |
- Time Complexity: since each cell is entered and processed a constant number of times.
- Space Complexity: for the
visitedmatrix and worst-case call stack.
7.7 Conclusion
- Recursive flood fill on an 8-connected grid identifies connected components in linear time relative to matrix area.
8. Practical 8: Rotting Oranges (Multi-Source BFS)
8.1 Aim
- Given a matrix
mat[][]where 0: Empty, 1: Fresh orange, 2: Rotten orange. Fresh oranges rot if adjacent (up, down, left, right) to a rotten orange (takes 1 unit time). Determine minimum time to rot all oranges, or return -1 if impossible.
8.2 Theory & Core Concepts
- Multi-Source Breadth-First Search (BFS):
- All initially rotten oranges begin spreading infection at time simultaneously.
- Insert all initial positions with value 2 into a
Queue. - Count total fresh oranges.
- Process queue level-by-level; each completed level represents 1 elapsed unit of time.
- For each rotten cell, infect unvisited fresh 4-neighbours, decrement the fresh counter, and push them to the queue.
- If fresh oranges remain after queue exhaustion, return -1.
8.3 Algorithm
- Start.
- Read dimensions and grid matrix.
- Initialize
Queue<int[]>,fresh = 0,time = 0. - Enqueue every cell with value 2; count cells with value 1 as
fresh. - Direction offsets: , .
- While
!q.isEmpty()andfresh > 0:size = q.size().- While
size-- > 0:- Pop
cur = q.poll(). - For to 3:
- , .
- If are valid and
grid[x][y] == 1:grid[x][y] = 2.fresh--.- Enqueue .
- Pop
time++.
- Output
fresh == 0 ? time : -1. - End.
8.4 Java Implementation
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int[][] grid = new int[m][n];
Queue<int[]> q = new LinkedList<>();
int fresh = 0, time = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
grid[i][j] = sc.nextInt();
if (grid[i][j] == 2) q.offer(new int[]{i, j});
else if (grid[i][j] == 1) fresh++;
}
}
int[] dx = {-1, 1, 0, 0};
int[] dy = {0, 0, -1, 1};
while (!q.isEmpty() && fresh > 0) {
int size = q.size();
while (size-- > 0) {
int[] cur = q.poll();
for (int k = 0; k < 4; k++) {
int x = cur[0] + dx[k];
int y = cur[1] + dy[k];
if (x >= 0 && y >= 0 && x < m && y < n && grid[x][y] == 1) {
grid[x][y] = 2;
fresh--;
q.offer(new int[]{x, y});
}
}
}
time++;
}
System.out.println(fresh == 0 ? time : -1);
}
}
8.5 Sample Input & Output
- Input:
2 32 1 00 0 1
- Output:
-1
8.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Matrix scan and queue initialization | ||
| Queue insertion / deletion | ||
| Four-neighbour boundary checking | ||
| Total Operations |
- Time Complexity: since every cell is visited at most once.
- Space Complexity: to store cell coordinates in the queue.
8.7 Conclusion
- BFS level-order traversal simulates concurrent infection waves across graph topologies, identifying reachability and distance in linear time.
9. Practical 9: Minimum Edit Distance (Dynamic Programming)
9.1 Aim
- Given two strings
str1andstr2, find the minimum number of edit operations (Insert, Remove, Replace) required to convertstr1intostr2. Each operation has equal unit cost.
9.2 Theory & Core Concepts
- Subproblem Definition: Let
dp[i][j]denote the minimum edits required to convert prefixstr1[0..i-1]into prefixstr2[0..j-1]. - Base Conditions:
dp[i][0] = i(converting string of length to empty string requires deletions).dp[0][j] = j(converting empty string to string of length requires insertions).
- Recurrence Relation:
- If characters match (
str1[i-1] == str2[j-1]): - If characters differ:
- If characters match (
9.3 Algorithm
- Start.
- Read strings
str1andstr2, with lengths and . - Allocate table
dp[m + 1][n + 1]. - For to , set
dp[i][0] = i. - For to , set
dp[0][j] = j. - For to :
- For to :
- If
str1.charAt(i - 1) == str2.charAt(j - 1):dp[i][j] = dp[i - 1][j - 1].
- Else:
dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i][j - 1], dp[i - 1][j - 1])).
- If
- For to :
- Output
dp[m][n]. - End.
9.4 Java Implementation
import java.util.Scanner;
public class string {
public static int minSteps(String str1, String str2) {
int m = str1.length();
int n = str2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j],
Math.min(dp[i][j - 1],
dp[i - 1][j - 1])) + 1;
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter the first string: ");
String str1 = scanner.nextLine();
System.out.print("Enter the second string: ");
String str2 = scanner.nextLine();
scanner.close();
int result = minSteps(str1, str2);
System.out.println("Minimum steps required: " + result);
}
}
9.5 Sample Input & Output
- Input:
Enter the first string: My GodEnter the second string: impossible
- Output:
Minimum steps required: 10
9.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Base case initialization | ||
| Cell character comparisons | ||
| Three-way minimum selection | ||
| Total Operations |
- Time Complexity: where and are the lengths of the strings.
- Space Complexity: table space.
9.7 Conclusion
- Dynamic programming resolves overlapping alignment choices in time, replacing naive exponential recursive search.
10. Practical 10: Minimum Path Sum (Dynamic Programming)
10.1 Aim
- Given an grid filled with non-negative integers, find a path from top-left to bottom-right that minimizes the sum of numbers along the path. Permitted movements are only Right and Down.
10.2 Theory & Core Concepts
- Optimal Substructure: The minimum path cost to arrive at cell depends solely on the minimum cost to arrive at its immediate predecessors: top cell and left cell .
- Dynamic Programming Formulation:
- Starting position:
- First row (only rightward moves possible):
- First column (only downward moves possible):
- General cell :
10.3 Algorithm
- Start.
- Read grid dimensions and elements of
grid[n][m]. - Allocate
dp[n][m]. - Set
dp[0][0] = grid[0][0]. - Initialize first row: For to ,
dp[0][j] = dp[0][j - 1] + grid[0][j]. - Initialize first column: For to ,
dp[i][0] = dp[i - 1][0] + grid[i][0]. - For to :
- For to :
dp[i][j] = grid[i][j] + Math.min(dp[i - 1][j], dp[i][j - 1]).
- For to :
- Output
dp[n - 1][m - 1]. - Stop.
10.4 Java Implementation
import java.util.Scanner;
public class MinimumPathSum {
public static int minPathSum(int[][] grid) {
int n = grid.length;
int m = grid[0].length;
int[][] dp = new int[n][m];
dp[0][0] = grid[0][0];
for (int j = 1; j < m; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for (int i = 1; i < n; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int i = 1; i < n; i++) {
for (int j = 1; j < m; j++) {
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1])
+ grid[i][j];
}
}
return dp[n - 1][m - 1];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter number of rows: ");
int n = sc.nextInt();
System.out.print("Enter number of columns: ");
int m = sc.nextInt();
int[][] grid = new int[n][m];
System.out.println("Enter the grid elements:");
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
grid[i][j] = sc.nextInt();
}
}
int result = minPathSum(grid);
System.out.println("Minimum path sum: " + result);
sc.close();
}
}
10.5 Sample Input & Output
- Input:
Enter number of rows: 3Enter number of columns: 3Enter the grid elements:1 3 11 5 14 2 1
- Output:
Minimum path sum: 7
10.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Base cell initialization | 1 | |
| First row initialization | ||
| First column initialization | ||
| Inner cell DP transitions | ||
| Total Operations | — |
- Time Complexity: .
- Space Complexity: for the 2D DP matrix.
10.7 Conclusion
- Grid DP tabulation efficiently evaluates non-branching optimal pathways by memoizing cumulative path prefixes, guaranteeing global optimality in polynomial time.
11. Practical 11: Remove K Digits (Monotonic Stack & Greedy)
11.1 Aim
- Given string
numrepresenting a non-negative integer and an integer , return the smallest possible integer after removing digits fromnum.
11.2 Theory & Core Concepts
- Greedy Principle: A smaller leading digit yields a smaller overall numerical value regardless of succeeding digits (e.g., is always smaller than ).
- Monotonic Increasing Stack:
- Traverse digits from left to right.
- While the stack is non-empty, remaining removal quota , and the top of the stack is strictly greater than the current digit:
- Pop the top digit and decrement .
- Push the current digit onto the stack.
- Corner Cases:
- If after full traversal, truncate digits from the top of the stack.
- Strip leading zeros from the final result.
- If all digits are eliminated, return
"0".
11.3 Algorithm
- Start.
- Read string
numand integer . - Allocate character
Stack<Character> stack. - For each character
digitinnum:- While
!stack.isEmpty()and andstack.peek() > digit:stack.pop().k--.
stack.push(digit).
- While
- While :
stack.pop().k--.
- Build string from stack contents and remove leading
'0'characters. - If resulting string length is 0, return
"0". - Output formatted string.
- Stop.
11.4 Java Implementation
import java.util.Scanner;
import java.util.Stack;
public class RemoveKDigits {
public static String removeKdigits(String num, int k) {
Stack<Character> stack = new Stack<>();
for (char digit : num.toCharArray()) {
while (!stack.isEmpty() && k > 0 &&
stack.peek() > digit) {
stack.pop();
k--;
}
stack.push(digit);
}
while (k > 0) {
stack.pop();
k--;
}
StringBuilder result = new StringBuilder();
for (char digit : stack) result.append(digit);
int i = 0;
while (i < result.length() && result.charAt(i) == '0') i++;
result = new StringBuilder(result.substring(i));
if (result.length() == 0) return "0";
return result.toString();
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter the number: ");
String num = sc.next();
System.out.print("Enter the number of digits to remove: ");
int k = sc.nextInt();
String result = removeKdigits(num, k);
System.out.println("Smallest possible integer: " + result);
sc.close();
}
}
11.5 Sample Input & Output
- Input:
Enter the number: 4592452840572141413471304981790348Enter the number of digits to remove: 27
- Output:
Smallest possible integer: 10348
11.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| Scanning input digits | ||
| Stack push operations | ||
| Stack pop operations | ||
| Result reconstruction and zero stripping | ||
| Total Operations | — |
- Time Complexity: because each digit is pushed and popped at most once.
- Space Complexity: auxiliary stack space.
11.7 Conclusion
- Monotonic stacks resolve inversion order constraints in linear time by enforcing immediate greedy elimination of locally sub-optimal digits.
12. Practical 12: Unique Paths (Dynamic Programming)
12.1 Aim
- A robot is located at the top-left corner of an grid. The robot can only move either down or right at any point. Find the total number of unique paths to reach the bottom-right corner.
12.2 Theory & Core Concepts
- Combinatorial / DP Modeling:
- To arrive at cell , the robot can only come directly from the top cell or left cell .
- Total unique paths satisfies the recurrence:
- Boundary Base Cases:
- The first row for all (only moving right).
- The first column for all (only moving down).
- Analytical Closed Form (Total Paths):
12.3 Algorithm
- Start.
- Read grid dimensions (rows) and (columns).
- Create 2D table
dp[m][n]. - Initialize
dp[i][0] = 1for all . - Initialize
dp[0][j] = 1for all . - For to :
- For to :
dp[i][j] = dp[i - 1][j] + dp[i][j - 1].
- For to :
- Output
dp[m - 1][n - 1]. - Stop.
12.4 Java Implementation
import java.util.Scanner;
public class UniquePaths {
public static int uniquePaths(int m, int n) {
int[][] dp = new int[m][n]; s
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Enter number of rows: ");
int m = sc.nextInt();
System.out.print("Enter number of columns: ");
int n = sc.nextInt();
int result = uniquePaths(m, n);
System.out.println("Number of unique paths: " + result);
sc.close();
}
}
12.5 Sample Input & Output
- Input:
Enter number of rows: 3Enter number of columns: 7
- Output:
Number of unique paths: 28
12.6 Complexity & Frequency Analysis
| Operation | Frequency | Complexity |
|---|---|---|
| First row initialization | ||
| First column initialization | ||
| Cell additions | ||
| Total Operations | — |
- Time Complexity: .
- Space Complexity: table memory (can be space-optimized to with a 1D buffer).
12.7 Conclusion
- Grid path counting decomposes into overlapping subproblems governed by Pascal's triangle identity, solved via DP tabulation in time.