Unit6 - Subjective Questions
CSE357 • Practice Questions with Detailed Answers
Define an Algorithm and explain the five essential characteristics that every algorithm must satisfy.
An Algorithm is a finite sequence of well-defined, computer-implementable instructions, typically to solve a class of problems or to perform a computation.
Essential Characteristics:
- Input: An algorithm has zero or more inputs, taken from a specified set of objects.
- Output: An algorithm has one or more outputs, which have a specified relation to the inputs.
- Definiteness: Each step of the algorithm must be precisely defined; the actions to be carried out must be rigorously and unambiguously specified for each case.
- Finiteness: An algorithm must always terminate after a finite number of steps. If it runs forever, it is a computational method, not an algorithm.
- Effectiveness: All operations to be performed must be sufficiently basic that they can in principle be done exactly and in a finite length of time by a person using paper and pencil.
Distinguish between A Priori Analysis and A Posteriori Analysis of algorithms.
A Priori Analysis (Theoretical Analysis):
- Definition: It is a determination of the order of magnitude of a statement execution count (time complexity) or space requirement before running the algorithm.
- Dependency: It is independent of the underlying hardware and programming language.
- Focus: It uses asymptotic notations (like Big-O) to describe the algorithm's efficiency as a function of input size .
A Posteriori Analysis (Empirical Analysis):
- Definition: It involves implementing the algorithm using a specific programming language and executing it on a specific machine.
- Dependency: It is highly dependent on hardware (processor speed, memory), compiler, and operating system.
- Focus: It collects actual statistics like running time (in seconds) and memory consumption (in bytes).
Explain the concept of Asymptotic Notation. Define Big-O notation () formally and provide its geometric interpretation.
Asymptotic Notation is a mathematical tool used to represent the time or space complexity of algorithms for large input sizes. It describes the limiting behavior of a function when the argument tends towards a particular value or infinity.
Big-O Notation ()
Definition: Let and be functions mapping non-negative integers to real numbers. We say that is (read as "big-oh of g of n") if there exist positive constants and such that:
Geometric Interpretation:
- acts as an upper bound on the growth of .
- For all input sizes greater than , the value of is always on or below the curve .
- It is typically used to describe the worst-case scenario of an algorithm.
Define Big-Omega () and Big-Theta () notations. How do they differ from Big-O?
Big-Omega ()
Definition: if there exist positive constants and such that:
- Meaning: It provides an asymptotic lower bound. It denotes that the algorithm will take at least this much time.
Big-Theta ()
Definition: if there exist positive constants and such that:
- Meaning: It provides an asymptotic tight bound. The function grows at the same rate as .
Difference from Big-O:
- Big-O (): Upper bound (Worst case typically). "Algorithm takes at most this much time."
- Big-Omega (): Lower bound (Best case typically). "Algorithm takes at least this much time."
- Big-Theta (): Tight bound (Average/Exact fit). "Algorithm takes exactly this order of time."
Given the function , prove that .
To prove , we need to find positive constants and such that:
Derivation:
- Since , we know that and .
- We can rewrite the inequality:
- Combine terms:
- Therefore, if we choose and , the condition holds.
Conclusion:
Since for all , by definition, .
Discuss the Best Case, Worst Case, and Average Case analysis of an algorithm. Why is the Worst Case often the most important?
Types of Cases:
- Best Case: The specific input configuration for which the algorithm performs the minimum number of steps. It defines the lower bound of time complexity.
- Average Case: The expected behavior of the algorithm over all possible inputs of size , weighted by the probability of those inputs occurring. It is often harder to calculate as it requires knowledge of input distribution.
- Worst Case: The specific input configuration for which the algorithm performs the maximum number of steps. It defines the upper bound ().
Importance of Worst Case:
- Guarantee: It provides a guarantee that the algorithm will never take longer than this time, which is critical for real-time systems.
- Design Benchmark: It allows software engineers to design systems based on peak load capacity.
- Frequency: In some algorithms (like searching unsorted databases), the worst-case scenario (item not found) occurs frequently.
Arrange the following functions in increasing order of their Rate of Growth: , , , , , , .
To arrange them, we compare how fast increases as .
Analysis:
- (Polynomial < 1)
- (Linear)
- (Log-linear)
- (By Stirling's approximation)
- (Quadratic)
- (Exponential)
- (Factorial)
Correct Order (Slowest to Fastest Growth):
Note: While , usually simple polynomial terms are listed before logarithmic factorial approximations if strictly ordering classes, but they are asymptotically tight.
What is Recursion? Explain the mechanics of a recursive call using the stack memory, citing the concept of a 'Base Case'.
Recursion is a programming technique where a function calls itself to solve a smaller instance of the problem.
Components:
- Base Case: The condition under which the recursion stops. Without this, the function would call itself indefinitely (infinite recursion) leading to a stack overflow.
- Recursive Step: The part where the function calls itself with modified arguments moving towards the base case.
Mechanics (Stack Memory):
- When a recursive call is made, the current state of the function (local variables, return address) is pushed onto the Call Stack (Activation Record).
- The control transfers to the new function call.
- This process continues until the Base Case is reached.
- Once the base case returns a value, the stack pops the top frame, returning control and the result to the previous caller.
- This unwinding continues until the original call returns the final result.
Explain the Backtracking algorithmic strategy. How does it differ from Brute Force?
Backtracking is a general algorithmic technique that considers searching every possible combination in order to solve a computational problem.
Core Concept:
- It builds candidates for the solution incrementally.
- It abandons a candidate ("backtracks") as soon as it determines that the candidate cannot possibly be completed to a valid solution.
- It typically uses a Depth-First Search (DFS) on the state-space tree.
Difference from Brute Force:
- Brute Force: Generates all possible solutions and checks each one to see if it satisfies the constraints. It visits every leaf node of the state-space tree.
- Backtracking: Uses bounding functions (constraints). If a partial solution violates a constraint, it prunes the whole subtree rooted at that node. It is essentially "Brute Force with Pruning," making it significantly more efficient.
Analyze the recurrence relation using the Master Theorem. What standard algorithm has this time complexity?
The Master Theorem solves recurrences of the form .
Given:
- (number of subproblems)
- (factor by which input size decreases)
- (cost of dividing/merging)
Steps:
- Calculate .
- Compare with .
- Here, and . They are equal.
- This falls under Case 2 of the Master Theorem: If , then .
Result:
Standard Algorithm: This is the time complexity of Merge Sort.
Describe the Dynamic Programming (DP) strategy. What are the two key properties a problem must possess to be solved efficiently using DP?
Dynamic Programming is an optimization technique used to solve complex problems by breaking them down into simpler overlapping subproblems. Unlike recursion, DP stores the results of subproblems to avoid re-computing them.
Key Properties:
-
Optimal Substructure:
- A problem exhibits optimal substructure if an optimal solution to the problem contains within it optimal solutions to subproblems.
- Example: In shortest path problems, the shortest path from A to C via B implies the path A to B is also the shortest.
-
Overlapping Subproblems:
- The recursive algorithm visits the same subproblems repeatedly.
- DP solves each subproblem only once and stores the result in a table (Memoization or Tabulation).
- Example: Calculating Fibonacci numbers recursively computes multiple times.
Compare and contrast Memoization (Top-Down) and Tabulation (Bottom-Up) approaches in Dynamic Programming.
Both are techniques to store results of subproblems in Dynamic Programming.
| Feature | Memoization (Top-Down) | Tabulation (Bottom-Up) |
|---|---|---|
| Approach | Starts with the main problem and breaks it down recursively. | Starts with the smallest subproblems and iteratively builds up to the main problem. |
| State | Recursive. Results are stored in a lookup table when computed for the first time. | Iterative. The table is filled in a specific order (e.g., usually 0 to n). |
| Table Entries | Only fills entries that are actually needed for the solution. | Fills all entries in the table, even if some are not needed for the final answer. |
| Overhead | Recursive call stack overhead exists. | No recursion overhead; faster in practice for dense problems. |
| Ease | Often easier to implement if the recurrence relation is complex. | Avoids stack overflow errors for deep recursion trees. |
Explain the Greedy Algorithm paradigm. What is the 'Greedy Choice Property'?
Greedy Algorithms build up a solution piece by piece, always choosing the next piece that offers the most immediate and obvious benefit.
Core Philosophy:
It makes a locally optimal choice at each step with the hope that these choices will lead to a globally optimal solution. It does not backtrack or revise previous choices.
Greedy Choice Property:
- This property states that a global optimum can be arrived at by selecting a local optimum.
- We make the choice that looks best in the current moment without considering results from subproblems.
- Contrast with DP: DP considers solutions to subproblems before making a choice; Greedy makes a choice before solving subproblems.
Distinguish between Greedy Algorithms and Dynamic Programming.
| Feature | Greedy Algorithms | Dynamic Programming |
|---|---|---|
| Decision Type | Makes the optimal choice at each step (Locally Optimal). | Makes a decision based on the results of all subproblems (Globally Optimal consideration). |
| Optimality | Does not guarantee an optimal solution for all problems (e.g., 0/1 Knapsack). | Guarantees an optimal solution if the principle of optimality holds. |
| Efficiency | Generally faster and simpler; usually linear or log-linear time. | Generally slower; requires more memory for tables ( or higher usually). |
| Backtracking | Never reconsiders previous choices. | Considers all possible sub-cases (essentially checking all options smartly). |
| Example | Fractional Knapsack, Prim's Algorithm. | 0/1 Knapsack, Longest Common Subsequence. |
Describe the Fractional Knapsack Problem and explain why it can be solved using a Greedy strategy, whereas the 0/1 Knapsack problem cannot.
Fractional Knapsack Problem:
Given items with weights and values , and a knapsack of capacity , maximize the total value. You can break items to take a fraction of them.
Greedy Strategy:
- Calculate value-to-weight ratio () for all items.
- Sort items descending by this ratio.
- Add items until the bag is full. If the last item doesn't fit, take the fraction that fits.
Why Greedy works for Fractional but not 0/1:
- Fractional: The greedy choice (taking the densest item) is always safe because you can fill the remaining "gap" with a fraction of the next best item. There is no "wasted space" penalty.
- 0/1 Knapsack: You either take the item or leave it. Taking the item with the highest ratio might leave a small empty space that cannot be filled by any other item, whereas a combination of items with lower ratios might fill the bag perfectly and yield a higher total value. The greedy choice might prevent reaching the global optimum.
Provide an overview of the Activity Selection Problem. How does the Greedy approach solve it?
Problem Definition:
Given a set of activities, each with a start time and finish time , select the maximum number of activities that can be performed by a single person/resource, assuming that the person can only work on one activity at a time.
Greedy Strategy:
- Sort: Sort all activities in increasing order of their finish times ().
- Select: Select the first activity (the one that finishes earliest).
- Iterate: For the remaining sorted activities, select the next activity only if its start time is greater than or equal to the finish time of the previously selected activity ().
Why it works: Choosing the activity that finishes earliest leaves the maximum amount of remaining time for other activities.
Explain the N-Queens Problem. How is Backtracking used to solve it?
Problem: Place queens on an chessboard such that no two queens attack each other (i.e., no two queens share the same row, column, or diagonal).
Backtracking Solution:
- Start in the leftmost column.
- If all queens are placed, return true.
- Try all rows in the current column.
- For each row, check if the queen can be placed safely:
- Check row on the left side.
- Check upper diagonal on left side.
- Check lower diagonal on left side.
- If safe, place the queen and recursively check for the rest of the queens in the next column.
- Backtrack Step: If placing the queen leads to no solution (recursive call returns false), remove the queen from the current cell (backtrack) and try the next row.
What is the Fibonacci Series? Derive the time complexity of the naive recursive solution vs. the Dynamic Programming solution.
Fibonacci Series: for , with .
Naive Recursive Solution:
- Code:
return fib(n-1) + fib(n-2) - Analysis: Each call branches into two. This creates a binary tree of depth .
- Complexity: (Exponential). Specifically where is the Golden Ratio.
- Issue: Massive re-computation of overlapping subproblems.
Dynamic Programming Solution (Memoization/Tabulation):
- Strategy: Store calculated values in an array
arr[0...n]. - Analysis: We compute each value from to exactly once.
- Complexity: (Linear).
- Space: (can be optimized to space by storing only last two values).
Define Little-o () and Little-omega () notation. How do they relate to strict inequality?
Little-o notation ()
- Definition: if for any positive constant , there exists an such that for all .
- Strict Inequality: It implies becomes insignificant relative to as grows. Algebraically: .
- Analogy: .
Little-omega notation ()
- Definition: if for any positive constant , there exists an such that for all .
- Strict Inequality: It implies grows strictly faster than . Algebraically: .
- Analogy: .
Analyze the time complexity of the following code snippet:
To determine the complexity, we count how many times the print statement executes.
- Outer Loop: Runs for .
- Inner Loop: Runs for to . So, it runs times for each iteration of the outer loop.
Total Executions:
Sum of for from $1$ to :
Sum of Arithmetic Series:
Asymptotic Analysis:
The term with the highest degree is .
Therefore, the time complexity is .