0% found this document useful (0 votes)
6 views18 pages

Python Revision Question Bank

The document is a comprehensive question bank for a Python and Algorithms course, covering topics such as algorithms, data structures, and coding practices over eight weeks. It includes multiple-choice questions (MCQs), theoretical questions, and coding exercises designed to reinforce understanding of concepts like GCD, recursion, sorting algorithms, and file I/O. Each week builds on the previous one, gradually introducing more complex topics and practical applications in bioinformatics.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views18 pages

Python Revision Question Bank

The document is a comprehensive question bank for a Python and Algorithms course, covering topics such as algorithms, data structures, and coding practices over eight weeks. It includes multiple-choice questions (MCQs), theoretical questions, and coding exercises designed to reinforce understanding of concepts like GCD, recursion, sorting algorithms, and file I/O. Each week builds on the previous one, gradually introducing more complex topics and practical applications in bioinformatics.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Python & Algorithms

Complete Revision Question Bank


Based on Programming, Data Structures & Algorithms in Python — Prof. Madhavan Mukund

8 Weeks • 45 Lectures • MCQ + Coding + Theory


Week 1 — Algorithms & GCD (Lectures 1–4)
This week introduces the core idea of what an algorithm is, then builds intuition through the GCD problem —
going from a naive brute-force approach all the way to Euclid's elegant recursive solution. The key insight is that
every improvement reduces the search space, and that Python's syntax is just a formal way of expressing these
ideas.

MCQ Questions
Q1. What is the defining characteristic of an algorithm?
• A) It must run on a computer
• B) It is a finite sequence of steps to solve a problem
• C) It must be written in Python
• D) It must always produce a numerical output
💡 Hint: Think about the recipe analogy from Lecture 1. A recipe can be followed by a person too.
Q2. In the naive GCD algorithm, why do we only check divisors up to min(m, n) rather than up to m?
• A) To reduce memory usage
• B) Because no number larger than min(m,n) can divide both m and n
• C) Because Python can only handle small numbers
• D) To avoid floating point errors
💡 Hint: A common divisor must divide both numbers. What's the largest it could be?
Q3. What is the time complexity of the naive GCD algorithm that checks all divisors?
• A) O(log n)
• B) O(n)
• C) O(n²)
• D) O(1)
Q4. In Euclid's algorithm, gcd(m, n) = gcd(n, m mod n). What is the base case?
• A) When m equals 1
• B) When m mod n equals 0, return n
• C) When m is greater than n
• D) When n equals 0, return m
💡 Hint: What condition tells us we've found the GCD? When the remainder becomes 0, n is the answer.
Q5. Which statement about Python's assignment statement is true?
• A) A variable must be declared before assignment
• B) Assignment binds a name to a value
• C) You can only assign integers
• D) Assignment creates a copy of the object

Theory / Written Questions


Q6. Explain in your own words why Euclid's algorithm is more efficient than the naive GCD approach. Use the
example gcd(14, 63) to illustrate.
💡 Hint: Walk through both approaches step by step. How many steps does each take? What property does Euclid exploit?
Q7. What does it mean for an algorithm to 'terminate'? Why is termination important, and how do we know
Euclid's algorithm always terminates?
💡 Hint: The remainder m mod n is strictly smaller than n each time. Why does this guarantee termination?
Coding Questions
Q8. Write a Python function that computes GCD using Euclid's algorithm. Then write a second version using a
while loop instead of recursion.
def gcd_recursive(m, n): # Your code here pass def gcd_iterative(m, n): #
Your code here — use while pass
💡 Hint: The recursive version is 2–3 lines. The iterative version replaces the recursive call with a loop that updates m and
n each iteration.
Q9. Write a function that returns a list of all common divisors of m and n (not just the greatest).
def common_divisors(m, n): # Return a list of all common divisors pass
Week 2 — Types, Strings, Lists, Control Flow, Functions
(Lectures 5–10)
Week 2 is the practical foundation of everything else. Understanding the difference between mutable lists and
immutable strings, how Python handles assignment vs. mutation, and how functions scope their variables —
these are concepts that trip up intermediate programmers constantly. Pay special attention to the list aliasing
behaviour.

MCQ Questions
Q10. What is the output of the following code? s = 'ATGCGT' s[2] = 'A'
• A) 'ATAAGT'
• B) 'ATGCGT' (unchanged)
• C) TypeError: 'str' object does not support item assignment
• D) IndexError
💡 Hint: Strings in Python are immutable — you cannot change them in place.
Q11. What is the difference between == and is in Python?
• A) They are identical
• B) == checks value equality; is checks identity (same object in memory)
• C) is checks value; == checks type
• D) == only works on numbers
Q12. What does list1 = list2 do in Python?
• A) Creates a deep copy of list2
• B) Makes list1 an independent copy
• C) Makes list1 point to the same object as list2
• D) Concatenates the two lists
💡 Hint: This is aliasing. Both names point to the same list — modifying one modifies the other.
Q13. What is the output of: list1 = [1,3,5]; list2 = list1; list1 = list1 + [7]; print(list2)?
• A) [1, 3, 5, 7]
• B) [1, 3, 5]
• C) []
• D) Error
💡 Hint: The + operator creates a NEW list and rebinds list1 to it. list2 still points to the original.
Q14. Which of the following correctly defines a recursive factorial function?
• A) def fact(n): return n * fact(n)
• B) def fact(n): if n == 0: return 1; else: return n * fact(n-1)
• C) def fact(n): return n * (n-1)
• D) def fact(n): return fact(n) * fact(n-1)

Theory / Written Questions


Q15. Explain the concept of mutability in Python. Why are strings immutable but lists mutable? Give one
example each of where this distinction matters in a bioinformatics context.
Q16. What is the difference between a parameter and an argument? Describe how Python passes arguments
to functions — is it pass-by-value or pass-by-reference?
💡 Hint: Python is 'pass by object reference'. The behaviour differs depending on whether the object is mutable.
Coding Questions
Q17. Write a function that takes a DNA string and returns the reverse complement. Remember: A↔T and
G↔C, and the complement is reversed.
def reverse_complement(dna): # complement: A->T, T->A, G->C, C->G # then reverse
the result pass # Test: reverse_complement('ATGC') should return 'GCAT'
💡 Hint: Use a dictionary for the complement mapping, a list comprehension to apply it, then ''.join() and [::-1].
Q18. Write a function that takes a list of sequences and returns only those with GC content above a given
threshold. Use a for loop, then rewrite using a list comprehension.
def filter_by_gc(sequences, threshold): # Version 1: for loop pass def
filter_by_gc_v2(sequences, threshold): # Version 2: list comprehension (one line)
pass
Week 3 — Sorting, Binary Search, Recursion (Lectures 11–18)
This week is where algorithmic thinking really kicks in. Binary search is the first example of a divide-and-conquer
strategy — cutting the problem in half each time. Selection and insertion sort are O(n²) but important to
understand because they build intuition for why better algorithms are needed. Recursion is introduced properly
here and is the gateway to everything in Weeks 4, 6, 7, and 8.

MCQ Questions
Q19. Binary search requires that the input list is:
• A) A linked list
• B) Sorted in ascending order
• C) Stored in a dictionary
• D) Of even length
Q20. What is the time complexity of binary search?
• A) O(n)
• B) O(n²)
• C) O(log n)
• D) O(1)
💡 Hint: Each step halves the search space. How many times can you halve n before reaching 1?
Q21. Why can't binary search be used on a Python list accessed sequentially?
• A) Because lists are unordered
• B) Because computing the midpoint requires random access in O(1) time, which lists don't support
• C) Because lists don't support comparison
• D) It can — binary search works fine on lists
💡 Hint: Arrays support O(1) indexing. Regular linked lists do not. Python lists are actually arrays under the hood, but the
lecture makes this distinction important.
Q22. What is the worst-case time complexity of Selection Sort?
• A) O(n log n)
• B) O(n)
• C) O(n²)
• D) O(log n)
Q23. In a recursion, what prevents infinite loops?
• A) Python's garbage collector
• B) A base case that returns without making another recursive call
• C) The recursion limit set by sys
• D) Using while instead of for

Theory / Written Questions


Q24. Compare Selection Sort and Insertion Sort. Which is better in practice? Are there cases where Insertion
Sort performs better than O(n²)? Explain with an example.
💡 Hint: Think about nearly-sorted data. Insertion sort can be O(n) in the best case.
Q25. Explain what happens in Python's call stack when a recursive function calls itself. What is a recursion
limit, and why does Python impose one?
Coding Questions
Q26. Implement binary search to find a target value in a sorted list of genomic positions. Return the index if
found, -1 if not.
def binary_search(positions, target): lo, hi = 0, len(positions) - 1 # Your code
here pass # Test: binary_search([100, 250, 380, 490, 720], 380) → 2
Q27. Implement Selection Sort. Then trace through the array [64, 25, 12, 22, 11] step by step to show each
swap.
def selection_sort(arr): # For each position, find the minimum in the remaining #
unsorted portion and swap it into place pass
Q28. Write a recursive function to compute the nth Fibonacci number. Then identify the problem with this
approach and describe how you'd fix it.
def fib(n): # Base cases: fib(0) = 0, fib(1) = 1 pass # What goes wrong for
large n? How would memoization help?
💡 Hint: Count how many times fib(3) gets computed when you call fib(5). The redundancy explodes exponentially — this
connects directly to Week 8's memoization.
Week 4 — Mergesort, Quicksort, Tuples, Dicts, List
Comprehension (Lectures 19–25)
Week 4 bridges efficient sorting with Python's most powerful data structures. Mergesort and Quicksort are both
O(n log n) average, but for different reasons — and Quicksort's worst-case O(n²) is critical to understand.
Dictionaries are central to bioinformatics (codon tables, genome annotations) and list comprehensions make
filtering genomic data elegant and concise.

MCQ Questions
Q29. What is the average-case time complexity of Quicksort?
• A) O(n²)
• B) O(n log n)
• C) O(log n)
• D) O(n)
Q30. When does Quicksort degrade to O(n²)?
• A) When the input is random
• B) When the pivot always ends up being the minimum or maximum element
• C) When the list has duplicates
• D) When the list has more than 1000 elements
💡 Hint: Think about what happens when you pick the first element as pivot on an already-sorted list.
Q31. What is the key difference between a tuple and a list in Python?
• A) Tuples can only hold numbers
• B) Tuples are immutable; lists are mutable
• C) Lists are faster
• D) Tuples cannot be iterated
Q32. What does the expression [x*2 for x in range(5) if x % 2 == 0] evaluate to?
• A) [0, 2, 4, 6, 8]
• B) [0, 4, 8]
• C) [2, 4]
• D) [0, 2, 4]
💡 Hint: First filter: x must be even (0, 2, 4). Then double each: 0, 4, 8.
Q33. How do you check if a key exists in a dictionary d?
• A) [Link]('key')
• B) 'key' in d
• C) [Link]('key')
• D) d['key'] exists

Theory / Written Questions


Q34. Mergesort is always O(n log n) while Quicksort is O(n log n) on average. Given this, why is Quicksort
often preferred in practice? What technique mitigates Quicksort's worst case?
Q35. A codon table maps 3-letter DNA codons to amino acids. Describe how you would represent this in
Python using a dictionary, and write pseudocode to translate a DNA sequence into a protein string.
Coding Questions
Q36. Implement Mergesort. Make sure you understand the merge step — this exact logic appears in sequence
alignment.
def merge(left, right): # Merge two sorted lists into one sorted list # This is
O(n) — scan both lists simultaneously pass def mergesort(arr): # Base case:
length 0 or 1 is already sorted # Recursive case: split, sort each half, merge
pass
💡 Hint: The merge step is like a two-pointer technique: compare the front of each list and take the smaller element.
Q37. Build a codon frequency counter. Given a DNA coding sequence, return a dictionary of how often each
codon appears.
def codon_frequency(dna): # Split sequence into codons (triplets) # Count each
codon using a dictionary # Return the frequency dict pass # Test:
codon_frequency('ATGATGATG') → {'ATG': 3}
Week 5 — File I/O, Strings, Exceptions (Lectures 26–31)
Week 5 is the most directly practical week for bioinformatics. Every real genomics pipeline reads and writes files
— FASTA, FASTQ, BED, VCF, SAM. All of these are text files, and parsing them uses exactly the skills from this
week: opening files, reading line by line, stripping whitespace, splitting on delimiters, and handling errors
gracefully.

MCQ Questions
Q38. What is the preferred way to open a file in Python to ensure it is closed properly?
• A) f = open('[Link]'); ... ; [Link]()
• B) with open('[Link]') as f: ...
• C) import file; [Link]('[Link]')
• D) read('[Link]')
Q39. What does [Link]() return?
• A) A single string with the entire file
• B) A list of strings, one per line (including newline characters)
• C) The first line of the file
• D) A generator that yields lines
Q40. What happens if you try to read from a file handle after reaching the end of file?
• A) An exception is raised
• B) It returns an empty string or empty list
• C) It restarts from the beginning
• D) It blocks until new data arrives
💡 Hint: From Lecture 29: after readlines() reads everything, calling read() returns an empty string.
Q41. Which exception would you catch if a file doesn't exist?
• A) ValueError
• B) IOError
• C) FileNotFoundError
• D) TypeError
Q42. What does the string method .strip() do?
• A) Removes all spaces from a string
• B) Removes leading and trailing whitespace (including \n)
• C) Splits a string on whitespace
• D) Converts string to lowercase

Theory / Written Questions


Q43. Describe the structure of the FASTA file format. Write pseudocode to parse a multi-sequence FASTA file
into a Python dictionary where keys are sequence IDs and values are the sequences.
Q44. What is exception handling, and why is it important in bioinformatics pipelines? Give two realistic
examples of exceptions that could occur when processing genomic data files.

Coding Questions
Q45. Write a complete FASTA parser. Handle the case where the file doesn't exist.
def parse_fasta(filename): sequences = {} try: with open(filename) as f:
current_id = None for line in f: line = [Link]()
# Your logic here: # If line starts with '>', it's a header
# Otherwise it's sequence data except FileNotFoundError: print(f'File
{filename} not found') return sequences
Q46. Write a function that reads a simple gene expression file (tab-separated: gene_name\texpression_value)
and returns a dictionary. Then filter it to return only genes with expression above a threshold.
def read_expression(filename): # Returns dict: {gene_name: float(expression_value)}
pass def filter_expressed(expression_dict, threshold): # Returns dict of genes above
threshold pass
Week 6 — Backtracking, Scope, Permutations, Stacks, Heaps
(Lectures 32–36)
Week 6 introduces more advanced algorithmic ideas. Backtracking is the pattern behind sequence alignment
traceback — you make choices, explore, and undo when you hit a dead end. Stacks and queues are foundational
data structures that appear in genome assembly (de Bruijn graphs use BFS/queues) and priority queues are used
in read alignment algorithms.

MCQ Questions
Q47. In the N-Queens backtracking problem, what triggers backtracking?
• A) When the board is filled
• B) When no valid position exists for the current queen
• C) When two queens are on the same row
• D) When the algorithm finds a solution
💡 Hint: Backtracking means 'undo the last choice and try the next option'.
Q48. What is the difference between global and local scope in Python?
• A) Global variables are faster
• B) Local variables are defined inside a function and not accessible outside; global variables persist
• C) Global variables can only hold numbers
• D) There is no difference
Q49. A stack follows which principle?
• A) FIFO — first in, first out
• B) LIFO — last in, first out
• C) Priority-based ordering
• D) Random access
Q50. What is a heap used for in Python (via the heapq module)?
• A) Storing sorted lists permanently
• B) Implementing a priority queue — efficiently getting the minimum element
• C) Dictionary lookups
• D) String formatting
Q51. What is the time complexity of inserting into and extracting from a heap?
• A) O(1) for both
• B) O(n) for both
• C) O(log n) for both
• D) O(n log n) for both

Theory / Written Questions


Q52. Explain how backtracking works using the N-Queens problem as an example. How does this pattern
relate to the traceback step in sequence alignment?
Q53. Compare stacks, queues, and priority queues. For each, give a real bioinformatics use case where that
data structure is appropriate.

Coding Questions
Q54. Implement a stack class using a Python list with push, pop, peek, and is_empty methods.
class Stack: def __init__(self): [Link] = [] def push(self,
item): pass # Add to top def pop(self): pass # Remove and
return top; raise error if empty def peek(self): pass # Return top
without removing def is_empty(self): pass
Q55. Write a function that uses a stack to check if a string of brackets is balanced. This models checking if a
genome annotation file has valid nested structures.
def is_balanced(s): # Valid pairs: () [] {} # Use a stack: push opening brackets
# When you see a closing bracket, check the top pass # is_balanced('({[]})') → True
# is_balanced('({[})') → False
Week 7 — OOP, Classes, User-Defined Lists, Search Trees
(Lectures 37–40)
Object-oriented programming is how Biopython is built. When you call [Link] or [Link], you're
using classes. Understanding how to define __init__, __str__, and operator overloading (like __add__) will help
you read and extend bioinformatics libraries. Search trees bring O(log n) lookup to data that must remain sorted
— important for genomic interval queries.

MCQ Questions
Q56. What does __init__ do in a Python class?
• A) It deletes an object
• B) It is the constructor — called automatically when an instance is created
• C) It converts the object to a string
• D) It is called when the object is printed
Q57. What is the purpose of 'self' in a class method?
• A) It refers to the class itself
• B) It refers to the current instance of the class
• C) It is a keyword meaning 'global'
• D) It passes arguments to the parent class
Q58. What does __add__ allow you to do?
• A) Add a method to a class after definition
• B) Overload the + operator for custom objects
• C) Add two classes together
• D) Import additional modules
Q59. In a Binary Search Tree, where is a new value inserted relative to the current node?
• A) Always at the root
• B) Left if smaller than current node, right if larger
• C) At a random position
• D) At the end of a list
Q60. What is the average time complexity of search, insert, and delete in a balanced BST?
• A) O(n)
• B) O(1)
• C) O(log n)
• D) O(n²)

Theory / Written Questions


Q61. What is an abstract data type (ADT)? How does a class in Python implement an ADT? Use a Stack or
Queue as your example.
Q62. Explain the concept of operator overloading. Why might a bioinformatics library like Biopython overload
operators for Sequence objects?

Coding Questions
Q63. Define a DNASequence class with attributes for ID and sequence. Add methods for gc_content(),
reverse_complement(), and __len__. Also overload __str__ to print in FASTA format.
class DNASequence: def __init__(self, seq_id, sequence): self.seq_id = seq_id
[Link] = [Link]() def gc_content(self): pass def
reverse_complement(self): pass def __len__(self): pass # Return
length of sequence def __str__(self): pass # FASTA format:
>ID\nSEQUENCE
Q64. Implement a simple Binary Search Tree with insert and search methods.
class BSTNode: def __init__(self, value): [Link] = value
[Link] = None [Link] = None class BST: def __init__(self):
[Link] = None def insert(self, value): pass def search(self,
value): pass # Return True if found, False otherwise
Week 8 — Dynamic Programming, LCS, Matrix Multiplication
(Lectures 41–45)
Week 8 is the climax of the course and the direct foundation of sequence alignment in bioinformatics. Dynamic
programming works by storing solutions to subproblems so you never compute the same thing twice — this is
called memoization. The Longest Common Subsequence (LCS) algorithm is structurally identical to Needleman-
Wunsch global alignment. Matrix multiplication connects directly to your recent assignment. Master this week and
you've mastered the core of computational genomics.

MCQ Questions
Q65. What is the key principle of dynamic programming?
• A) Divide the problem into completely independent halves
• B) Store solutions to overlapping subproblems to avoid redundant computation
• C) Always use recursion
• D) Reduce the problem to a sorting task
💡 Hint: Think about the Fibonacci example — without memoization, fib(5) computes fib(3) multiple times.
Q66. What is the time complexity of computing Fibonacci with memoization vs. naive recursion?
• A) Both O(2^n)
• B) Memoized: O(n); Naive: O(2^n)
• C) Both O(n)
• D) Memoized: O(log n); Naive: O(n²)
Q67. In the Longest Common Subsequence (LCS) problem, what are the two cases at each cell dp[i][j]?
• A) If seq1[i] > seq2[j], go left; otherwise go up
• B) If seq1[i] == seq2[j], take dp[i-1][j-1]+1; otherwise take max(dp[i-1][j], dp[i][j-1])
• C) Always take the maximum of all three neighbours
• D) If seq1[i] != seq2[j], backtrack
Q68. In the Needleman-Wunsch algorithm, which direction does the traceback arrow point when characters
match?
• A) Left
• B) Up
• C) Diagonal (up-left)
• D) Down
Q69. What is the time and space complexity of the LCS/Needleman-Wunsch DP on sequences of length m and
n?
• A) O(m+n) time, O(1) space
• B) O(m*n) time, O(m*n) space
• C) O(m*n) time, O(1) space
• D) O(log(m*n)) time, O(m*n) space

Theory / Written Questions


Q70. Explain the difference between memoization (top-down) and tabulation (bottom-up) dynamic
programming. Which approach did the course use for grid paths and LCS? Why might one be preferred
over the other?
Q71. The LCS problem and the Needleman-Wunsch alignment algorithm are structurally very similar. Explain
the relationship between them. What does the scoring matrix in Needleman-Wunsch correspond to in LCS?
💡 Hint: LCS maximises common characters (no gap penalty). NW adds gap penalties and mismatch scores. The DP table
structure is the same.
Q72. Why does dynamic programming require that subproblems have 'optimal substructure'? Give an example
from LCS to illustrate what this means.

Coding Questions — EXAM CRITICAL


The following questions directly mirror what will appear in a computational genomics exam. Practice writing these
from scratch without looking at notes.

Q73. Implement the Longest Common Subsequence algorithm using dynamic programming. Return both the
length and the actual LCS string.
import numpy as np def lcs(s1, s2): m, n = len(s1), len(s2) # Step 1: Build dp
table of size (m+1) x (n+1) dp = [Link]((m+1, n+1), dtype=int) # Step 2:
Fill the table for i in range(1, m+1): for j in range(1, n+1): if
s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1]) # Step 3: Traceback to find the actual
LCS string # Start at dp[m][n] and work backwards result = [] i, j = m, n
# Your traceback code here return dp[m][n], ''.join(reversed(result)) # Test:
lcs('ATCGTA', 'ACGTA') → (5, 'ACGTA')
Q74. Implement the Needleman-Wunsch global alignment algorithm. This is your matrix assignment extended
with biological meaning.
import numpy as np def needleman_wunsch(seq1, seq2, match=1, mismatch=-1, gap=-2):
m, n = len(seq1), len(seq2) # Step 1: Initialise scoring matrix dp =
[Link]((m+1, n+1)) for i in range(m+1): dp[i][0] = i * gap # gap penalties along
left edge for j in range(n+1): dp[0][j] = j * gap # gap penalties along top edge
# Step 2: Fill matrix — at each cell, take the best of 3 moves for i in range(1,
m+1): for j in range(1, n+1): score = match if seq1[i-1] == seq2[j-1]
else mismatch dp[i][j] = max( dp[i-1][j-1] + score, #
diagonal: match or mismatch dp[i-1][j] + gap, # up: gap in seq2
dp[i][j-1] + gap # left: gap in seq1 ) # Step 3: Traceback
(follow the choices you made) align1, align2 = [], [] i, j = m, n while i > 0
or j > 0: score = match if seq1[i-1] == seq2[j-1] else mismatch if i > 0
and j > 0 and dp[i][j] == dp[i-1][j-1] + score: [Link](seq1[i-1])
[Link](seq2[j-1]) i -= 1; j -= 1 elif i > 0 and dp[i][j] ==
dp[i-1][j] + gap: [Link](seq1[i-1]) [Link]('-')
i -= 1 else: [Link]('-') [Link](seq2[j-1])
j -= 1 return ''.join(reversed(align1)), ''.join(reversed(align2)), dp[m][n] #
Test: needleman_wunsch('ATCG', 'ACG')
💡 Hint: Study this function until you can write it from memory. The dp matrix IS your assignment matrix. The three
directions correspond to three biological events: match/mismatch, gap in seq2, gap in seq1.
Q75. Implement memoized Fibonacci using a dictionary cache. Then compare its performance against naive
recursion for n=35.
# Version 1: Naive (exponential time) def fib_naive(n): if n <= 1: return n
return fib_naive(n-1) + fib_naive(n-2) # Version 2: Memoized (linear time) def
fib_memo(n, cache={}): if n in cache: return cache[n] if n <= 1: return n
cache[n] = fib_memo(n-1, cache) + fib_memo(n-2, cache) return cache[n] # Version 3:
Tabulated (bottom-up, also linear) def fib_dp(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]
Quick Reference: Complexity Cheat Sheet
Knowing these by heart will help you both in MCQs and in explaining algorithm choices in written answers.

Algorithm Best Average Worst


Linear Search O(1) O(n) O(n)
Binary Search O(1) O(log n) O(log n)
Selection Sort O(n²) O(n²) O(n²)
Insertion Sort O(n) O(n²) O(n²)
Mergesort O(n log n) O(n log n) O(n log n)
Quicksort O(n log n) O(n log n) O(n²)
BST Search O(1) O(log n) O(n)
LCS / NW DP — O(m×n) O(m×n)

The Bioinformatics Thread


Every algorithm in this course has a direct counterpart in computational genomics. Keep these connections in
mind — examiners love questions that ask you to link Python concepts to biological applications.

• Strings & slicing (Week 2) → DNA/RNA sequences, reading frames, restriction sites
• Binary search (Week 3) → Finding positions in sorted genomic coordinates
• Mergesort merge step (Week 4) → Merging sorted read alignments (samtools merge)
• Dictionaries (Week 4) → Codon tables, gene annotation, variant databases
• File I/O (Week 5) → Parsing FASTA, FASTQ, VCF, BED, SAM formats
• Backtracking (Week 6) → Alignment traceback, haplotype phasing
• Stacks/queues (Week 6) → BFS in genome graphs, assembly de Bruijn graphs
• Classes (Week 7) → Biopython SeqRecord, Alignment objects
• LCS / DP (Week 8) → Needleman-Wunsch global alignment, Smith-Waterman local alignment
• Matrix multiplication (Week 8) → Scoring matrices (BLOSUM62, PAM250), PCA on expression data

You might also like